# Team Board — Идеи и концепция ## Суть проекта **Team Board** — платформа для управления командой AI-агентов, работающих над проектами. **Ключевая идея:** Несколько AI-агентов работают как команда разработчиков. Человек видит всё: задачи, код, переписку. Полная прозрачность. --- ## Проблема, которую решаем Один универсальный AI-ассистент: - Контекст переполняется при разных задачах - Сложно параллельно вести несколько направлений - Нет специализации — один промпт на всё **Решение:** Команда специализированных агентов, каждый со своей ролью и контекстом. --- ## Архитектура: Tracker-Centric ### Принцип **Tracker = центральный сервис.** Всё остальное — клиенты. ``` ┌─────────────────────────────────────────────────────┐ │ WEB CLIENT │ │ ┌───────────┐ ┌────────────┐ │ │ │ Next.js │ ←→ │ BFF │ (свой бэкенд) │ │ │ фронтенд │ │ Python │ │ │ └───────────┘ │ + Authentik│ │ │ └─────┬──────┘ │ └──────────────────────────┼──────────────────────────┘ │ ws (внутренняя сеть) ┌────────────▼────────────┐ │ TRACKER │ │ (внутренний сервис) │ │ НЕ выставлен наружу │ │ │ │ - проекты │ │ - доски (канбан) │ │ - задачи + подзадачи │ │ - чаты │ │ - события │ │ - БД (PostgreSQL) │ └────────────┬────────────┘ │ ws ┌─────────────────┼─────────────────┐ ▼ ▼ ▼ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ Агент 1 │ │ Агент 2 │ │ Агент N │ │ (Claude) │ │ (Codex) │ │ (Gemini) │ │ отд. сервис │ │ отд. сервис │ │ отд. сервис │ └──────────────┘ └──────────────┘ └──────────────┘ ``` ### Компоненты | Компонент | Описание | |-----------|----------| | **Tracker** | Ядро: проекты, задачи, чаты, события. Внутренний, WebSocket сервер. Роутинг событий агентам | | **Web Client** | Next.js + BFF (Python). Авторизация через Authentik. Единственное что торчит наружу | | **Агенты** | Независимые приложения (любой язык). Подключаются к Tracker по WebSocket | ### Репозитории ``` team-board/ ├── tracker/ — ядро (Python, WebSocket, PostgreSQL) ├── web-client/ — Next.js + BFF └── docs/ — документация ``` Агенты — отдельные репозитории (шаблон + конкретные). --- ## Канбан-доска ### Колонки ``` ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Backlog │ │ TODO │ │ In Prog │ │ Review │ │ Done │ ├──────────┤ ├──────────┤ ├──────────┤ ├──────────┤ ├──────────┤ │ [draft] │ │ [ready] │ │ [active] │ │ [review] │ │[complete]│ │ [draft] │ │ [ready] │ │ │ │ │ │[complete]│ │ │ │ │ │ │ │ │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ ``` ### Статусы задач | Статус | Описание | |--------|----------| | `draft` | Черновик. Можно обсуждать, но не выполнять | | `ready` | Готова к выполнению. Перенос из Backlog → TODO автоматически ставит этот статус | | `in_progress` | Агент взял в работу | | `review` | На ревью у другого агента | | `completed` | Выполнена | | `blocked` | Заблокирована зависимостью | ### Жизненный цикл задачи ``` 1. Человек создаёт задачу → draft (Backlog) 2. Обсуждение в чате проекта 3. Человек перетаскивает в TODO → статус меняется на ready 4. Агент берёт задачу → in_progress 5. Агент завершает → review 6. Ревьюер проверяет → completed / возврат в in_progress ``` --- ## Задачи ### Структура задачи ```yaml Задача: id: uuid проект: project_id название: "Реализовать API авторизации" описание: "Markdown текст с деталями" статус: draft | ready | in_progress | review | completed | blocked # Лейблы (как в Jira — произвольные, создаются в трекере) лейблы: ["coding", "api", "backend", "urgent"] # PR (вручную или по лейблу) требует_pr: true | false # Назначение назначен: agent_id (или null) # Вложенные файлы файлы: - name: "schema.sql" type: "text/sql" content: "..." - name: "mockup.png" type: "image/png" url: "/files/task-123/mockup.png" # Подзадачи (неограниченная вложенность) подзадачи: - название: "Написать модели" назначен: agent-coder статус: completed - название: "Code review" назначен: agent-reviewer статус: in_progress # Зависимости зависит_от: [task_id_1, task_id_2] блокирует: [task_id_3] # Мета приоритет: low | medium | high | critical теги: ["api", "auth"] создано: timestamp обновлено: timestamp ``` ### Зависимости задач ``` Task A ──depends_on──→ Task B │ └─ Task A НЕ может быть взята пока Task B не completed Пример: "Написать тесты" зависит от "Написать код" "Деплой" зависит от "Тесты пройдены" ``` **Правила:** - Задача со статусом `blocked` не может быть взята агентом - Когда зависимость завершена → автоматически разблокировать - Циклические зависимости запрещены (валидация при создании) - В UI: визуальная связь между задачами (стрелки) ### Приложенные файлы - К задаче можно прикрепить файлы (код, изображения, документы) - Агент может добавлять файлы к задаче (результаты работы) - Файлы хранятся на диске, метаданные в БД - Превью для изображений и кода в UI --- ## Чаты ### Три уровня #### 1. Лобби (общий чат) Отдельная сущность, не привязан к проекту: - Обсуждение идей с агентами - Аналитика, brainstorm - Агент может создавать файлы, заметки - Место для обсуждения до создания проекта #### 2. Чат проекта У каждого проекта свой чат: - Обсуждение задач - Системные уведомления (задача создана, завершена, etc.) - Агенты видят только чаты своих проектов #### 3. Комментарии задачи Внутри каждой задачи: - Обсуждение деталей - Код ревью - Результаты подзадач --- ## Агенты ### Принцип **Агент = независимое приложение.** Написано на чём угодно (Python, Go, Rust, JS — без разницы). Подключается к Tracker по WebSocket. Может быть даже человек с WebSocket-клиентом. Tracker не знает и не заботится, что внутри агента — нейросеть, скрипт или человек. ### Структура агента ```yaml Агент: id: uuid имя: "Кодер" slug: "coder" # Capabilities — что умеет этот агент capabilities: ["coding", "backend", "testing"] # Подписка подписка: режим: assigned # all | mentions | assigned проекты: ["*"] # или конкретные # Ограничения макс_параллельных: 2 таймаут: 600 # секунд # Статус (управляется Tracker) status: online | offline | busy last_heartbeat: timestamp ``` ### Лейблы Произвольные метки, создаются в трекере (как в Jira): ```sql CREATE TABLE labels ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT UNIQUE NOT NULL, -- "coding", "design", "urgent" color TEXT, -- "#ff0000" created_at TIMESTAMPTZ DEFAULT NOW() ); ``` Примеры: `coding`, `design`, `analytics`, `testing`, `docs`, `backend`, `frontend`, `urgent`, `bug` ### Связка: лейблы задач ↔ capabilities агентов ``` Задача с лейблом "coding" → только агенты с capability "coding" Задача с лейблом "design" → только агенты с capability "design" ``` Агент-дизайнер НЕ возьмёт задачу с лейблом `coding` — у него нет такой capability. ### Подписка на события | Режим | Агент получает | |-------|---------------| | `all` | Все события в подписанных проектах | | `mentions` | Только когда @упомянут | | `assigned` | Назначенные задачи + mentions | --- ## WebSocket протокол ### Подключение и Init Handshake При подключении агент проходит аутентификацию и получает начальный контекст: ``` 1. Агент подключается: ws://tracker:8100/ws 2. Агент → Tracker: auth { "type": "auth", "token": "agent-token-xxx" } 3. Tracker → Агент: auth.ok + init (начальный контекст) { "type": "auth.ok", "agent": { "id": "uuid", "name": "Кодер", "capabilities": ["coding", "backend"] }, "init": { "projects": [ {"id": "uuid", "name": "Team Board", "slug": "team-board"} ], "assigned_tasks": [ {"id": "uuid", "title": "...", "status": "in_progress", "project_id": "uuid", "labels": ["coding"]} ], "pending_tasks": [ {"id": "uuid", "title": "...", "status": "ready", "project_id": "uuid", "labels": ["coding"]} ] } } 4. При ошибке: { "type": "auth.error", "message": "Invalid token" } → соединение закрывается ``` **init** содержит: - **projects** — проекты, в которых участвует агент - **assigned_tasks** — задачи, назначенные на этого агента (in_progress, review) - **pending_tasks** — задачи, подходящие по capabilities и готовые к взятию (ready) ### Роутинг событий (Tracker → Агент) Tracker фильтрует события по трём критериям: **1. Capabilities** — лейблы задачи ∩ capabilities агента - Задача с лейблом `coding` → только агентам с capability `coding` - Нет совпадения → событие не отправляется **2. Подписка агента** (subscription mode) - `assigned` → только свои задачи + @mentions - `mentions` → @mentions в чатах и комментариях - `all` → все события (фильтруются по capabilities) **3. Чаты** — отдельная логика: - **Чат задачи** → assignee + участники обсуждения - **Чат проекта** → все агенты проекта (без фильтра по capabilities — обсуждение для всех) - **Лобби** → все подключённые агенты ### Трекер → Клиент (события) ``` task.created — задача создана (с учётом роутинга) task.updated — задача обновлена (статус, описание, лейблы) task.ready — задача готова к выполнению task.assigned — задача назначена агенту task.blocked — задача заблокирована зависимостью task.unblocked — зависимость выполнена, задача разблокирована chat.message — новое сообщение в чате (с учётом роутинга) agent.status — статус агента изменился (online/offline/busy) file.attached — файл прикреплён к задаче ``` ### Клиент → Трекер (команды) ``` auth — аутентификация (первое сообщение) task.take — агент берёт задачу task.complete — агент завершил задачу task.update — агент обновляет задачу (статус, описание) task.comment — комментарий к задаче task.attach — прикрепить файл chat.send — отправить сообщение в чат agent.heartbeat — пульс (каждые 30 сек) ``` ### Heartbeat ``` Агент → Tracker (каждые 30 сек): { "type": "agent.heartbeat", "status": "idle" | "busy", "current_tasks": ["task-uuid-1"] } Если heartbeat не пришёл 90 секунд → agent.status = offline ``` --- ## Ревью и PR ### Не каждая задача = PR PR нужен когда задача связана с кодом. Определяется вручную или по лейблам: - Лейбл `coding` / `testing` → `требует_pr = true` (по умолчанию) - Лейбл `design` / `analytics` → `требует_pr = false` - Можно переопределить вручную ### Флоу ревью (для задач с PR) ``` 1. Агент работает → коммитит в feature branch 2. Создаёт PR в Gitea 3. Сдвигает задачу в Review 4. Трекер назначает ревьюера (другой агент, НЕ автор) 5. Ревьюер смотрит PR, пишет комментарии В ЗАДАЧЕ 6. Ок → Approve → Done, PR мержится 7. Не ок → замечания → обратно In Progress → автор исправляет ``` ### Флоу ревью (для задач без PR) ``` 1. Агент работает → прикрепляет результат (файл/отчёт) к задаче 2. Сдвигает в Review 3. Ревьюер проверяет результат 4. Ок → Done 5. Не ок → замечания → обратно In Progress ``` ### Правила ревью - Автор ≠ ревьюер (всегда) - Максимум 3 итерации — потом эскалация к человеку - Все комментарии в задаче (единый контекст) - Чат проекта = лог событий (всё видно) ### Итерации ревью ```yaml review_history: - iteration: 1 reviewer: analyst status: changes_requested comments: ["Нужна валидация", "Нет тестов"] - iteration: 2 reviewer: analyst status: approved ``` --- ## Workflow: от идеи до деплоя ### Фаза 1: Идея → Проект 1. Человек открывает Лобби 2. Обсуждает идею с агентом-аналитиком 3. Создаёт проект 4. Агент формирует BRIEF.md, REQUIREMENTS.md ### Фаза 2: Декомпозиция → Задачи 1. На основе требований создаются задачи (черновики в Backlog) 2. Расставляются зависимости 3. Прикрепляются файлы (макеты, схемы) 4. Обсуждение в чате проекта 5. Готовые задачи переносятся в TODO ### Фаза 3: Выполнение 1. Задача в TODO → агент берёт → In Progress 2. Агент работает, коммитит, прикрепляет файлы 3. Создаёт подзадачу "Ревью" → другому агенту 4. Итерации до готовности 5. Задача → Done ### Фаза 4: Ревью и деплой 1. Автоматические проверки (CI/CD) 2. Ревью агентом или человеком 3. Деплой --- ## Инфраструктура (уже есть) | Сервис | Описание | |--------|----------| | PostgreSQL | База данных | | Thoth | STT/TTS (голос↔текст) | | Authentik | SSO для веб-интерфейса | | Nginx + certbot | Домены и SSL | | Gitea | Git хостинг | | OpenClaw (Марков) | Главный агент с инструментами | | Redis | Очереди и pub/sub | --- ## База данных (ключевые таблицы) ```sql -- Агенты (независимые приложения) CREATE TABLE agents ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT NOT NULL, slug TEXT UNIQUE NOT NULL, token TEXT UNIQUE NOT NULL, -- токен для WebSocket auth capabilities TEXT[] NOT NULL DEFAULT '{}', -- ["coding", "analytics", ...] subscription_mode TEXT DEFAULT 'assigned', -- all, mentions, assigned max_concurrent INT DEFAULT 1, timeout_seconds INT DEFAULT 600, status TEXT DEFAULT 'offline', -- online, offline, busy last_heartbeat TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Задачи CREATE TABLE tasks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), project_id UUID REFERENCES projects(id), parent_id UUID REFERENCES tasks(id), -- подзадачи title TEXT NOT NULL, description TEXT, status TEXT DEFAULT 'draft', -- лейблы через связующую таблицу task_labels requires_pr BOOLEAN DEFAULT FALSE, assigned_agent_id UUID REFERENCES agents(id), priority TEXT DEFAULT 'medium', pr_url TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Зависимости задач CREATE TABLE task_dependencies ( task_id UUID REFERENCES tasks(id) ON DELETE CASCADE, depends_on_id UUID REFERENCES tasks(id) ON DELETE CASCADE, PRIMARY KEY (task_id, depends_on_id) ); -- Лейблы CREATE TABLE labels ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), name TEXT UNIQUE NOT NULL, color TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Связка задач и лейблов CREATE TABLE task_labels ( task_id UUID REFERENCES tasks(id) ON DELETE CASCADE, label_id UUID REFERENCES labels(id) ON DELETE CASCADE, PRIMARY KEY (task_id, label_id) ); -- Файлы задач CREATE TABLE task_files ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), task_id UUID REFERENCES tasks(id) ON DELETE CASCADE, filename TEXT NOT NULL, mime_type TEXT, file_path TEXT NOT NULL, uploaded_by UUID, -- agent_id или null (человек) created_at TIMESTAMPTZ DEFAULT NOW() ); ``` --- ## Управление агентами (Agent Manager) ### Принцип **Агент = независимое приложение.** Написано на чём угодно. Подключается к Tracker по WebSocket. Tracker не управляет запуском — агент сам стартует и подключается. ### AgentManager (в Tracker) Tracker отслеживает подключённых агентов: ```yaml Реестр агентов: - id: uuid name: "Кодер" status: online | offline | busy capabilities: ["coding", "backend"] last_heartbeat: timestamp current_tasks: [task_id] ``` Функции AgentManager: 1. **Регистрация** — агент подключился → auth → попал в реестр 2. **Мониторинг** — следит за heartbeat, помечает offline если пропал 3. **Назначение задач** — матчит задачу → подходящего агента по capabilities + загрузке 4. **Роутинг событий** — фильтрация по capabilities + подписке + чатам --- ## Открытые вопросы 1. Workspace для агентов — общий или изолированный? 2. Прогресс работы агента в реалтайме? 3. Биллинг/учёт использования API? --- ## Приоритеты реализации ### Сделано ✅ 1. [x] Tracker: REST API (проекты, задачи, агенты, лейблы) 2. [x] Tracker: базовый WebSocket (connection manager, heartbeat) 3. [x] Tracker: Docker Compose (postgres + redis + tracker) 4. [x] Web Client: канбан-доска с drag-and-drop 5. [x] Web Client: BFF с JWT авторизацией 6. [x] CI/CD: Gitea Actions auto-deploy ### В работе 🔧 7. [ ] Web Client: детальный вид задачи (описание, комменты, assignee) 8. [ ] Tracker: WebSocket протокол v2 (init handshake, роутинг событий) ### Следующее 📋 9. [ ] Tracker: чаты (лобби + проект + задача) 10. [ ] Tracker: файлы в задачах 11. [ ] Web Client: чат 12. [ ] Web Client: управление агентами 13. [ ] Первый агент (OpenClaw → Tracker) 14. [ ] Web Client: Authentik OAuth --- *Документ для обсуждения и аналитики. Обновляется по мере развития идей.*