# Planning — Team Board Дата: 2026-02-23 ## Принципы - Каждый эпик = самодостаточный блок, можно релизить независимо - Порядок = зависимости + приоритет из Architecture Review - Никаких параллельных эпиков — строго последовательно - Каждая story имеет чёткие критерии приёмки ## Эпик 1: WebSocket Foundation — Исправить критические баги Цель: Устранить P0 блокеры из Architecture Review — WS collision и отсутствие task events Зависимости: нет ### Story 1.1: Исправить WebSocket connection collision **Как** системный разработчик **я хочу** чтобы множественные подключения одного пользователя не вытесняли друг друга **чтобы** система работала корректно при multiple tabs/reconnect **Критерии приёмки:** - [ ] `ConnectionManager.clients` изменён с `dict[str, ConnectedClient]` на `dict[str, list[ConnectedClient]]` - [ ] Добавлен `sessions: dict[str, ConnectedClient]` с уникальными session_id - [ ] При подключении создаётся уникальный session_id - [ ] При отключении удаляется только конкретная сессия - [ ] Broadcast отправляется всем сессиям пользователя **Компоненты:** Tracker **Оценка:** M ### Story 1.2: Добавить broadcast task events **Как** агент **я хочу** получать уведомления о создании/изменении задач **чтобы** реагировать на новую работу в проекте **Критерии приёмки:** - [ ] `POST /api/v1/tasks` вызывает `broadcast_task_event("task.created")` - [ ] `PATCH /api/v1/tasks/{id}` вызывает `broadcast_task_event("task.updated")` - [ ] `DELETE /api/v1/tasks/{id}` вызывает `broadcast_task_event("task.deleted")` - [ ] События содержат полную информацию о задаче - [ ] WebSocket клиент получает события в формате `{"type": "task.created", "data": task}` **Компоненты:** Tracker **Оценка:** M ### Story 1.3: Добавить REST token auth для агентов **Как** агент **я хочу** аутентифицироваться через токен в REST API **чтобы** делать запросы напрямую к Tracker **Критерии приёмки:** - [ ] Middleware `verify_agent_token()` проверяет заголовок `Authorization: Bearer tb-xxxxx` - [ ] Токен валидируется по таблице Member.token - [ ] Защищены все эндпоинты кроме `/docs`, `/health`, `/ws` - [ ] При неверном токене возвращается 401 - [ ] BFF продолжает работать (проксирует с токеном) **Компоненты:** Tracker **Оценка:** S ## Эпик 2: Task Operations — Агентские операции с задачами Цель: Реализовать специальные операции для агентов из PRD Зависимости: Эпик 1 ### Story 2.1: Реализовать take task API **Как** агент **я хочу** атомарно взять задачу в работу **чтобы** не было race condition с другими агентами **Критерии приёмки:** - [ ] `POST /api/v1/tasks/{id}/take` endpoint создан - [ ] Проверяется что задача в статусе backlog или todo - [ ] Атомарно устанавливается assignee_slug = текущий агент и status = in_progress - [ ] При конфликте возвращается 409 Conflict - [ ] Broadcast task.updated события после успешного взятия - [ ] BFF проксирует операцию **Компоненты:** Tracker / BFF **Оценка:** M ### Story 2.2: Реализовать reject task API **Как** агент **я хочу** отклонить назначенную мне задачу **чтобы** вернуть её в backlog с объяснением **Критерии приёмки:** - [ ] `POST /api/v1/tasks/{id}/reject` с body `{"reason": "string"}` - [ ] Проверяется что assignee_slug = текущий агент - [ ] Устанавливается assignee_slug = null, status = backlog - [ ] Добавляется комментарий-сообщение "Задача отклонена: {reason}" - [ ] Broadcast task.updated события - [ ] BFF проксирует операцию **Компоненты:** Tracker / BFF **Оценка:** M ### Story 2.3: Реализовать assign task API **Как** участник **я хочу** назначить задачу другому участнику **чтобы** делегировать работу **Критерии приёмки:** - [ ] `POST /api/v1/tasks/{id}/assign` с body `{"assignee_slug": "string"}` - [ ] Проверяется существование assignee в проекте - [ ] Устанавливается assignee_slug и status = todo (если был backlog) - [ ] Broadcast task.updated события - [ ] BFF проксирует операцию **Компоненты:** Tracker / BFF **Оценка:** S ### Story 2.4: Реализовать watch/unwatch task API **Как** участник **я хочу** подписываться на уведомления по задаче **чтобы** отслеживать её прогресс **Критерии приёмки:** - [ ] `POST /api/v1/tasks/{id}/watch` добавляет текущий slug в watchers[] - [ ] `DELETE /api/v1/tasks/{id}/watch` удаляет slug из watchers[] - [ ] Дубликаты в watchers игнорируются - [ ] Broadcast task.updated события при изменении watchers - [ ] BFF проксирует операции **Компоненты:** Tracker / BFF **Оценка:** S ## Эпик 3: WebSocket Events — Правильная фильтрация событий Цель: Унифицировать фильтрацию событий для всех типов участников Зависимости: Эпик 2 ### Story 3.1: Реализовать project.subscribe для humans **Как** пользователь веб-клиента **я хочу** подписываться только на события нужных проектов **чтобы** не получать лишний трафик **Критерии приёмки:** - [ ] Humans/bridges могут отправлять `project.subscribe` сообщения - [ ] `connection.subscribed_projects` хранит список подписок - [ ] По умолчанию подписок нет (не "получать всё") - [ ] События фильтруются по подпискам для всех типов участников - [ ] Web Client автоматически подписывается на текущий проект **Компоненты:** Tracker / Web **Оценка:** M ### Story 3.2: Унифицировать фильтрацию по listen_mode **Как** агент с chat_listen="mentions" **я хочу** получать только сообщения где меня упоминают **чтобы** снизить шум в канале **Критерии приёмки:** - [ ] Функция `should_receive_event(client, event_type, data)` для всех типов - [ ] chat_listen="mentions" → только сообщения с mentions[] содержащими агента - [ ] chat_listen="all" → все сообщения в подписанных проектах - [ ] task_listen="mentions" → только задачи где агент assignee/reviewer/watcher - [ ] task_listen="all" → все task события в подписанных проектах - [ ] Humans используют ту же логику с listen_mode="all" по умолчанию **Компоненты:** Tracker **Оценка:** M ### Story 3.3: Исправить on_behalf_of validation **Как** BFF **я хочу** валидировать on_behalf_of пользователей **чтобы** предотвратить коллизии slug **Критерии приёмки:** - [ ] При on_behalf_of проверяется существование Member с таким slug - [ ] Несуществующие users получают префикс `web-{slug}` - [ ] Все proxy подключения логируются с уровнем INFO - [ ] Bridge не может перехватить slug существующего агента - [ ] Добавлены unit тесты для collision cases **Компоненты:** BFF **Оценка:** S ## Эпик 4: Agent Management — UI для управления агентами Цель: Создать интерфейс для создания и мониторинга агентов Зависимости: Эпик 3 ### Story 4.1: Страница Agent Management **Как** администратор **я хочу** видеть список всех агентов с их статусами **чтобы** мониторить работу системы **Критерии приёмки:** - [ ] Страница `/agents` доступна в навигации - [ ] Таблица агентов с колонками: name, slug, status, capabilities, last_seen_at - [ ] Статусы показаны цветами: 🟢 online, 🔴 offline, 🟡 busy - [ ] Обновление статусов через WebSocket в реальном времени - [ ] Кнопка "Create Agent" ведёт на форму создания **Компоненты:** Web **Оценка:** M ### Story 4.2: Форма создания агента **Как** администратор **я хочу** создать нового агента и получить его токен **чтобы** подключить к системе **Критерии приёмки:** - [ ] Форма с полями: name, slug, capabilities (чекбоксы), chat_listen, task_listen, model - [ ] Slug валидируется на уникальность - [ ] При создании генерируется токен формата `tb-{32 random chars}` - [ ] Токен показывается один раз с предупреждением "Сохраните токен" - [ ] После создания редирект на `/agents` со списком - [ ] Токен копируется в clipboard кнопкой **Компоненты:** Web / BFF / Tracker **Оценка:** M ### Story 4.3: Agent configuration UI **Как** администратор **я хочу** редактировать настройки агента **чтобы** корректировать его поведение **Критерии приёмки:** - [ ] В таблице агентов кнопка "Edit" открывает модальное окно - [ ] Поля: name, capabilities, chat_listen, task_listen, model, prompt - [ ] Slug не редактируется (readonly) - [ ] Кнопка "Regenerate Token" с подтверждением - [ ] Изменения сохраняются через PATCH API - [ ] Обновление конфигурации применяется без перезапуска агента **Компоненты:** Web / BFF / Tracker **Оценка:** M ## Эпик 5: Task Steps UI — Интеграция steps в интерфейс Цель: Показывать прогресс задач через steps UI Зависимости: Эпик 4 ### Story 5.1: Steps в TaskModal **Как** пользователь **я хочу** видеть этапы задачи в виде чеклиста **чтобы** отслеживать прогресс выполнения **Критерии приёмки:** - [ ] Секция Steps между описанием и комментариями в TaskModal - [ ] Список шагов с чекбоксами и заголовками - [ ] Прогресс-бар "3 из 7 выполнено" вверху секции - [ ] Чекбоксы интерактивны — клик отмечает/снимает выполнение - [ ] Обновления сохраняются через PATCH API - [ ] Live обновления через WebSocket **Компоненты:** Web **Оценка:** M ### Story 5.2: Управление steps в TaskModal **Как** исполнитель задачи **я хочу** добавлять и удалять этапы **чтобы** планировать свою работу **Критерии приёмки:** - [ ] Кнопка "+ Add Step" в секции Steps - [ ] Инлайн добавление шага с автосохранением - [ ] Кнопка удаления у каждого шага (только для незавершённых) - [ ] Drag & drop для изменения порядка шагов - [ ] Завершённые шаги визуально отличаются (зачёркнутый текст) **Компоненты:** Web **Оценка:** S ## Эпик 6: Files & Attachments — Загрузка файлов Цель: Реализовать upload/download файлов в сообщениях Зависимости: Эпик 5 ### Story 6.1: Upload API для attachments **Как** пользователь **я хочу** прикреплять файлы к сообщениям **чтобы** делиться документами с командой **Критерии приёмки:** - [ ] `POST /api/v1/messages/{id}/attachments` принимает multipart/form-data - [ ] Файлы сохраняются в `/var/lib/team-board/attachments/{message_id}/` - [ ] Создаётся Attachment запись в БД с metadata - [ ] Поддерживаются файлы до 10MB - [ ] Валидация MIME типов (изображения, документы, код) - [ ] BFF проксирует загрузку с авторизацией **Компоненты:** Tracker / BFF **Оценка:** M ### Story 6.2: Download API для attachments **Как** пользователь **я хочу** скачивать прикреплённые файлы **чтобы** просматривать их локально **Критерии приёмки:** - [ ] `GET /api/v1/attachments/{id}` отдаёт файл с правильными заголовками - [ ] Content-Type, Content-Length, Content-Disposition установлены - [ ] Проверка доступа — пользователь должен иметь доступ к сообщению - [ ] Обслуживание статичных файлов через FastAPI - [ ] BFF проксирует скачивание с авторизацией **Компоненты:** Tracker / BFF **Оценка:** S ### Story 6.3: File preview в UI **Как** пользователь **я хочу** видеть превью файлов в чате **чтобы** не скачивать их для просмотра **Критерии приёмки:** - [ ] Изображения показываются как thumbnail в сообщении - [ ] Клик на thumbnail открывает полноразмерное изображение - [ ] Документы показываются как ссылки с иконками типов файлов - [ ] Код файлы (.js, .py, .md) показываются с syntax highlighting - [ ] Кнопка скачивания у каждого attachment **Компоненты:** Web **Оценка:** M ## Эпик 7: MCP Tools — Инструменты для агентов Цель: Создать MCP Tools для взаимодействия агентов с системой Зависимости: Эпик 6 ### Story 7.1: Базовые Task Tools **Как** агент **я хочу** создавать и управлять задачами через MCP **чтобы** автоматизировать workflow **Критерии приёмки:** - [ ] `create_task(title, description, project_slug, priority?, labels?)` → task_id - [ ] `take_task(task_id)` → success/error - [ ] `update_task(task_id, fields)` → updated task - [ ] `complete_task(task_id)` → устанавливает status=done - [ ] `list_tasks(project_slug?, status?, assignee?)` → task list - [ ] Все tools используют существующий REST API с токен авторизацией **Компоненты:** Picogent **Оценка:** M ### Story 7.2: Communication Tools **Как** агент **я хочу** отправлять сообщения и читать чат **чтобы** участвовать в обсуждениях **Критерии приёмки:** - [ ] `send_message(content, chat_id?, task_id?, mentions?)` → message_id - [ ] `list_messages(chat_id?, task_id?, limit?)` → message list - [ ] `add_task_comment(task_id, content)` → comment message - [ ] `mention_user(slug, message)` → автодобавление в mentions[] - [ ] Все сообщения получают правильный author_slug агента **Компоненты:** Picogent **Оценка:** S ### Story 7.3: Project & Member Tools **Как** агент **я хочу** получать информацию о проектах и участниках **чтобы** понимать контекст работы **Критерии приёмки:** - [ ] `list_projects()` → project list с основными полями - [ ] `get_project(slug)` → детальная информация о проекте - [ ] `list_members(project_slug?)` → список участников - [ ] `get_member(slug)` → информация об участнике - [ ] `watch_task(task_id)` / `unwatch_task(task_id)` → управление подписками **Компоненты:** Picogent **Оценка:** S ## Эпик 8: Advanced Features — Дополнительные возможности Цель: Реализовать отложенные features для полноценной работы Зависимости: Эпик 7 ### Story 8.1: Telegram Bridge Foundation **Как** пользователь **я хочу** получать уведомления в Telegram **чтобы** не пропускать важные события проекта **Критерии приёмки:** - [ ] Bridge агент подключается как member типа "bridge" - [ ] Принимает все события проектов (listen_mode="all") - [ ] Фильтрует важные события: task.assigned на меня, mentions в чате - [ ] Отправляет уведомления в личный чат Telegram - [ ] Конфигурация через переменные окружения **Компоненты:** Picogent (отдельный bridge agent) **Оценка:** L ### Story 8.2: Voice Messages Support **Как** пользователь **я хочу** отправлять голосовые сообщения **чтобы** быстро комментировать задачи **Критерии приёмки:** - [ ] Web Client записывает аудио через MediaRecorder API - [ ] Upload аудио как attachment с типом audio/* - [ ] Message.voice_url ссылается на attachment - [ ] Аудио плеер в UI для воспроизведения - [ ] Агенты могут транскрибировать voice_url через STT **Компоненты:** Web / Tracker / Picogent **Оценка:** L ### Story 8.3: Advanced Task Dependencies **Как** PM **я хочу** видеть граф зависимостей задач **чтобы** планировать последовательность работ **Критерии приёмки:** - [ ] UI для добавления зависимостей в TaskModal (autocomplete других задач) - [ ] Валидация циклических зависимостей на бэкенде - [ ] Визуализация зависимостей в виде граф-диаграммы - [ ] Блокировка взятия задач с незавершёнными зависимостями - [ ] Автоматическое уведомление при разблокировке задачи **Компоненты:** Web / Tracker **Оценка:** L