TASK PHASE 9 — LIVING MAP (FULL STACK SERVICE)¶
Version: 1.0
Status: READY FOR IMPLEMENTATION
Scope: Backend + WebSocket + NATS + Minimal Frontend Hook
1. Context¶
DAARION уже має:
- core сервіси:
messaging-service(Matrix-aware Messenger)agent-runtime,agent-filter,dagi-routerllm-proxy,memory-orchestrator,toolcoreauth-service,pdp-service,usage-engineagents-service(Agent Hub + lifecycle)microdao-service(microDAO Console)dao-service(DAO Dashboard)city-service,space-service- інфраструктуру:
- PostgreSQL
- NATS JetStream
- docker-compose для різних фаз
- WebSocket-потоки для окремих модулів
Потрібен єдиний "Living Map" шар, який агрегує стан всієї мережі:
- City (microDAO, метрики)
- Space (DAO-планети, ноди)
- Nodes (ресурси, алерти)
- Agents (статус, використання)
- DAO (голосування, proposals)
- Messaging (активність каналів)
і видає це:
- через
GET /living-map/snapshot(full-state) - через
GET /living-map/history(event log) - через
GET /living-map/entities(каталог сутностей) - через
WS /living-map/stream(живий потік подій).
Цей таск — backend + API + NATS + WS + базовий frontend hook.
2. Goals¶
- Створити сервіс
living-map-service(FastAPI), порт7017. - Зібрати стан мережі з існуючих сервісів в один snapshot.
- Підписатися на ключові NATS-сабджекти й зберігати історію в
living_map_history. - Віддавати:
snapshot(HTTP)history(HTTP)real-time stream(WS).- Додати мінімальну фронтенд-обгортку
useLivingMapFull(React hook) для інтеграції з 2D/3D UI.
3. Architecture Overview¶
3.1. New service: living-map-service¶
- Stack: Python 3 + FastAPI + uvicorn
- Port:
7017 - Responsibilities:
- Агрегувати дані з:
city-service(city snapshot)space-service(planets/nodes/events)agents-service(agents, metrics, events)microdao-service(microDAOs)dao-service(dao, proposals, votes)usage-engine(LLM/tool usage summary)
- Нормалізувати в єдину структуру сцени:
scene.layers.cityscene.layers.spacescene.layers.nodesscene.layers.agentsscene.meta(timestamps, version)
- Підписуватись на NATS-subject'и й створювати event log.
- Видавати snapshot/history + WebSocket stream.
3.2. Data sources (HTTP)¶
Очікувані існуючі/доступні ендпоінти (можна створити прості адаптери, якщо їх ще нема):
city-service:GET http://city-service:7001/api/city/snapshotspace-service:GET http://space-service:7002/api/space/sceneабо окремо planets/nodes/eventsagents-service:GET http://agents-service:7014/agents(list)GET http://agents-service:7014/agents/metrics(summary)microdao-service:GET http://microdao-service:7015/microdaos(list)dao-service:GET http://dao-service:7016/dao(list)GET http://dao-service:7016/dao/proposals/summaryusage-engine:GET http://usage-engine:7013/internal/usage/summary?period_hours=24
Якщо чогось немає — зробити простий adapter/placeholder з mock даними всередині living-map-service.
3.3. NATS Subjects¶
Потрібно підписатися на:
city.event.*dao.event.*microdao.event.*node.metrics.*agent.event.*usage.llm.*usage.agent.*messaging.message.created
(Якщо частина сабджектів ще не існує — підготувати consumer з graceful handling та вимкненими/placeholder subscriptions.)
4. API Specification¶
4.1. GET /living-map/health¶
Простий health-check.
{
"status": "ok",
"service": "living-map-service",
"version": "1.0.0",
"time": "2025-11-24T12:34:56Z"
}
4.2. GET /living-map/snapshot¶
Агрегований стан усієї мережі.
Response (спрощений приклад):
{
"generated_at": "2025-11-24T12:34:56Z",
"layers": {
"city": {
"microdaos_total": 12,
"active_users": 57,
"active_agents": 34,
"health": "green",
"items": [
{
"id": "microdao:7",
"slug": "daarion-city",
"name": "DAARION City",
"status": "active",
"agents": 9,
"nodes": 3
}
]
},
"space": {
"planets": [
{
"id": "dao:daarion-core",
"name": "DAARION CORE",
"type": "dao",
"orbits": ["node:gpu-1", "node:gpu-2"],
"status": "active"
}
],
"nodes": [
{
"id": "node:gpu-1",
"name": "NODE1",
"cpu": 0.42,
"gpu": 0.77,
"memory": 0.63,
"alerts": []
}
]
},
"nodes": {
"items": [
{
"id": "node:gpu-1",
"microdao_id": "microdao:7",
"status": "online",
"metrics": {
"cpu": 0.42,
"gpu": 0.77,
"ram": 0.63,
"net_in": 12345,
"net_out": 9876
}
}
]
},
"agents": {
"items": [
{
"id": "agent:sofia",
"name": "Sofia",
"kind": "system",
"microdao_id": "microdao:7",
"status": "online",
"usage": {
"llm_calls_24h": 123,
"tokens_24h": 45678
}
}
]
}
},
"meta": {
"source_services": [
"city-service",
"space-service",
"agents-service",
"microdao-service",
"dao-service",
"usage-engine"
]
}
}
4.3. GET /living-map/entities¶
Плоский список сутностей з мінімальними даними для побудови legend/списків.
Query params:
type(optional):city|space|node|agent|dao|microdao|channellimit(optional, default 100)
Response:
{
"items": [
{
"id": "microdao:7",
"type": "microdao",
"label": "DAARION City",
"status": "active",
"layer": "city"
},
{
"id": "dao:daarion-core",
"type": "dao",
"label": "DAARION CORE DAO",
"status": "active",
"layer": "space"
}
]
}
4.4. GET /living-map/entities/{id}¶
Детальний опис сутності (проксі до відповідного сервісу з нормалізацією).
Response (узагальнений):
{
"id": "agent:sofia",
"type": "agent",
"layer": "agents",
"data": {
"...": "raw or normalized fields"
}
}
4.5. GET /living-map/history¶
Історія подій Living Map.
Query params:
since(optional, ISO datetime)limit(optional, default 200)
Response:
{
"items": [
{
"id": "evt-uuid",
"timestamp": "2025-11-24T12:30:00Z",
"event_type": "node.metrics.update",
"payload": {
"node_id": "node:gpu-1",
"cpu": 0.8,
"gpu": 0.95
}
}
]
}
4.6. WS /living-map/stream¶
WebSocket-потік:
-
Типи повідомлень:
-
snapshot— повний стан (на підключення та за потреби) event— одинична подія- Формат:
{
"kind": "event",
"event_type": "agent.event.status",
"timestamp": "2025-11-24T12:34:56Z",
"payload": { ... }
}
5. Database Schema¶
Створити міграцію, наприклад: migrations/010_create_living_map_tables.sql.
CREATE TABLE IF NOT EXISTS living_map_history (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
timestamp timestamptz NOT NULL DEFAULT now(),
event_type TEXT NOT NULL,
payload JSONB NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_living_map_history_timestamp
ON living_map_history (timestamp DESC);
CREATE INDEX IF NOT EXISTS idx_living_map_history_event_type
ON living_map_history (event_type);
6. Implementation Plan¶
6.1. Files to create¶
services/living-map-service/main.pyservices/living-map-service/models.pyservices/living-map-service/repository_history.pyservices/living-map-service/adapters/city_client.pyservices/living-map-service/adapters/space_client.pyservices/living-map-service/adapters/agents_client.pyservices/living-map-service/adapters/microdao_client.pyservices/living-map-service/adapters/dao_client.pyservices/living-map-service/adapters/usage_client.pyservices/living-map-service/nats_subscriber.pyservices/living-map-service/ws_stream.pyservices/living-map-service/Dockerfileservices/living-map-service/requirements.txtdocker-compose.phase9.yml(або оновити загальний)scripts/start-phase9.shscripts/stop-phase9.shmigrations/010_create_living_map_tables.sql-
Frontend:
-
src/features/livingMap/hooks/useLivingMapFull.ts
6.2. Minimal frontend hook¶
useLivingMapFull.ts:
GET /living-map/snapshot→ зберігає state- Підключає WS
/living-map/stream - При
kind=eventоновлює локальний state (immutable update) -
Повертає:
-
snapshot eventsisLoadingerrorconnectionStatus
7. Security / Auth¶
-
Всі HTTP-ендпоінти:
-
Перевірка JWT/Session через
auth-service(ActorContext). -
Опціонально,
GET /living-map/snapshotможе мати: -
public_mode(спрощений, анонімний) - або вимагати auth (рекомендовано).
-
WS:
-
Authorization: Bearer <token>у заголовках. -
NATS:
-
лише internal subjects, використовувати існуючий NATS connection з параметрами як в інших сервісах.
8. TODO Checklist¶
Backend:
- [ ] Створити міграцію
010_create_living_map_tables.sql - [ ] Створити
living-map-serviceструктуру - [ ] Реалізувати адаптери до інших сервісів (з timeout/retry)
- [ ] Реалізувати
GET /living-map/health - [ ] Реалізувати
GET /living-map/snapshot - [ ] Реалізувати
GET /living-map/entities - [ ] Реалізувати
GET /living-map/entities/{id} - [ ] Реалізувати
GET /living-map/history - [ ] Реалізувати
WS /living-map/stream - [ ] Реалізувати
nats_subscriber.pyдля key subjects - [ ] Інтегрувати Auth/PDP (як у інших сервісах)
- [ ] Додати Dockerfile + requirements.txt
- [ ] Оновити docker-compose/script'и
- [ ] Додати базові unit tests (snapshot builder)
Frontend:
- [ ] Створити
useLivingMapFull.ts - [ ] Протестувати запит snapshot + WS stream (можна через тимчасовий debug-компонент)
9. Acceptance Criteria¶
docker-compose -f docker-compose.phase9.yml up -dпіднімаєliving-map-serviceбез помилок.GET /living-map/healthповертаєstatus=ok.GET /living-map/snapshotповертає валідний JSON зlayers.city,layers.space,layers.nodes,layers.agents.GET /living-map/historyповертає список подій, які приходять з NATS.-
WS /living-map/streamнадсилає: -
при підключенні:
kind="snapshot" - далі:
kind="event"при нових подіях. useLivingMapFullуспішно підключається до API+WS і оновлює локальний state без TypeScript помилок.- Уся нова логіка проходить лінтер та тести.
END OF TASK