diff --git a/PLANNING.md b/PLANNING.md new file mode 100644 index 0000000..752ef0a --- /dev/null +++ b/PLANNING.md @@ -0,0 +1,360 @@ +# 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 \ No newline at end of file