TASK_PHASE_MICRODAO_DASHBOARD_v1¶
Статус: PLANNED
Пріоритет: High (презентація MVP)
1. Ціль¶
Зробити повноцінний кабінет MicroDAO (спочатку для DAARION DAO), який показує:
-
базові метрики DAO (кімнати, громадяни, агенти);
-
стрічку активності (новини/апдейти);
-
кімнати DAO + кнопки створення кімнати;
-
команду DAO (ключові агенти/громадяни);
-
підготовлені секції під проєкти/задачі/файли/інтеграції.
Архітектурна вимога: цей самий дашборд повинен працювати для будь-якого MicroDAO (slug-залежний), щоб його можна було фрактально клонувати.
2. Поточний стан¶
Є:
-
/microdao — список MicroDAO (з лого, тегами, pinned-сортуванням).
-
/microdao/[slug] — сторінка MicroDAO з:
-
Branding (лого, банер),
-
visibility (public / platform),
-
MicroDAO Rooms section,
-
базовою статистикою (rooms count).
-
/city — кімнати міста (мапа + список).
-
/citizens — публічні агенти (громадяни).
-
/agents — Agent Console (63 агентів, фільтри по нодах, кнопка "Новий агент").
-
API для кімнат і агентів уже працює.
Немає:
-
окремого Dashboard API для MicroDAO;
-
таблиць для активності (новин) и DAO-level метрик;
-
явної прив'язки громадян до конкретного MicroDAO (лише district/room mapping).
3. Архітектура рішення¶
3.1. База даних (PostgreSQL)¶
3.1.1. Таблиця активності MicroDAO¶
Створити міграцію migrations/041_microdao_activity.sql:
CREATE TABLE microdao_activity (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
microdao_slug TEXT NOT NULL REFERENCES city_microdao(slug) ON DELETE CASCADE,
kind TEXT NOT NULL CHECK (kind IN ('post', 'event', 'update')),
title TEXT,
body TEXT NOT NULL,
author_agent_id UUID NULL REFERENCES city_agent(id),
author_name TEXT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX idx_microdao_activity_microdao_created_at
ON microdao_activity (microdao_slug, created_at DESC);
3.1.2. Розширити city_microdao під метрики (опціонально, але корисно)¶
Міграція migrations/042_microdao_stats.sql:
ALTER TABLE city_microdao
ADD COLUMN IF NOT EXISTS citizens_count INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS rooms_count INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS agents_count INTEGER NOT NULL DEFAULT 0,
ADD COLUMN IF NOT EXISTS last_update_at TIMESTAMPTZ;
На етапі MVP значення можна просто перераховувати на льоту в репозиторії й не оновлювати ці поля — але стовпці потрібні для майбутнього кешування.
3.2. Backend: FastAPI (city-service)¶
3.2.1. Repo-рівень (Python)¶
Файл: services/city-service/repo_city.py
Додати:
async def get_microdao_dashboard(conn, slug: str) -> MicrodaoDashboard:
"""
Aggregates:
- microdao summary
- last 5 activity items
- up to 5 rooms
- up to 6 citizens (agents) linked to this microdao
"""
Використати існуючі репо-методи:
-
get_microdao_by_slug -
get_microdao_rooms(slug) -
get_agents_by_microdao(slug)або аналог (якщо немає — додати простий SELECT по district/slug mapping).
Нові helper-методи:
async def get_microdao_activity(conn, slug: str, limit: int = 10) -> list[MicrodaoActivity]:
...
async def insert_microdao_activity(conn, activity: CreateMicrodaoActivity) -> MicrodaoActivity:
...
3.2.2. Pydantic-моделі¶
Файл: services/city-service/models_city.py
Додати:
class MicrodaoActivity(BaseModel):
id: UUID
microdao_slug: str
kind: str
title: str | None
body: str
author_agent_id: UUID | None
author_name: str | None
created_at: datetime
class CreateMicrodaoActivity(BaseModel):
kind: str = Field(pattern="^(post|event|update)$")
title: str | None = None
body: str
author_agent_id: UUID | None = None
author_name: str | None = None
class MicrodaoDashboard(BaseModel):
microdao: MicrodaoSummary
stats: MicrodaoStats
recent_activity: list[MicrodaoActivity]
rooms: list[RoomSummary]
citizens: list[PublicCitizenSummary]
MicrodaoStats:
class MicrodaoStats(BaseModel):
rooms_count: int
citizens_count: int
agents_count: int
last_update_at: datetime | None
3.2.3. Routes (FastAPI)¶
Файл: services/city-service/routes_city.py
Додати endpoints:
@router.get("/microdao/{slug}/dashboard", response_model=MicrodaoDashboard)
async def get_microdao_dashboard(slug: str, conn=Depends(get_conn)):
return await repo_city.get_microdao_dashboard(conn, slug)
@router.get("/microdao/{slug}/activity", response_model=list[MicrodaoActivity])
async def list_microdao_activity(slug: str, limit: int = 20, conn=Depends(get_conn)):
return await repo_city.get_microdao_activity(conn, slug, limit)
@router.post("/microdao/{slug}/activity", response_model=MicrodaoActivity, status_code=201)
async def create_microdao_activity(
slug: str,
payload: CreateMicrodaoActivity,
conn=Depends(get_conn),
# TODO: optional auth / orchestrator check
):
return await repo_city.create_microdao_activity(conn, slug, payload)
Для MVP можна не чіпати авторизацію — припустити, що виклик робить orchestrator через адмін-UI.
3.3. Frontend: Next.js (apps/web)¶
3.3.1. API-клієнт¶
Файл: apps/web/src/lib/api.ts
Додати:
export async function fetchMicrodaoDashboard(slug: string): Promise<MicrodaoDashboard> {
const res = await fetch(`${CITY_API_BASE_URL}/microdao/${slug}/dashboard`, { cache: "no-store" });
if (!res.ok) throw new Error("Failed to load microdao dashboard");
return res.json();
}
export async function fetchMicrodaoActivity(slug: string): Promise<MicrodaoActivity[]> {
const res = await fetch(`${CITY_API_BASE_URL}/microdao/${slug}/activity?limit=20`, { cache: "no-store" });
if (!res.ok) throw new Error("Failed to load microdao activity");
return res.json();
}
Типи MicrodaoDashboard / MicrodaoActivity додати до apps/web/src/lib/types.ts.
3.3.2. Структура сторінки /microdao/[slug]¶
Файл (вже існує):
apps/web/src/app/microdao/[slug]/page.tsx
Перетворити на Dashboard Layout:
-
На сервері викликати
fetchMicrodaoDashboard(slug). -
Розбити на секції:
<MicrodaoHeaderCard dashboard={dashboard} /> // hero
<MicrodaoDashboardGrid>
<MicrodaoActivitySection activity={dashboard.recent_activity} />
<MicrodaoRoomsSection rooms={dashboard.rooms} slug={slug} />
<MicrodaoTeamSection citizens={dashboard.citizens} />
<MicrodaoProjectsSection microdao={dashboard.microdao} /> // placeholder
<MicrodaoTasksSection microdao={dashboard.microdao} /> // placeholder
</MicrodaoDashboardGrid>
Нові компоненти:
-
apps/web/src/components/microdao/MicrodaoHeaderCard.tsx -
apps/web/src/components/microdao/MicrodaoActivitySection.tsx -
apps/web/src/components/microdao/MicrodaoTeamSection.tsx -
apps/web/src/components/microdao/MicrodaoProjectsSection.tsx(stub) -
apps/web/src/components/microdao/MicrodaoTasksSection.tsx(stub)
MicrodaoHeaderCard¶
Показати:
-
Лого (через
normalizeAssetUrl) -
Назву, теги (Platform / Core / Active)
-
Метрики:
-
{stats.rooms_count} Кімнат -
{stats.citizens_count} Громадян -
{stats.agents_count} Агентів -
кнопки:
-
"Поспілкуватися з DAARWIZZ" →
href="/city?room=city-lobby" -
"Створити кімнату" → прокрутка до секції кімнат або модалка.
MicrodaoActivitySection¶
-
Заголовок "Новини DAARION" (або назва DAO).
-
Список останніх 5–10 записів:
-
заголовок / перші рядки body,
-
дата,
-
автор (агент або author_name).
-
Якщо немає записів — показати
Empty state: "Поки що немає новин".
3.4. Зв'язок з існуючими розділами¶
-
MicroDAO Rooms: у компоненті
MicrodaoRoomsSectionвикористати вже існуючу логіку створення/видалення кімнат. -
Citizens:
MicrodaoTeamSectionповинна показувати тільки тих громадян, у якихhome_microdao_slugабо district/room mapping вказує на цей MicroDAO. На етапі MVP можна вибрати фіксований набір (наприклад, 6 ключових агентів DAARION) через простий SQL.
4. План виконання (для Cursor)¶
Крок 1. DB міграції¶
-
Створити
migrations/041_microdao_activity.sqlі042_microdao_stats.sql. -
Запустити міграції локально й на NODE1 (MVP DB).
Крок 2. Backend¶
-
Оновити
models_city.py— додати моделіMicrodaoActivity,CreateMicrodaoActivity,MicrodaoStats,MicrodaoDashboard. -
Оновити
repo_city.py— реалізувати aggregation дляget_microdao_dashboardта CRUD для activity. -
Оновити
routes_city.py— додати/microdao/{slug}/dashboardта/microdao/{slug}/activity.
Крок 3. Frontend¶
-
Оновити
apps/web/src/lib/types.tsтаapi.ts(типи й API-клієнт). -
Переписати
apps/web/src/app/microdao/[slug]/page.tsx, щоб вона використовувалаfetchMicrodaoDashboard. -
Створити компоненти:
-
MicrodaoHeaderCard.tsx -
MicrodaoActivitySection.tsx -
MicrodaoTeamSection.tsx -
(stubs)
MicrodaoProjectsSection.tsx,MicrodaoTasksSection.tsx
Крок 4. DAARION DAO як демо¶
-
Заповнити хоча б 5–10 записів
microdao_activityдляslug='daarion'(через SQL або простий admin-endpoint /seed). -
Прив'язати ключових агентів DAARION до цього MicroDAO (update в таблиці citizens/agents).
-
Перевірити сторінку
/microdao/daarion: -
лого + title;
-
метрики не ламаються (0 — ок, NaN — ні);
-
відображаються кімнати DAARION;
-
видно список 6+ громадян DAARION;
-
CTA "Поспілкуватися з DAARWIZZ" працює.
7. Що показувати на презентації¶
-
МікроDAO список — DAARION, Energy Union, GreenFood, Soul наверху (pin).
-
DAARION DAO сторінка:
-
красивий hero-блок як "панель керування DAO";
-
блок "Новини DAARION";
-
блок "Кімнати DAARION";
-
блок "Команда DAARION".
-
City Rooms — показати, що одна з кімнат — головний публічний чат (DAARION City Lobby) з DAARWIZZ.
-
Citizens / Agents — як реєстр агентів, які прив'язані до DAARION.
Це вже виглядає як живий кабінет DAO, а не просто сайт.
Якщо хочеш, наступним кроком можу згенерувати окремий TASK_PHASE_MICRODAO_DASHBOARD_v1_CURSOR_PROMPT.md з готовим промтом для Cursor (щоб він сам крок-за-кроком виконав усе з цього таска).