feat(rooms): Add city-lobby with DAARWIZZ + fix API proxy
- Created city-lobby room as main public chat with DAARWIZZ - Fixed /api/city/rooms proxy to use correct backend path (/api/v1/city/rooms) - Updated district rooms with zone keys (leadership, system, engineering, etc.) - Set MicroDAO lobbies as primary rooms - Created seed_city_rooms.py script - Created TASK_PHASE_CITY_ROOMS_AND_PUBLIC_CHAT_v1.md Total: 35 rooms, 31 public, 10 districts
This commit is contained in:
@@ -11,7 +11,7 @@ export async function GET(_req: NextRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`${API_BASE}/city/rooms`, {
|
const res = await fetch(`${API_BASE}/api/v1/city/rooms`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
cache: "no-store",
|
cache: "no-store",
|
||||||
|
|||||||
334
docs/tasks/TASK_PHASE_CITY_ROOMS_AND_PUBLIC_CHAT_v1.md
Normal file
334
docs/tasks/TASK_PHASE_CITY_ROOMS_AND_PUBLIC_CHAT_v1.md
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
# TASK_PHASE_CITY_ROOMS_AND_PUBLIC_CHAT_v1
|
||||||
|
|
||||||
|
Проєкт: DAARION.city
|
||||||
|
Мета:
|
||||||
|
1) оживити "Кімнати Міста" (City Rooms) – карта + список;
|
||||||
|
2) додати головний публічний чат з DAARWIZZ;
|
||||||
|
3) дозволити створювати кімнати всередині MicroDAO з перемикачем Public/Private.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. Поточний стан
|
||||||
|
|
||||||
|
UI (за скріншотами):
|
||||||
|
|
||||||
|
- MicroDAO:
|
||||||
|
- є список MicroDAO з картками (DAARION DAO, Energy Union, GreenFood, Soul…).
|
||||||
|
- всередині MicroDAO є блок "Orchestrator Team Chat", але кімнати явно не підключені.
|
||||||
|
- City Rooms:
|
||||||
|
- вкладка "Мапа" показує сітку районів (Leadership Hall, System Control, Engineering, Marketing, Finance, Web3, Security, Vision, R&D, Memory, Welcome/General).
|
||||||
|
- вкладка "Список" показує "Кімнати не знайдено".
|
||||||
|
- Matrix / gateway:
|
||||||
|
- Matrix-інтеграція вже є (див. існуючі `matrix-architecture`/`gateway` доки).
|
||||||
|
- Є публічні кімнати, але вони не підв'язані до city-service Rooms API.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Scope
|
||||||
|
|
||||||
|
### Включено
|
||||||
|
|
||||||
|
1. **Нова модель "кімнати міста" (City Rooms)** в бекенді:
|
||||||
|
- з прив'язкою до MicroDAO / району / Matrix roomId.
|
||||||
|
|
||||||
|
2. **API для кімнат**:
|
||||||
|
- список, створення, оновлення visibility (Public/Private), отримання деталей.
|
||||||
|
|
||||||
|
3. **Головна кімната "City Lobby" з DAARWIZZ**:
|
||||||
|
- спеціальний флаг `is_city_default`.
|
||||||
|
|
||||||
|
4. **MicroDAO Rooms**:
|
||||||
|
- список кімнат MicroDAO;
|
||||||
|
- кнопка `+ Створити кімнату` з перемикачем Public/Private.
|
||||||
|
|
||||||
|
5. **City Rooms UI**:
|
||||||
|
- вкладка "Список" – реальні кімнати з фільтрами;
|
||||||
|
- вкладка "Мапа" – tiles прив'язані до реальних кімнат (по district).
|
||||||
|
|
||||||
|
### Виключено
|
||||||
|
|
||||||
|
- Повна CrewAI-логіка (запуск декількох агентів як команди) – це окремий Task 3.
|
||||||
|
- Управління правами Matrix-кімнат (залишаємо базове: створює gateway, ACL мінімальні).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Backend – модель "кімнати"
|
||||||
|
|
||||||
|
### 2.1. Схема БД
|
||||||
|
|
||||||
|
Створити міграцію `migrations/043_city_rooms.sql`:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- City Rooms table for DAARION.city
|
||||||
|
-- Supports: city rooms, microdao rooms, crew rooms, district rooms
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS city_rooms (
|
||||||
|
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
|
slug text UNIQUE NOT NULL,
|
||||||
|
title text NOT NULL,
|
||||||
|
description text,
|
||||||
|
room_type text NOT NULL, -- 'city', 'microdao', 'crew', 'district'
|
||||||
|
visibility text NOT NULL DEFAULT 'private', -- 'public', 'microdao', 'private'
|
||||||
|
microdao_id text NULL REFERENCES microdaos(id),
|
||||||
|
district_key text NULL, -- 'leadership', 'security', 'engineering', etc.
|
||||||
|
matrix_room_id text NULL,
|
||||||
|
is_city_default boolean NOT NULL DEFAULT false,
|
||||||
|
is_microdao_default boolean NOT NULL DEFAULT false,
|
||||||
|
orchestrator_agent_id text NULL REFERENCES agents(id),
|
||||||
|
icon text NULL,
|
||||||
|
color text NULL,
|
||||||
|
created_by text NULL REFERENCES users(id),
|
||||||
|
created_at timestamptz NOT NULL DEFAULT now(),
|
||||||
|
updated_at timestamptz NOT NULL DEFAULT now(),
|
||||||
|
archived_at timestamptz NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_city_rooms_microdao ON city_rooms (microdao_id);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_city_rooms_district ON city_rooms (district_key);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_city_rooms_visibility ON city_rooms (visibility);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_city_rooms_type ON city_rooms (room_type);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_city_rooms_archived ON city_rooms (archived_at) WHERE archived_at IS NULL;
|
||||||
|
|
||||||
|
COMMENT ON TABLE city_rooms IS 'Кімнати міста DAARION - для чатів, команд, районів';
|
||||||
|
COMMENT ON COLUMN city_rooms.room_type IS 'Тип кімнати: city (міська), microdao, crew (команда), district (район)';
|
||||||
|
COMMENT ON COLUMN city_rooms.visibility IS 'Видимість: public (всім), microdao (членам MicroDAO), private (запрошеним)';
|
||||||
|
COMMENT ON COLUMN city_rooms.is_city_default IS 'Головна кімната міста (City Lobby з DAARWIZZ)';
|
||||||
|
COMMENT ON COLUMN city_rooms.is_microdao_default IS 'Головна кімната MicroDAO';
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2. Repo / models / routes
|
||||||
|
|
||||||
|
* У `models_city.py`:
|
||||||
|
* додати `CityRoom` / `CityRoomSummary` з полями вище.
|
||||||
|
|
||||||
|
* У `repo_city.py`:
|
||||||
|
* `get_city_rooms(filter_by_visibility, filter_by_microdao, filter_by_district)`
|
||||||
|
* `get_city_room_by_slug(slug)`
|
||||||
|
* `create_city_room(...)`
|
||||||
|
* `update_city_room_visibility(slug, visibility)`
|
||||||
|
|
||||||
|
* У `routes_city.py`:
|
||||||
|
* `GET /api/v1/city/rooms`
|
||||||
|
* query params: `visibility`, `microdao_slug`, `district`.
|
||||||
|
* `POST /api/v1/city/rooms`
|
||||||
|
* body: `{ title, description?, room_type, visibility, microdao_slug?, district_key? }`.
|
||||||
|
* `PATCH /api/v1/city/rooms/{slug}`
|
||||||
|
* змінити: `title`, `description`, `visibility`, `archived_at`.
|
||||||
|
|
||||||
|
### 2.3. Matrix інтеграція
|
||||||
|
|
||||||
|
Для створення нової кімнати:
|
||||||
|
|
||||||
|
* при `POST /api/v1/city/rooms`:
|
||||||
|
* бекенд:
|
||||||
|
* викликає gateway / internal service:
|
||||||
|
* напр. `POST /internal/matrix/create-room` з payload:
|
||||||
|
* `{ "slug": "...", "title": "...", "visibility": "public|private" }`;
|
||||||
|
* отримує `matrix_room_id`.
|
||||||
|
* записує `matrix_room_id` в `city_rooms`.
|
||||||
|
|
||||||
|
Фактичний URL/сервіс знайти в існуючих доках `gateway` / `matrix-architecture` і використати.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Seed даних
|
||||||
|
|
||||||
|
### 3.1. City Lobby з DAARWIZZ
|
||||||
|
|
||||||
|
Створити `scripts/seed_city_rooms.py`:
|
||||||
|
|
||||||
|
* Якщо немає кімнати `slug = 'city-lobby'`:
|
||||||
|
* створити запис:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"slug": "city-lobby",
|
||||||
|
"title": "DAARION City Lobby",
|
||||||
|
"description": "Головний публічний чат з DAARWIZZ.",
|
||||||
|
"room_type": "city",
|
||||||
|
"visibility": "public",
|
||||||
|
"is_city_default": true,
|
||||||
|
"orchestrator_agent_id": "daarwizz"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
* Викликати Matrix-gateway для створення відповідної Matrix-кімнати.
|
||||||
|
* Прив'язати до MicroDAO DAARION (якщо потрібно – через окрему таблицю або поле).
|
||||||
|
|
||||||
|
### 3.2. Default кімнати MicroDAO (по 1 на платформу)
|
||||||
|
|
||||||
|
Для кожної з платформ:
|
||||||
|
|
||||||
|
* `daarion` (DAARION DAO)
|
||||||
|
* `energy-union` (Energy Union)
|
||||||
|
* `greenfood` (GreenFood DAO)
|
||||||
|
* `soul` (Soul Retreat Hub)
|
||||||
|
|
||||||
|
створити room:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"slug": "microdao-<slug>-lobby",
|
||||||
|
"title": "<Name> Lobby",
|
||||||
|
"room_type": "microdao",
|
||||||
|
"visibility": "microdao",
|
||||||
|
"microdao_id": "...",
|
||||||
|
"is_microdao_default": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3. District Rooms (10 районів)
|
||||||
|
|
||||||
|
Для кожного району з `agents_city_mapping.yaml`:
|
||||||
|
|
||||||
|
* leadership → "Leadership Hall"
|
||||||
|
* system → "System Control Center"
|
||||||
|
* engineering → "Engineering Lab"
|
||||||
|
* marketing → "Marketing Hub"
|
||||||
|
* finance → "Finance Office"
|
||||||
|
* web3 → "Web3 District"
|
||||||
|
* security → "Security Bunker"
|
||||||
|
* vision → "Vision Studio"
|
||||||
|
* rnd → "R&D Laboratory"
|
||||||
|
* memory → "Memory Vault"
|
||||||
|
|
||||||
|
створити room:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"slug": "district-<key>",
|
||||||
|
"title": "<Name>",
|
||||||
|
"room_type": "district",
|
||||||
|
"visibility": "public",
|
||||||
|
"district_key": "<key>"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Frontend – MicroDAO сторінка
|
||||||
|
|
||||||
|
Файли: `apps/web/src/app/microdao/page.tsx`, `apps/web/src/app/microdao/[slug]/page.tsx` та пов'язані компоненти.
|
||||||
|
|
||||||
|
### 4.1. API hook
|
||||||
|
|
||||||
|
Створити хук:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// apps/web/src/hooks/useMicrodaoRooms.ts
|
||||||
|
import useSWR from 'swr';
|
||||||
|
import { fetcher } from '@/lib/fetcher';
|
||||||
|
|
||||||
|
export function useMicrodaoRooms(slug: string) {
|
||||||
|
return useSWR(slug ? `/api/city/rooms?microdao_slug=${slug}` : null, fetcher);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
(через існуючий proxy `/api/...` до бекенду).
|
||||||
|
|
||||||
|
### 4.2. Блок "Кімнати MicroDAO"
|
||||||
|
|
||||||
|
На сторінці MicroDAO:
|
||||||
|
|
||||||
|
* додати секцію під Branding / перед "Orchestrator Team Chat":
|
||||||
|
|
||||||
|
Макет:
|
||||||
|
|
||||||
|
* Заголовок: `Кімнати MicroDAO`
|
||||||
|
* Кнопка праворуч: `+ Створити кімнату`
|
||||||
|
* Список карток:
|
||||||
|
|
||||||
|
```
|
||||||
|
[ DAARION DAO Lobby ] [ Leadership Crew ] [ Security Council ]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3. Модалка "Створити кімнату"
|
||||||
|
|
||||||
|
Поля:
|
||||||
|
|
||||||
|
* Назва кімнати
|
||||||
|
* Опис (опційно)
|
||||||
|
* Тип (read-only: `MicroDAO`)
|
||||||
|
* Перемикач: `Публічна кімната`
|
||||||
|
* якщо вимкнено → `visibility = 'microdao'` (лише члени MicroDAO);
|
||||||
|
* якщо увімкнено → `visibility = 'public'`.
|
||||||
|
|
||||||
|
On submit → `POST /api/city/rooms`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Frontend – City Rooms сторінка
|
||||||
|
|
||||||
|
Файл: `apps/web/src/app/city/page.tsx` або `apps/web/src/app/city/rooms/page.tsx` (подивитись фактичний).
|
||||||
|
|
||||||
|
### 5.1. Вкладка "Список"
|
||||||
|
|
||||||
|
* Використати `GET /api/city/rooms?visibility=public` за замовчанням.
|
||||||
|
* Відображати таблицею/картками:
|
||||||
|
|
||||||
|
Поля:
|
||||||
|
|
||||||
|
* Назва
|
||||||
|
* Тип / District / MicroDAO
|
||||||
|
* Іконки:
|
||||||
|
* Public / MicroDAO / Private
|
||||||
|
* Лічильник:
|
||||||
|
* `X агентів` (опційно, якщо буде окремий endpoint; на MVP можна не показувати).
|
||||||
|
|
||||||
|
### 5.2. Вкладка "Мапа"
|
||||||
|
|
||||||
|
* Для tile'ів районів (Leadership Hall, Security Bunker, Web3 District, …):
|
||||||
|
* під'єднати відповідні `city_rooms` через `district_key`.
|
||||||
|
* Клік по tile → переходить на `/city/rooms/[slug]` або відкриває чат.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Frontend – головний CTA з DAARWIZZ
|
||||||
|
|
||||||
|
На головній сторінці `apps/web/src/app/page.tsx`:
|
||||||
|
|
||||||
|
* додати основну кнопку (у hero-секції):
|
||||||
|
|
||||||
|
`Поспілкуватися з DAARWIZZ`
|
||||||
|
|
||||||
|
* дія:
|
||||||
|
* `router.push('/city/rooms/city-lobby')`
|
||||||
|
* або відкриває вбудований чат-віджет, якщо він уже реалізований.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Acceptance Criteria
|
||||||
|
|
||||||
|
1. `GET /api/v1/city/rooms` повертає список кімнат (мінімум: `city-lobby` + 4 MicroDAO лобі + 10 district rooms).
|
||||||
|
|
||||||
|
2. На сторінці MicroDAO:
|
||||||
|
* видно блок "Кімнати MicroDAO";
|
||||||
|
* кнопка `+ Створити кімнату` створює запис у БД;
|
||||||
|
* нова кімната з'являється у списку без перезавантаження.
|
||||||
|
|
||||||
|
3. На сторінці City Rooms:
|
||||||
|
* вкладка "Список" показує реальні кімнати;
|
||||||
|
* вкладка "Мапа" не показує помилок, tile'и районів прив'язані до відповідних кімнат (або до лобі за замовчанням).
|
||||||
|
|
||||||
|
4. При переході на `/city/rooms/city-lobby` відкривається чат з DAARWIZZ (Matrix roomId збережений у `city_rooms`).
|
||||||
|
|
||||||
|
5. Нові кімнати MicroDAO мають коректний visibility:
|
||||||
|
* без галочки – не видно у `?visibility=public`;
|
||||||
|
* з галочкою – видно у публічному списку.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Наступні кроки (Task 3)
|
||||||
|
|
||||||
|
Після реалізації цього таска:
|
||||||
|
|
||||||
|
- ти матимеш головний публічний чат з DAARWIZZ на головній;
|
||||||
|
- кожне MicroDAO зможе створювати свої кімнати з вибором публічності;
|
||||||
|
- сторінка "Кімнати Міста" перестане бути пустою й стане справжнім лобі міста.
|
||||||
|
|
||||||
|
А керування агентами (створення/видалення, Crew-кімнати) винесемо в наступний Task 3:
|
||||||
|
- Глобальна кнопка "Створити агента" на `/agents`
|
||||||
|
- Локальна кнопка "Додати агента цієї ноди" в Node Cabinet
|
||||||
|
- Видалення/архівація агента в кабінеті агента
|
||||||
|
- Групи агентів = кімнати команд (CrewAI)
|
||||||
|
|
||||||
197
scripts/seed_city_rooms.py
Normal file
197
scripts/seed_city_rooms.py
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Seed City Rooms for DAARION.city
|
||||||
|
|
||||||
|
Creates:
|
||||||
|
1. City Lobby with DAARWIZZ (main public chat)
|
||||||
|
2. Updates district rooms with district_key
|
||||||
|
3. Creates MicroDAO default lobbies if missing
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python scripts/seed_city_rooms.py --dry-run # Preview changes
|
||||||
|
python scripts/seed_city_rooms.py # Apply changes
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add project root to path
|
||||||
|
PROJECT_ROOT = Path(__file__).parent.parent
|
||||||
|
sys.path.insert(0, str(PROJECT_ROOT))
|
||||||
|
|
||||||
|
# Database connection
|
||||||
|
DATABASE_URL = os.getenv(
|
||||||
|
"DATABASE_URL",
|
||||||
|
"postgresql://postgres:postgres@144.76.224.179:5432/daarion"
|
||||||
|
)
|
||||||
|
|
||||||
|
# District mapping from agents_city_mapping.yaml
|
||||||
|
DISTRICTS = [
|
||||||
|
{"key": "leadership", "name": "Leadership Hall", "slug": "leadership-hall", "color": "#F59E0B", "icon": "crown"},
|
||||||
|
{"key": "system", "name": "System Control Center", "slug": "system-control", "color": "#6366F1", "icon": "cpu"},
|
||||||
|
{"key": "engineering", "name": "Engineering Lab", "slug": "engineering-lab", "color": "#10B981", "icon": "code"},
|
||||||
|
{"key": "marketing", "name": "Marketing Hub", "slug": "marketing-hub", "color": "#EC4899", "icon": "megaphone"},
|
||||||
|
{"key": "finance", "name": "Finance Office", "slug": "finance-office", "color": "#14B8A6", "icon": "banknotes"},
|
||||||
|
{"key": "web3", "name": "Web3 District", "slug": "web3-district", "color": "#8B5CF6", "icon": "cube"},
|
||||||
|
{"key": "security", "name": "Security Bunker", "slug": "security-bunker", "color": "#EF4444", "icon": "shield"},
|
||||||
|
{"key": "vision", "name": "Vision Studio", "slug": "vision-studio", "color": "#22D3EE", "icon": "eye"},
|
||||||
|
{"key": "rnd", "name": "R&D Laboratory", "slug": "rnd-lab", "color": "#A855F7", "icon": "beaker"},
|
||||||
|
{"key": "memory", "name": "Memory Vault", "slug": "memory-vault", "color": "#06B6D4", "icon": "database"},
|
||||||
|
]
|
||||||
|
|
||||||
|
# MicroDAO lobbies
|
||||||
|
MICRODAOS = [
|
||||||
|
{"slug": "daarion", "name": "DAARION DAO", "lobby_slug": "daarion-lobby"},
|
||||||
|
{"slug": "energy-union", "name": "Energy Union", "lobby_slug": "energy-union-lobby"},
|
||||||
|
{"slug": "greenfood", "name": "GreenFood DAO", "lobby_slug": "greenfood-lobby"},
|
||||||
|
{"slug": "soul", "name": "Soul Retreat Hub", "lobby_slug": "soul-lobby"},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def seed_rooms(dry_run: bool = True):
|
||||||
|
"""Seed city rooms."""
|
||||||
|
import asyncpg
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print("🏙️ DAARION City Rooms Seed")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
print("\n🔍 DRY RUN - No changes will be made\n")
|
||||||
|
|
||||||
|
conn = await asyncpg.connect(DATABASE_URL)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 1. Create City Lobby with DAARWIZZ
|
||||||
|
print("\n📍 Step 1: City Lobby with DAARWIZZ")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
existing_lobby = await conn.fetchrow(
|
||||||
|
"SELECT id, slug FROM city_rooms WHERE slug = 'city-lobby'"
|
||||||
|
)
|
||||||
|
|
||||||
|
if existing_lobby:
|
||||||
|
print(f" ✅ City Lobby already exists: {existing_lobby['id']}")
|
||||||
|
else:
|
||||||
|
print(" 📝 Creating City Lobby...")
|
||||||
|
if not dry_run:
|
||||||
|
await conn.execute("""
|
||||||
|
INSERT INTO city_rooms (
|
||||||
|
id, slug, name, description, room_type, visibility,
|
||||||
|
is_default, is_public, sort_order, owner_type, space_scope
|
||||||
|
) VALUES (
|
||||||
|
'room_city_lobby',
|
||||||
|
'city-lobby',
|
||||||
|
'DAARION City Lobby',
|
||||||
|
'Головний публічний чат з DAARWIZZ. Ласкаво просимо до DAARION!',
|
||||||
|
'city',
|
||||||
|
'public-city',
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
1,
|
||||||
|
'city',
|
||||||
|
'city'
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
print(" ✅ City Lobby created!")
|
||||||
|
else:
|
||||||
|
print(" Would create: city-lobby (DAARION City Lobby)")
|
||||||
|
|
||||||
|
# 2. Update district rooms with district_key (using zone field)
|
||||||
|
print("\n📍 Step 2: Update District Rooms")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
for district in DISTRICTS:
|
||||||
|
existing = await conn.fetchrow(
|
||||||
|
"SELECT id, slug, zone FROM city_rooms WHERE slug = $1",
|
||||||
|
district["slug"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if existing:
|
||||||
|
if existing["zone"] != district["key"]:
|
||||||
|
print(f" 📝 Updating {district['slug']} with zone={district['key']}")
|
||||||
|
if not dry_run:
|
||||||
|
await conn.execute("""
|
||||||
|
UPDATE city_rooms
|
||||||
|
SET zone = $1, room_type = 'district', color = $2, icon = $3
|
||||||
|
WHERE slug = $4
|
||||||
|
""", district["key"], district["color"], district["icon"], district["slug"])
|
||||||
|
else:
|
||||||
|
print(f" ✅ {district['slug']} already has zone={district['key']}")
|
||||||
|
else:
|
||||||
|
print(f" 📝 Creating district room: {district['slug']}")
|
||||||
|
if not dry_run:
|
||||||
|
await conn.execute("""
|
||||||
|
INSERT INTO city_rooms (
|
||||||
|
id, slug, name, room_type, visibility, zone,
|
||||||
|
is_public, sort_order, owner_type, space_scope, color, icon
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, 'district', 'public-city', $4,
|
||||||
|
true, 50, 'city', 'city', $5, $6
|
||||||
|
)
|
||||||
|
""", f"room_district_{district['key']}", district["slug"],
|
||||||
|
district["name"], district["key"], district["color"], district["icon"])
|
||||||
|
|
||||||
|
# 3. Verify MicroDAO lobbies
|
||||||
|
print("\n📍 Step 3: Verify MicroDAO Lobbies")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
for dao in MICRODAOS:
|
||||||
|
existing = await conn.fetchrow(
|
||||||
|
"SELECT id, slug, room_role FROM city_rooms WHERE slug = $1",
|
||||||
|
dao["lobby_slug"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if existing:
|
||||||
|
if existing["room_role"] != "primary":
|
||||||
|
print(f" 📝 Setting {dao['lobby_slug']} as primary room")
|
||||||
|
if not dry_run:
|
||||||
|
await conn.execute("""
|
||||||
|
UPDATE city_rooms SET room_role = 'primary' WHERE slug = $1
|
||||||
|
""", dao["lobby_slug"])
|
||||||
|
else:
|
||||||
|
print(f" ✅ {dao['lobby_slug']} is primary room")
|
||||||
|
else:
|
||||||
|
print(f" ⚠️ Missing: {dao['lobby_slug']} - will need manual creation")
|
||||||
|
|
||||||
|
# 4. Summary
|
||||||
|
print("\n📊 Summary")
|
||||||
|
print("-" * 40)
|
||||||
|
|
||||||
|
total = await conn.fetchval("SELECT COUNT(*) FROM city_rooms")
|
||||||
|
public = await conn.fetchval("SELECT COUNT(*) FROM city_rooms WHERE is_public = true")
|
||||||
|
districts = await conn.fetchval("SELECT COUNT(*) FROM city_rooms WHERE room_type = 'district'")
|
||||||
|
|
||||||
|
print(f" Total rooms: {total}")
|
||||||
|
print(f" Public rooms: {public}")
|
||||||
|
print(f" District rooms: {districts}")
|
||||||
|
|
||||||
|
if dry_run:
|
||||||
|
print("\n🔍 DRY RUN complete - no changes were made")
|
||||||
|
else:
|
||||||
|
print("\n✅ Seed complete!")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
await conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Seed City Rooms for DAARION.city"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--dry-run",
|
||||||
|
action="store_true",
|
||||||
|
help="Preview changes without applying them"
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
asyncio.run(seed_rooms(dry_run=args.dry_run))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
Reference in New Issue
Block a user