Files
microdao-daarion/docs/tasks/TASK_PHASE9_LIVING_MAP_FULL.md
Apple 3de3c8cb36 feat: Add presence heartbeat for Matrix online status
- matrix-gateway: POST /internal/matrix/presence/online endpoint
- usePresenceHeartbeat hook with activity tracking
- Auto away after 5 min inactivity
- Offline on page close/visibility change
- Integrated in MatrixChatRoom component
2025-11-27 00:19:40 -08:00

12 KiB
Raw Blame History

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-router
    • llm-proxy, memory-orchestrator, toolcore
    • auth-service, pdp-service, usage-engine
    • agents-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

  1. Створити сервіс living-map-service (FastAPI), порт 7017.
  2. Зібрати стан мережі з існуючих сервісів в один snapshot.
  3. Підписатися на ключові NATS-сабджекти й зберігати історію в living_map_history.
  4. Віддавати:
    • snapshot (HTTP)
    • history (HTTP)
    • real-time stream (WS).
  5. Додати мінімальну фронтенд-обгортку 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.city
      • scene.layers.space
      • scene.layers.nodes
      • scene.layers.agents
      • scene.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/snapshot
  • space-service:
    • GET http://space-service:7002/api/space/scene або окремо planets/nodes/events
  • agents-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/summary
  • usage-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|channel
  • limit (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.py

  • services/living-map-service/models.py

  • services/living-map-service/repository_history.py

  • services/living-map-service/adapters/city_client.py

  • services/living-map-service/adapters/space_client.py

  • services/living-map-service/adapters/agents_client.py

  • services/living-map-service/adapters/microdao_client.py

  • services/living-map-service/adapters/dao_client.py

  • services/living-map-service/adapters/usage_client.py

  • services/living-map-service/nats_subscriber.py

  • services/living-map-service/ws_stream.py

  • services/living-map-service/Dockerfile

  • services/living-map-service/requirements.txt

  • docker-compose.phase9.yml (або оновити загальний)

  • scripts/start-phase9.sh

  • scripts/stop-phase9.sh

  • migrations/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
    • events
    • isLoading
    • error
    • connectionStatus

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

  1. docker-compose -f docker-compose.phase9.yml up -d піднімає living-map-service без помилок.

  2. GET /living-map/health повертає status=ok.

  3. GET /living-map/snapshot повертає валідний JSON з layers.city, layers.space, layers.nodes, layers.agents.

  4. GET /living-map/history повертає список подій, які приходять з NATS.

  5. WS /living-map/stream надсилає:

    • при підключенні: kind="snapshot"
    • далі: kind="event" при нових подіях.
  6. useLivingMapFull успішно підключається до API+WS і оновлює локальний state без TypeScript помилок.

  7. Уся нова логіка проходить лінтер та тести.


END OF TASK