Skip to content

# TASK_PHASE_ROOMS_LAYER_RESTORE_AND_MATRIX_INTEGRATION

Version: 1.0 Status: Ready Priority: Critical (MVP breaking issue)

# 1. МЕТА

Повністю відновити та інтегрувати Rooms Layer у MVP згідно з:

- `Rooms_Layer_Architecture_v1.md`
- `District_Interface_Architecture_v1.md`
- `MicroDAO_Interface_Architecture_v1.md`
- Matrix federation & gateway design
- Agent Governance Protocol

Цей таск виправляє критичні проблеми: - City Rooms не вантажаться у "список" - MicroDAO Rooms = 0 - Agent Chat Rooms = missing - Node Chat Rooms = missing - Citizens Layer = 0 citizens - `/city/map` показує кімнати, але API `/rooms/list` — порожній

# 2. ВИМОГИ (архітектурні інваріанти)

## 2.1. Кімната існує у трьох шарах одночасно:

1. База даних (city-service): `city_rooms` + `matrix_room_id` + `room_agents`

2. Matrix (Synapse): кімната повинна бути створена на сервері matrix

3. Gateway (matrix-gateway): API `/internal/matrix/room/create` та `/internal/matrix/agent-join`

# 3. СКОП РОБОТИ

## 3.1. Відновити City Rooms (8 кімнат)

Згідно з `Rooms_Layer_Architecture_v1.md`:

Slug | Name | Owner | Agents
--- | --- | --- | ---
`general` | General | city | DARIO, DARIA
`welcome` | Welcome | city | Greeter
`leadership-hall` | Leadership Hall | city | DAARWIZZ
`builders` | Builders | city | Builder agents
`science-lab` | Science Lab | city | Research agents
`security-bureau` | Security Bureau | city | Security agent
`economics-square` | Economics Square | city | Finance agent
`announcements` | Announcements | city | DAARWIZZ

### Завдання

1. Створити SQL seed у city-service для `city_rooms`
2. Створити matrix room для кожної кімнати через gateway
3. Записати `matrix_room_id` у таблицю `city_rooms`
4. Підключити public agent до кожної кімнати

### SQL Seed

    INSERT INTO city_rooms (id, slug, name, description, room_type, owner_type, owner_id, space_scope, visibility, is_public, sort_order, created_at, updated_at)
    VALUES
      (gen_random_uuid(), 'general', 'General', 'Main city chat room', 'chat', 'city', 'daarion', 'city', 'public-city', true, 1, NOW(), NOW()),
      (gen_random_uuid(), 'welcome', 'Welcome', 'Welcome new citizens', 'chat', 'city', 'daarion', 'city', 'public-city', true, 2, NOW(), NOW()),
      (gen_random_uuid(), 'leadership-hall', 'Leadership Hall', 'City governance discussions', 'chat', 'city', 'daarion', 'city', 'public-city', true, 3, NOW(), NOW()),
      (gen_random_uuid(), 'builders', 'Builders', 'Builders community', 'chat', 'city', 'daarion', 'city', 'public-city', true, 4, NOW(), NOW()),
      (gen_random_uuid(), 'science-lab', 'Science Lab', 'Research and AI discussions', 'chat', 'city', 'daarion', 'city', 'public-city', true, 5, NOW(), NOW()),
      (gen_random_uuid(), 'security-bureau', 'Security Bureau', 'Security discussions', 'chat', 'city', 'daarion', 'city', 'public-city', true, 6, NOW(), NOW()),
      (gen_random_uuid(), 'economics-square', 'Economics Square', 'Economics and tokenomics', 'chat', 'city', 'daarion', 'city', 'public-city', true, 7, NOW(), NOW()),
      (gen_random_uuid(), 'announcements', 'Announcements', 'Official announcements', 'broadcast', 'city', 'daarion', 'city', 'public-city', true, 8, NOW(), NOW())
    ON CONFLICT (slug) DO UPDATE SET
      name = EXCLUDED.name,
      description = EXCLUDED.description,
      updated_at = NOW();

## 3.2. Відновити MicroDAO Rooms

Кожне MicroDAO повинно мати:

Room Slug Pattern | Name | Role
--- | --- | ---
`{slug}-lobby` | Lobby | Primary public room
`{slug}-governance` | Governance | Voting & proposals
`{slug}-news` | News | Announcements
`{slug}-builders` | Builders | Development
`{slug}-help` | Help | Support

### Завдання

1. Backend: auto-generate rooms when MicroDAO created
2. Matrix: auto-create matrix rooms via gateway
3. UI: підключити список кімнат до `/microdao/:slug`

### API Endpoint

    @router.post("/microdao/{slug}/rooms/ensure")
    async def ensure_microdao_rooms(slug: str):
        """
        Ensure all standard rooms exist for a MicroDAO.
        Creates missing rooms in DB and Matrix.
        """
        dao = await repo_city.get_microdao_by_slug(slug)
        if not dao:
            raise HTTPException(404, "MicroDAO not found")

        standard_rooms = [
            {"suffix": "lobby", "name": "Lobby", "role": "primary"},
            {"suffix": "governance", "name": "Governance", "role": "governance"},
            {"suffix": "news", "name": "News", "role": "news"},
            {"suffix": "builders", "name": "Builders", "role": "builders"},
            {"suffix": "help", "name": "Help", "role": "help"},
        ]

        created = []
        for room_def in standard_rooms:
            room_slug = f"{slug}-{room_def['suffix']}"
            existing = await repo_city.get_room_by_slug(room_slug)
            if not existing:
                room = await create_room_with_matrix(
                    slug=room_slug,
                    name=f"{dao['name']} {room_def['name']}",
                    owner_type="microdao",
                    owner_id=dao["id"],
                    room_role=room_def["role"]
                )
                created.append(room_slug)

        return {"created": created, "total": len(standard_rooms)}

## 3.3. Відновити Agent Chat Rooms

### Правило

Кожен агент має власну консольну кімнату з метаданими:

- `room_type = "agent-console"`
- `owner_type = "agent"`
- `owner_id = agent_id`

### Завдання

1. Backend: при `GET /agents/{id}/chat-room`
2. якщо кімната не існує → створити автоматично
3. Matrix: створити приватну кімнату
4. Gateway: додати агента у кімнату
5. Frontend: оновити widget (грузити messages через gateway)

### Auto-Create Logic

    async def ensure_agent_chat_room(agent_id: str):
        """Ensure agent has a chat room, create if missing."""
        agent = await repo_city.get_agent_by_id(agent_id)
        if not agent:
            raise HTTPException(404, "Agent not found")

        room_slug = f"agent-console-{agent.get('public_slug') or agent_id}"
        room = await repo_city.get_room_by_slug(room_slug)

        if not room:
            # Create room in DB
            room = await repo_city.create_room({
                "slug": room_slug,
                "name": f"{agent['display_name']} Console",
                "room_type": "agent-console",
                "owner_type": "agent",
                "owner_id": agent_id,
                "space_scope": "agent",
                "visibility": "private",
                "is_public": False
            })

            # Create Matrix room via gateway
            matrix_room = await create_matrix_room(room_slug, agent['display_name'])
            if matrix_room:
                await repo_city.update_room_matrix_id(room["id"], matrix_room["room_id"])

        return room

## 3.4. Відновити Node Chat Rooms

### Правило

Кожна нода має кімнату підтримки:

- `room_slug = "node-support-{node_slug}"`
- `room_type = "node-support"`
- Учасники: GuardianOS, Steward, користувачі

### Завдання

1. Backend: generate + seed node support rooms
2. Gateway: ensure node guardian is room admin
3. Matrix: join guardian + steward agents

### SQL Seed for NODE1 and NODE2

    INSERT INTO city_rooms (id, slug, name, description, room_type, owner_type, owner_id, space_scope, visibility, is_public, created_at, updated_at)
    VALUES
      (gen_random_uuid(), 'node-support-node1', 'NODE1 Support', 'Support room for Hetzner GEX44 Production', 'node-support', 'node', 'node-1-hetzner-gex44', 'node', 'members', false, NOW(), NOW()),
      (gen_random_uuid(), 'node-support-node2', 'NODE2 Support', 'Support room for MacBook Pro M4 Max', 'node-support', 'node', 'node-2-macbook-m4max', 'node', 'members', false, NOW(), NOW())
    ON CONFLICT (slug) DO NOTHING;

## 3.5. Виправити Citizens Layer

Public Agents = "Citizens of DAARION City"

### Правило

Агент є "громадянином" якщо: - `is_public = true` - `status = 'online' OR status = 'offline'` (не archived) - Має `city_visibility = 'public'` або `gov_level IN ('city_governance', 'district_lead', 'orchestrator')`

### Завдання

1. Backend: Оновити фільтр у `/public/citizens`
2. UI: Виводити список усіх public agents у `/citizens`
3. Matrix: Публічні агенти автоматично додаються до `general` room

### Updated Query

    async def list_public_citizens(limit: int = 100):
        """List all public agents as city citizens."""
        query = """
            SELECT a.*, nc.node_name
            FROM agents a
            LEFT JOIN node_cache nc ON a.node_id = nc.node_id
            WHERE a.is_public = true
              AND a.status != 'archived'
              AND (
                a.gov_level IN ('city_governance', 'district_lead', 'orchestrator', 'core_team')
                OR a.kind IN ('civic', 'governance', 'orchestrator')
              )
            ORDER BY a.display_name
            LIMIT $1
        """
        return await db.fetch(query, limit)

## 3.6. Виправити API /rooms/list

### Проблема

`/city/rooms` API повертає порожній список або помилку.

### Завдання

1. Перевірити endpoint у `city-service/routes_city.py`
2. Забезпечити повернення:
3. rooms list
4. occupancy (online count)
5. agents list per room
6. matrix room mapping

### Expected Response

    {
      "rooms": [
        {
          "id": "uuid",
          "slug": "general",
          "name": "General",
          "room_type": "chat",
          "owner_type": "city",
          "matrix_room_id": "!abc:matrix.daarion.space",
          "online_count": 5,
          "agents": [
            {"id": "dario", "display_name": "DARIO", "role": "primary"}
          ]
        }
      ],
      "total": 8
    }

## 3.7. Перевірка Gateway

### Завдання

1. Перевірити health matrix-gateway (`/health`)
2. Перевірити NATS підключення
3. Перевірити Matrix credentials
4. Перезапустити якщо потрібно

### Health Check Commands

    # Check gateway health
    curl http://localhost:9300/health

    # Check Matrix connection
    curl http://localhost:9300/internal/matrix/status

    # Check NATS connection
    docker logs gateway | grep -i nats

# 4. ЧЕКЛІСТ ВПРОВАДЖЕННЯ

Після завершення цього таска:

- [ ] `/city/map` — показує кімнати ✅
- [ ] `/city` (список view) — працює
- [ ] У кожного MicroDAO є свої кімнати (5+)
- [ ] У кожного агента є своя чат-кімната
- [ ] У кожної ноди є своя чат-кімната
- [ ] Matrix кімнати реально існують
- [ ] Gateway виконує join + send
- [ ] Citizens Layer показує публічних агентів (5+)
- [ ] Всі сторінки мають агентів + чат-віджет працює

# 5. ПОРЯДОК ВИКОНАННЯ

1. Seed City Rooms → SQL migration
2. Create Matrix Rooms → gateway API calls
3. Update city_rooms → set matrix_room_id
4. Fix /rooms/list API → return proper data
5. Seed MicroDAO Rooms → for DAARION root
6. Fix Citizens Layer → update query
7. Test Agent Chat → ensure auto-create works
8. Test Node Chat → ensure rooms exist
9. Verify UI → all pages show rooms

# 6. ВИХІДНІ АРТЕФАКТИ

Після виконання:

- `docs/debug/rooms_layer_restore_report_<DATE>.md`
- SQL migration file
- Updated API endpoints
- UI verification screenshots

# 7. ІНСТРУКЦІЯ ДЛЯ CURSOR

    Виконай TASK_PHASE_ROOMS_LAYER_RESTORE_AND_MATRIX_INTEGRATION.md.

    Працюй у модулях:
    1) city-service (FastAPI) — routes_city.py, repo_city.py, migrations.py
    2) matrix-gateway — room creation API
    3) apps/web (Next.js) — rooms list, citizens page

    Дотримуйся документації у /docs/foundation/.
    Після кожного сектора — роби git commit.
    Не змінюй інші частини системи.

Target Date: Immediate Priority: Critical Dependencies: Matrix gateway running, PostgreSQL accessible