# 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. Сторінка кімнати: - назва, опис, тип кімнати; - список ключових агентів (host/moderators); - presence-індикатори; - чат-виджет, прив'язаний до room_id / matrix_room_id. 4. Обробка помилок: - 404, якщо кімната не існує; - fallback UI, якщо Matrix тимчасово недоступний. --- # 4. МОДУЛЬ 1 — BACKEND (CITY-SERVICE) API (якщо ще немає) Перевірити/додати в city-service: ## 4.1. GET /api/v1/city/rooms Список всіх city-кімнат. Вихід: ```json [ { "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. Вихід: ```json { "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` (або створити новий): ```ts export async function getCityRooms(): Promise { ... } export async function getCityRoomBySlug(slug: string): Promise { ... } ``` Де `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: - якщо вже є універсальний `` з режимами 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: - Next.js `notFound()` → стандартна 404-сторінка. 2. Якщо помилка backend (500): - показати повідомлення "Кімната тимчасово недоступна". 3. Якщо немає `matrix_room_id`: - показати банер "Matrix ще синхронізується, чат скоро з'явиться". --- # 10. SMOKE-ТЕСТИ Після завершення: 1. `/city`: - список/мапа містить 8+ кімнат. 2. `/city/general`: - сторінка відкривається; - видно назву, опис; - видно host-агентів (наприклад, DARIO/DARIA); - видно presence. 3. `/city/welcome`, `/city/leadership-hall`, `/city/builders`, `/city/security`, `/city/announcements`: - усі відкриваються без 404. 4. Chat: - у кімнаті `/city/general` можливо: - побачити історію повідомлень; - відправити нове повідомлення (як авторизований користувач). --- # 11. FINISH-АРТЕФАКТ Після виконання Cursor створює: `docs/debug/city_rooms_routing_report_.md` Зі змістом: - список slug'ів city-кімнат; - приклади успішних HTTP-викликів: - `GET /api/v1/city/rooms` - `GET /api/v1/city/rooms/{slug}` - скріншот або опис перевірки `/city/{slug}`; - підтвердження роботи чату в принаймні одній кімнаті. --- # 12. PROMPT ДЛЯ CURSOR ```text Виконай 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_.md ``` --- **Target Date**: Immediate **Priority**: High **Dependencies**: Matrix integration complete, Chat API working