# Sofiia Console — Operations Runbook

## 1. Rebuild & Deploy (NODA2)

```bash
cd /opt/microdao-daarion  # or ~/github-projects/microdao-daarion on dev

# Rebuild sofiia-console (UI + backend)
docker compose -f docker-compose.node2-sofiia.yml build sofiia-console --no-cache
docker compose -f docker-compose.node2-sofiia.yml up -d sofiia-console

# Rebuild gateway (for agent registry changes)
docker compose -f docker-compose.node2-sofiia.yml build gateway --no-cache
docker compose -f docker-compose.node2-sofiia.yml up -d gateway
```

## 2. Confirm Build Version

```bash
# Via API
APIKEY=$(grep SOFIIA_CONSOLE_API_KEY .env | cut -d= -f2)
curl -s http://localhost:8002/api/meta/version -H "X-API-Key: $APIKEY"
# Expected: {"version":"0.4.0","build_sha":"dev","build_time":"local",...}

# In UI: header shows "v0.4.0 dev" badge (top right)
```

## 3. Verify Agents List

```bash
APIKEY=$(grep SOFIIA_CONSOLE_API_KEY .env | cut -d= -f2)

# NODA2 agents
curl -s "http://localhost:8002/api/agents?nodes=NODA2" -H "X-API-Key: $APIKEY" | \
  python3 -c "import sys,json; d=json.load(sys.stdin); print(f'items={len(d[\"items\"])} stats={d[\"stats\"]} errors={d[\"node_errors\"]}')"

# NODA1 agents  
curl -s "http://localhost:8002/api/agents?nodes=NODA1" -H "X-API-Key: $APIKEY" | \
  python3 -c "import sys,json; d=json.load(sys.stdin); print(f'items={len(d[\"items\"])} stats={d[\"stats\"]} errors={d[\"node_errors\"]}')"

# All nodes
curl -s "http://localhost:8002/api/agents?nodes=NODA1,NODA2" -H "X-API-Key: $APIKEY" | \
  python3 -c "import sys,json; d=json.load(sys.stdin); print(f'items={len(d[\"items\"])} stats={d[\"stats\"]} errors={d[\"node_errors\"]}')"

# Direct gateway check (NODA2)
curl -s http://localhost:9300/health | python3 -c "
import sys,json; d=json.load(sys.stdin)
print(f'agents={d[\"agents_count\"]}')
for k,v in sorted(d[\"agents\"].items()): print(f'  {k}: badges={v.get(\"badges\",[])}')
"
```

## 4. UI Debug Panel

У вкладці **📁 Проєкти → Agents**:
1. Натисніть кнопку **🔍 Debug** в панелі дій
2. Debug panel показує:
   - `fetch`: час останнього запиту
   - `nodes`: вибрані ноди
   - `items`: кількість агентів
   - `ok/total`: кількість успішних нод
   - `errors`: помилки нод (якщо є)

## 5. Troubleshooting

### Агенти не відображаються в UI

1. Перевірте API ключ у налаштуваннях UI
2. Натисніть **↻ Sync**
3. Відкрийте **🔍 Debug** — перевірте `errors`
4. Перевірте gateway health: `curl http://localhost:9300/health`

### Gateway падає при старті

```bash
docker logs dagi-gateway-node2 --tail 50
```

Типова причина: ImportError у `http_api_doc.py` → `doc_service.py`
Рішення: перевірте що в `doc_service.py` є stub-функції (doc_service, update_document, list_document_versions, publish_document_artifact).

### SQLite "no such column: last_applied_hash"

БД у volume має стару схему. Вирішення — міграції виконуються автоматично при старті через `_MIGRATION_SQL_STMTS` у `db.py`. Restart контейнера вирішує:
```bash
docker restart sofiia-console
```

### NODA2 gateway_url недоступний з контейнера

У `config/nodes_registry.yml` NODA2 використовує `host.docker.internal:9300`.
Якщо UI запущений не в Docker — замініть на `localhost:9300`.

### Monitor / AISTALK не відображаються

Перевірте що в `gateway-bot/http_api.py`:
- `MONITOR_CONFIG` і `AISTALK_CONFIG` визначені через `load_agent_config`
- Вони додані в `AGENT_REGISTRY`
- Файл `gateway-bot/monitor_prompt.txt` існує

```bash
docker exec dagi-gateway-node2 python3 -c "
from http_api import AGENT_REGISTRY
print(list(AGENT_REGISTRY.keys()))
"
```

## 6. Monitor Policy

Monitor (`agent_id=monitor`) є **обов'язковим** агентом на кожній ноді.

### Перевірка
```bash
APIKEY=$(grep SOFIIA_CONSOLE_API_KEY .env | cut -d= -f2)
curl -s "http://localhost:8002/api/agents?nodes=NODA1,NODA2" -H "X-API-Key: $APIKEY" | \
  python3 -c "import sys,json; d=json.load(sys.stdin); print('missing:', d.get('required_missing_nodes'))"
```

- `required_missing=[]` — все ОК
- `required_missing=[{"node_id":"NODA1","agent_id":"monitor"}]` — Monitor відсутній на NODA1 → перевірте gateway registry → rebuild gateway

### Governance event
Якщо Monitor відсутній на онлайн-ноді — автоматично записується `governance_event` типу `node_required_agent_missing` (severity=high).

## 7. Voice & Telegram Capabilities

У вкладці Agents:
- **🎙 Voice** badge — агент підтримує голос (AISTALK)
- **💬 Telegram** badge — агент активний у Telegram
- Фільтри **🎙 Voice** і **💬 Telegram** — client-side фільтрація

### API
```bash
curl -s "http://localhost:8002/api/agents?nodes=NODA1" -H "X-API-Key: $APIKEY" | \
  python3 -c "import sys,json; d=json.load(sys.stdin); 
  voice=[a['agent_id'] for a in d['items'] if a.get('capabilities',{}).get('voice')]
  print('voice:', voice)"
```

## 8. Document Versioning

API для версій документів (в межах Sofiia Console):
```bash
# Список версій
GET /api/projects/{project_id}/documents/{doc_id}/versions

# Оновити документ (зберігає нову версію)
POST /api/projects/{project_id}/documents/{doc_id}/update
{"content_md": "# Новий зміст", "author_id": "user", "reason": "оновлення", "dry_run": false}

# Відновити версію
POST /api/projects/{project_id}/documents/{doc_id}/restore
{"version_id": "...", "author_id": "user"}
```

## 9. Agent Registry SSoT

Canonical реєстр: `config/agent_registry.yml`

Gateway завантажує агентів з `gateway-bot/http_api.py::AGENT_REGISTRY` (Python dict).
Щоб додати нового агента:
1. Додайте запис в `config/agent_registry.yml`
2. Додайте `*_CONFIG = load_agent_config(...)` і запис в `AGENT_REGISTRY` у `gateway-bot/http_api.py`
3. Створіть `gateway-bot/<agent_id>_prompt.txt`
4. Rebuild gateway

## 10. Ports Reference

| Сервіс | Port | URL |
|---|---|---|
| Sofiia Console UI | 8002 | http://localhost:8002 |
| Gateway | 9300 | http://localhost:9300/health |
| Router | 9102 | http://localhost:9102/health |
| Memory | 8000 | http://localhost:8000/health |
| Qdrant | 6333 | http://localhost:6333/healthz |
