Skip to content

# TASK_PHASE_CITY_ROOMS_ROUTING_v1

Version: 1.0 Status: Ready Priority: High (City Layer UX + Matrix Rooms)

# 1. МЕТА

Зробити так, щоб кожна City Room була доступною за URL:

- `/city` — огляд усіх кімнат
- `/city/{slug}` — сторінка конкретної кімнати

Сторінка кімнати має:

- завантажувати дані кімнати з backend (room meta + matrix_room_id),
- показувати присутніх агентів,
- інтегрувати чат (Matrix room),
- показувати presence агентів.

# 2. ВИХІДНІ ДАНІ

Вже є:

- Таблиця `rooms` з city-кімнатами (scope = 'city', 8+ кімнат).
- Поле `slug` або еквівалент (наприклад `city-general`, `city-welcome` тощо).
- `matrix_room_id` заповнене (Matrix sync завершений).
- Matrix Gateway та Chat API:
- `GET /api/v1/chat/rooms/{room_id}/messages`
- `POST /api/v1/chat/rooms/{room_id}/messages`
- Presence Layer:
- `GET /api/v1/agents/{agent_id}/presence`
- Frontend:
- базовий Chat Widget
- компонент PresenceDot
- карта /city вже існує (огляд кімнат).

# 3. SCOPE

1. Frontend routing для `/city/{slug}` (Next.js, App Router).
2. API-обгортка для завантаження City Room.
3. Сторінка кімнати:
4. назва, опис, тип кімнати;
5. список ключових агентів (host/moderators);
6. presence-індикатори;
7. чат-виджет, прив'язаний до room_id / matrix_room_id.
8. Обробка помилок:
9. 404, якщо кімната не існує;
10. fallback UI, якщо Matrix тимчасово недоступний.

# 4. МОДУЛЬ 1 — BACKEND (CITY-SERVICE) API (якщо ще немає)

Перевірити/додати в city-service:

## 4.1. GET /api/v1/city/rooms

Список всіх city-кімнат.

Вихід:

    [
      {
        "id": "uuid",
        "slug": "city-general",
        "name": "General",
        "description": "Головна кімната міста",
        "scope": "city",
        "matrix_room_id": "!room:matrix.daarion.city",
        "host_agents": ["agent_id_1", "agent_id_2"]
      },
      ...
    ]

## 4.2. GET /api/v1/city/rooms/{slug}

Конкретна кімната за slug.

Вихід:

    {
      "id": "uuid",
      "slug": "city-general",
      "name": "General",
      "description": "Головна кімната міста",
      "scope": "city",
      "matrix_room_id": "!room:matrix.daarion.city",
      "host_agents": [
        {
          "id": "agent_id_1",
          "name": "DARIO",
          "role": "host"
        }
      ]
    }

Якщо кімнати немає → 404.

# 5. МОДУЛЬ 2 — FRONTEND API КЛІЄНТ

В `apps/web/src/lib/api/city.ts` (або створити новий):

    export async function getCityRooms(): Promise<CityRoomSummary[]> { ... }

    export async function getCityRoomBySlug(slug: string): Promise<CityRoomDetail> { ... }

Де `CityRoomDetail` містить як мінімум:

- id
- slug
- name
- description
- matrixRoomId
- hostAgents[]

# 6. МОДУЛЬ 3 — ROUTING: `/city/{slug}`

У `apps/web/src/app/city/[slug]/page.tsx`:

1. Прочитати `params.slug`.
2. Викликати `getCityRoomBySlug(slug)`.
3. Якщо 404 → показати `notFound()` (Next.js).
4. Якщо інша помилка → показати error boundary / fallback.

# 7. МОДУЛЬ 4 — UI СТОРІНКИ КІМНАТИ

Макет сторінки `/city/{slug}`:

## 7.1. Верхня частина (header)

- Назва кімнати (`room.name`)
- Підназва / опис (`room.description`)
- Badge: `City Room`
- Breadcrumb: `City / {room.name}`

## 7.2. Блок "Host Agents"

Карточка(и) головних агентів кімнати:

- аватар
- ім'я
- роль (host/moderator)
- PresenceDot (online/away/offline)
- посилання "Перейти в кабінет агента"

Дані брати з `host_agents`.

## 7.3. Блок "Room Info" (опціонально)

- список тегів (public / governance / help / etc.)
- кількість учасників (якщо є)

## 7.4. Блок "Chat"

Використати Chat Widget, але прив'язати не до Agent/Node/MicroDAO, а до ROOM:

- якщо вже є універсальний `<AgentChatWidget>` з режимами entityType, можна:
- додати `entityType="room"`
- `entityId = room.id`
- якщо ні — створити `CityRoomChatWidget`, який:
- бере `room.id` → `/api/v1/chat/rooms/{room.id}/messages`
- дозволяє надсилати повідомлення в кімнату

Для неавторизованих:

- "Увійдіть, щоб писати у міську кімнату".

# 8. МОДУЛЬ 5 — ІНТЕГРАЦІЯ З /city

На сторінці `/city`:

- у списку/мапі кімнат:
- додати посилання на `/city/{slug}`.
- клік по кімнаті → відкриває `/city/{slug}`.

# 9. ОБРОБКА ПОМИЛОК

1. Якщо `/api/v1/city/rooms/{slug}` повертає 404:

2. Next.js `notFound()` → стандартна 404-сторінка.

3. Якщо помилка backend (500):

4. показати повідомлення "Кімната тимчасово недоступна".

5. Якщо немає `matrix_room_id`:

6. показати банер "Matrix ще синхронізується, чат скоро з'явиться".

# 10. SMOKE-ТЕСТИ

Після завершення:

1. `/city`:

2. список/мапа містить 8+ кімнат.

3. `/city/general`:

4. сторінка відкривається;
5. видно назву, опис;
6. видно host-агентів (наприклад, DARIO/DARIA);

7. видно presence.

8. `/city/welcome`, `/city/leadership-hall`, `/city/builders`, `/city/security`, `/city/announcements`:

9. усі відкриваються без 404.

10. Chat:

11. у кімнаті `/city/general` можливо:
    - побачити історію повідомлень;
    - відправити нове повідомлення (як авторизований користувач).

# 11. FINISH-АРТЕФАКТ

Після виконання Cursor створює:

`docs/debug/city_rooms_routing_report_<DATE>.md`

Зі змістом:

- список slug'ів city-кімнат;
- приклади успішних HTTP-викликів:
- `GET /api/v1/city/rooms`
- `GET /api/v1/city/rooms/{slug}`
- скріншот або опис перевірки `/city/{slug}`;
- підтвердження роботи чату в принаймні одній кімнаті.

# 12. PROMPT ДЛЯ CURSOR

    Виконай TASK_PHASE_CITY_ROOMS_ROUTING_v1.md.

    Фокус:
    1) Backend: /api/v1/city/rooms, /api/v1/city/rooms/{slug} (якщо ще немає)
    2) Frontend: Next.js routing /city/[slug]
    3) UI: сторінка кімнати (host agents, presence, chat)
    4) Інтеграція з існуючими чат/Matrix/PRESENCE шарами

    Після завершення створи:
    docs/debug/city_rooms_routing_report_<DATE>.md

Target Date: Immediate Priority: High Dependencies: Matrix integration complete, Chat API working