# TASK_PHASE_CITY_ROOMS_FINISH_v2
## Title
TASK_PHASE_CITY_ROOMS_FINISH_v2 — MicroDAO Rooms + City Lobby CTA + Online Stats Fix
## 1. Overview
Finish the DAARION City chat layer:
1. City Rooms page:
* Map + List already work.
* Fix `NaN` for online users count.
2. MicroDAO Rooms:
* Each MicroDAO must have its own rooms section.
* Ability to create new rooms from MicroDAO cabinet.
3. City Lobby CTA:
* Main public chat with DAARWIZZ should be accessible directly from the homepage and top navigation.
All changes must use existing architecture: `city-service` (FastAPI + Postgres) and `apps/web` (Next.js / React).
---
## 2. Current State (as of 2025-12-01)
* Backend:
* `scripts/seed_city_rooms.py` creates ~31 rooms (district rooms, lobbies, city lobby, etc.).
* `city-service` exposes `/api/v1/city/rooms` (already used by UI).
* Rooms table already contains:
* `id`
* `slug`
* `name` (title)
* `description`
* `zone` (district key)
* `room_type` (e.g. `city`, `district`, `microdao`, etc.)
* `is_public` (bool)
* `microdao_id` (nullable, for MicroDAO rooms)
* Frontend:
* `/city` (City Rooms):
* Map tab: grid of districts, shows total rooms and online counters.
* List tab: renders all rooms with description.
* At the bottom: summary cards: `Kімнат: 31`, `Онлайн: NaN`.
* MicroDAO pages (`/microdao/[slug]`):
* Currently have no dedicated "MicroDAO Rooms" section.
* Homepage (`/`):
* No direct CTA to "DAARION City Lobby".
---
## 3. Goals
1. **Fix online counter**:
* Never show `NaN` on the City Rooms page.
2. **MicroDAO Rooms UI**:
* On `/microdao/[slug]` display:
* List of rooms belonging to this MicroDAO.
* Button "Створити кімнату".
3. **City Lobby CTA**:
* On homepage and/or main menu:
* Button "Поспілкуватися з DAARWIZZ" that opens `DAARION City Lobby`.
---
## 4. Backend Tasks
### 4.1. Room model & repository
Files:
* `services/city-service/models_city.py`
* `services/city-service/repo_city.py`
* `services/city-service/routes_city.py`
1. **Ensure Room model exposes needed fields:**
```python
class CityRoomSummary(BaseModel):
id: str
slug: str
name: str
description: Optional[str]
zone: Optional[str]
room_type: str
microdao_id: Optional[str]
is_public: bool
members_online: int = 0 # ← must always be integer (0 by default)
```
2. **Repo method for city rooms:**
* `get_all_rooms()` must:
* Return `members_online` as integer (use `COALESCE(..., 0)`).
3. **Repo method for MicroDAO rooms:**
Add/verify method:
```python
async def get_microdao_rooms(microdao_id: str) -> List[dict]:
"""Get rooms for specific MicroDAO"""
# WHERE microdao_id = $1 AND is_public = true OR owner_type = 'microdao'
```
4. **API routes:**
* Verify endpoint: `GET /api/v1/city/rooms` returns `members_online: int`.
* Verify endpoint: `GET /city/microdao/{slug}/rooms` returns MicroDAO rooms.
* Add endpoint for room creation:
```python
class CreateRoomRequest(BaseModel):
title: str
description: Optional[str]
room_type: str = "microdao"
is_public: bool = False
@router.post("/city/microdao/{slug}/rooms")
async def create_microdao_room(slug: str, body: CreateRoomRequest):
# Create room for MicroDAO
```
5. **Online stats summary:**
* Add/verify endpoint: `GET /api/v1/city/rooms/summary`
* Returns: `{"rooms_total": int, "online_total": int}`
---
## 5. Frontend Tasks
Files:
* `apps/web/src/app/city/page.tsx`
* `apps/web/src/app/microdao/[slug]/page.tsx`
* `apps/web/src/app/page.tsx` (homepage)
* `apps/web/src/components/microdao/MicrodaoRoomsSection.tsx` (new)
### 5.1. Fix `NaN` online stats
1. In `city/page.tsx`:
* Ensure online count uses fallback:
```tsx
const onlineTotal = summary?.online_total ?? 0;
// or
const onlineTotal = Number(summary?.online_total) || 0;
```
2. If API returns `null` or `undefined`, display `0`.
### 5.2. MicroDAO Rooms section
In `apps/web/src/app/microdao/[slug]/page.tsx`:
1. Add API call:
```ts
const rooms = await fetchMicrodaoRooms(slug); // GET /city/microdao/{slug}/rooms
```
2. Render new section:
```tsx
Кімнати MicroDAO
{rooms.length === 0 ? (
Ще немає кімнат. Створіть першу кімнату для цієї платформи.
) : (
{rooms.map((room) => (
))}
)}
```
3. `MicrodaoRoomCard` component:
* title
* description
* room_type (badge)
* visibility (Public/Private badge)
* members_online
4. "Create Room" modal:
* Назва кімнати (title, required)
* Опис (optional)
* Тип (select: Lobby, Governance, Project, Crew)
* Видимість (switch: Public / Private, default = Private)
* On submit → POST `/city/microdao/{slug}/rooms`
### 5.3. City Lobby CTA
1. On homepage (`apps/web/src/app/page.tsx`):
```tsx
Головний публічний чат DAARION City
Поспілкуватися з DAARWIZZ та іншими громадянами міста.
```
2. Optionally add to navigation header:
* New item: "City Lobby" → `/city?room=city-lobby`
---
## 6. Acceptance Criteria
1. City Rooms page shows:
* Correct number of rooms.
* Online count is integer (0 allowed), never `NaN`.
2. MicroDAO page (`/microdao/daarion`, etc.) shows:
* "Кімнати MicroDAO" section.
* Ability to create a room.
* Newly created room appears in list.
3. Homepage shows:
* CTA "Поспілкуватися з DAARWIZZ".
* Clicking the button opens City Lobby room.
4. All routes work both on NODE1 and NODE2.