# TASK PHASE — NODE DASHBOARD API (MVP) Version: 1.0 Target: NODE1 (city-service + daarion-web) --- ## 1. Мета Замість 404-заглушки для `/api/node/dashboard` зробити мінімальний Node Dashboard API, який: - повертає базову інформацію про ноду (status, tags, agents_online, uptime); - не ламає сторінку ноди, навіть якщо метрик поки немає; - має чітку структуру для подальшого розширення (Prometheus, NATS events, тощо). --- ## 2. Поточний стан - `/nodes` і `/nodes/:nodeId` вже працюють через `/public/nodes`. - На сторінці `nodes/[nodeId]` фронт робить запит на `/api/node/dashboard`, отримує 404 та показує банер (graceful degradation). - бекенд не має відповідного endpoint’а. --- ## 3. Завдання для backend (city-service) ### 3.1. Створити Node Dashboard endpoint 1. Додати новий роутер, наприклад `routes_node_dashboard.py`, або розширити існуючий `routes_city`. 2. Маршрут: ``` GET /api/v1/nodes/{node_id}/dashboard ``` 3. Реалізація: ```python @router.get("/api/v1/nodes/{node_id}/dashboard") async def get_node_dashboard(node_id: str): node = await repo_city.get_node_by_id(node_id) if not node: raise HTTPException(status_code=404, detail="Node not found") return { "node_id": node["node_id"], "name": node["name"], "kind": node.get("kind"), "status": node.get("status", "unknown"), "tags": node.get("roles", []), "agents_total": node.get("agents_total", 0), "agents_online": node.get("agents_online", 0), "uptime": None, # placeholder "metrics_available": False # флаг, що метрик ще немає } ``` 4. Під’єднати роутер у `main.py`. ### 3.2. Legacy-роут (опційно) Якщо фронт все ще звертається до `/api/node/dashboard?nodeId=...`, додати невеликий alias: ```python @router.get("/api/node/dashboard") async def get_node_dashboard_legacy(node_id: str): return await get_node_dashboard(node_id) ``` ### 3.3. Repo / модель Перевірити, що `repo_city.get_node_by_id` повертає словник з потрібними полями (node_id, name, roles, status, agents_total, agents_online). --- ## 4. Завдання для frontend (apps/web) 1. В `apps/web/src/lib/api/nodes.ts` (або аналогічному файлі): ```ts export async function getNodeDashboard(nodeId: string) { return api.get(`/api/nodes/${encodeURIComponent(nodeId)}/dashboard`); } ``` 2. В `nodes/[nodeId]/page.tsx`: - використовувати новий API; - якщо `metrics_available === false`, показувати банер “детальний дашборд у розробці”, але рендерити базову інформацію; - якщо відповідь 404 → fallback до вже наявної логіки (профіль з `/public/nodes`). --- ## 5. Перевірки 1. `GET https://daarion.space/api/nodes/node-1-hetzner-gex44/dashboard` ```json { "node_id": "node-1-hetzner-gex44", "name": "...", "status": "online", "tags": ["core","gateway",...], "agents_total": 9, "agents_online": 1, "uptime": null, "metrics_available": false } ``` 2. UI `https://daarion.space/nodes/node-1-hetzner-gex44`: - сторінка відкривається без помилок; - зверху банер (поки API повертає `metrics_available=false`); - базова інформація про ноду видно. 3. У логах Next.js немає помилок “Failed to fetch node dashboard”. --- ## 6. Подальші кроки (out of scope) - Коли з’являться реальні метрики (Prometheus, Agent runtime), заповнити поля `uptime`, `metrics_available=True`, додати масив графіків/alerts. - Додати історію подій ноди (restart, incident, deployment) через `event_outbox`.