Add CONCEPTS.md - единая точка правды по всем основным концепциям Team Board

Создан подробный документ на основе анализа всего кода и документации:
- Архитектура и компоненты
- Полные модели данных (Member, Project, Task, Step, Chat, Message, Attachment, AgentConfig)
- Авторизация (JWT, токены агентов, BFF auth, WS auth)
- WebSocket Protocol (типы сообщений, auth flow, heartbeat, фильтрация)
- REST API (все эндпоинты с методами и параметрами)
- Агенты (подключение, config, capabilities, listen modes)
- BFF (роль, проксирование REST и WS)
- Фронтенд (страницы, компоненты, WS/REST использование)
- Деплой (Docker, systemd, nginx, SSL)
- TODO секции для нереализованных частей

Документ основан на реальном коде, не на предположениях.
This commit is contained in:
Markov 2026-02-23 15:04:47 +01:00
parent bffb769002
commit 8b59ee3743

680
CONCEPTS.md Normal file
View File

@ -0,0 +1,680 @@
# Team Board — Концепции системы (Source of Truth)
**Версия:** 1.0
**Дата:** 2026-02-23
**Статус:** Единая точка правды по всем концепциям Team Board
---
## 1. Архитектура
### 1.1 Общая схема
```
┌─────────────┐ ┌──────────────┐ ┌──────────────┐
│ Web Client │────▶│ BFF │────▶│ Tracker │
│ (Next.js) │ │ (FastAPI) │ │ (FastAPI) │
└─────────────┘ └──────────────┘ └──────┬───────┘
┌────────────────────────────────────────┤
│ │ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐ ┌──▼───┐
│Picogent │ │Picogent │ │Telegram │ │ DB │
│ Кодер │ │Архитект │ │ Bridge │ │ Pg │
└─────────┘ └─────────┘ └─────────┘ └──────┘
```
### 1.2 Компоненты и порты
| Компонент | Технологии | Порт | Доступность | Описание |
|-----------|------------|------|-------------|----------|
| **Tracker** | Python, FastAPI, SQLAlchemy, PostgreSQL | 8100 | Внутренняя | Ядро системы. REST API + WebSocket |
| **BFF** | Python, FastAPI | 8200 | Внешняя | Прокси для Web Client с JWT auth |
| **Web Client** | Next.js 15, Tailwind CSS | 3100 | Внешняя | UI: канбан, чат, настройки |
| **PostgreSQL** | PostgreSQL 16 | 5433 | Внутренняя | База данных |
| **Redis** | Redis 7 | 6380 | Внутренняя | Кеш (пока не используется) |
| **Picogent** | Node.js, TypeScript | — | Внутренняя | AI-агент процесс |
### 1.3 Протоколы взаимодействия
- **Web Client ↔ BFF:** HTTPS REST API + WebSocket (JWT auth)
- **BFF ↔ Tracker:** HTTP REST API + WebSocket (Token auth)
- **Агенты ↔ Tracker:** HTTP REST API + WebSocket (Token auth)
- **База данных:** PostgreSQL connection pool через SQLAlchemy
---
## 2. Модели данных
### 2.1 Member (Участники)
**Ключевой принцип:** Агенты и люди — единая модель. Различие только в `type` и методе авторизации.
```python
Member:
id: UUID (PK)
name: str # Отображаемое имя
slug: str (UNIQUE) # Уникальный идентификатор (a-z, 0-9, -)
type: str # "human" | "agent"
role: str # "owner" | "member" | "observer" | "bridge"
auth_method: str # "password" | "oauth" | "token"
password_hash: str? # Для людей
token: str? (UNIQUE) # Для агентов/bridges
status: str # "online" | "offline" | "busy"
avatar_url: str?
created_at: timestamp
updated_at: timestamp
```
### 2.2 AgentConfig (Конфигурация агентов)
```python
AgentConfig:
id: UUID (PK)
member_id: UUID (FK → Member, UNIQUE)
capabilities: str[] # ["coding", "review", "testing"]
chat_listen: str # "all" | "mentions"
task_listen: str # "all" | "mentions"
prompt: str? # Системный промпт
model: str? # LLM модель
```
### 2.3 Project (Проекты)
```python
Project:
id: UUID (PK)
name: str # Отображаемое название
slug: str (UNIQUE) # Уникальный ID (для URLs)
description: str? # Описание (markdown)
repo_urls: str[] # Массив Git репозиториев
status: str # "active" | "archived"
task_counter: int # Счётчик для генерации номеров задач
created_at: timestamp
updated_at: timestamp
```
### 2.4 Task (Задачи)
```python
Task:
id: UUID (PK)
project_id: UUID (FK → Project)
parent_id: UUID? (FK → Task) # Подзадача
number: int # Порядковый номер в проекте (1, 2, 3...)
title: str # Название задачи
description: str? # Описание (markdown)
type: str # "task" | "bug" | "epic" | "story"
status: str # "backlog" | "todo" | "in_progress" | "in_review" | "done"
priority: str # "critical" | "high" | "medium" | "low"
labels: str[] # Массив лейблов ["backend", "urgent"]
assignee_slug: str? # Кому назначена (Member.slug)
reviewer_slug: str? # Кто ревьюит (Member.slug)
watchers: str[] # Наблюдатели (массив Member.slug)
depends_on: UUID[] # Зависимости от других задач
position: int # Позиция в колонке канбана
time_spent: int # Потраченное время (минуты)
created_at: timestamp
updated_at: timestamp
```
**Связи:**
- Task.project → Project (многие к одному)
- Task.parent → Task (самоссылка для подзадач)
- Task.subtasks ← Task (обратная связь)
### 2.5 Step (Шаги задачи)
```python
Step:
id: UUID (PK)
task_id: UUID (FK → Task)
title: str # Описание шага
done: bool # Выполнен ли
position: int # Порядок в списке
created_at: timestamp
updated_at: timestamp
```
### 2.6 Chat (Чаты)
```python
Chat:
id: UUID (PK)
project_id: UUID? (FK → Project) # NULL для lobby
kind: str # "lobby" | "project"
created_at: timestamp
updated_at: timestamp
```
**Типы чатов:**
- **Lobby** — глобальный чат (один на всю систему)
- **Project** — чат проекта (один на проект)
### 2.7 Message (Сообщения)
**Unified Message:** Одна модель для чат-сообщений И комментариев к задачам.
```python
Message:
id: UUID (PK)
chat_id: UUID? (FK → Chat) # Если сообщение в чате
task_id: UUID? (FK → Task) # Если комментарий к задаче
parent_id: UUID? (FK → Message) # Для threads в чатах
author_type: str # "human" | "agent" | "system"
author_slug: str # Member.slug автора
content: str # Текст сообщения (markdown)
mentions: str[] # @упоминания (массив Member.slug)
voice_url: str? # URL голосового сообщения
created_at: timestamp
updated_at: timestamp
```
**Ограничения:** Ровно одно из `chat_id` или `task_id` должно быть заполнено.
### 2.8 Attachment (Вложения)
```python
Attachment:
id: UUID (PK)
message_id: UUID (FK → Message)
filename: str # Оригинальное имя файла
mime_type: str? # MIME тип
size: int # Размер в байтах
storage_path: str # Путь к файлу на диске
created_at: timestamp
```
---
## 3. Авторизация
### 3.1 Типы авторизации
| Тип участника | Метод авторизации | Описание |
|---------------|-------------------|----------|
| **human (Web UI)** | JWT Token | Логин/пароль → JWT |
| **human (MCP Client)** | JWT Token | Логин/пароль → JWT (будущее) |
| **agent** | Bearer Token | Статический токен в agent.json |
| **bridge** | Bearer Token | Статический токен для мостов |
### 3.2 JWT Tokens (для людей)
- **Секрет:** `JWT_SECRET` (environment variable)
- **Алгоритм:** HS256
- **Payload:** `{"sub": member_id, "name": member_name, "exp": timestamp}`
- **Срок действия:** 30 дней (настраивается)
### 3.3 Agent Tokens
- **Формат:** `tb-` + random string (32 символа)
- **Хранение:** `Member.token` (уникальное поле)
- **Генерация:** При создании агента через UI
- **Отзыв:** Через API `POST /api/v1/members/{slug}/revoke-token`
### 3.4 Роли и права
| Роль | Описание | Права |
|------|----------|-------|
| `owner` | Владелец инстанса | Все права |
| `member` | Обычный участник | `send_messages`, `create_tasks`, `update_tasks` |
| `observer` | Наблюдатель | Только чтение |
| `bridge` | Мост в другую систему | `send_messages` |
### 3.5 Процесс авторизации
**Web Client:**
1. POST /api/auth/login → JWT token
2. Сохранение в localStorage
3. Authorization: Bearer {jwt} в запросах
4. WebSocket: ?token={jwt} в query
**Agent:**
1. Статический токен из конфига
2. WS: `{"type": "auth", "token": "tb-xxx"}`
3. REST: Authorization: Bearer {token} (TODO: не реализовано)
---
## 4. WebSocket Protocol
### 4.1 Подключение
**URL:** `ws://localhost:8100/ws` (прямое) или `wss://dev.team.uix.su/agent-ws` (через nginx)
### 4.2 Сообщения: Клиент → Сервер
| Тип | Формат | Описание |
|-----|--------|----------|
| `auth` | `{"type": "auth", "token": "..."}` | Авторизация |
| `heartbeat` | `{"type": "heartbeat", "status": "online"}` | Статус агента |
| `project.subscribe` | `{"type": "project.subscribe", "project_id": "uuid"}` | Подписка на проект |
| `project.unsubscribe` | `{"type": "project.unsubscribe", "project_id": "uuid"}` | Отписка |
| `chat.send` | `{"type": "chat.send", "chat_id": "uuid", "content": "text", "mentions": []}` | Сообщение в чат |
| `ack` | `{"type": "ack"}` | Подтверждение получения |
### 4.3 Сообщения: Сервер → Клиент
| Тип | Описание | Данные |
|-----|----------|--------|
| `auth.ok` | Успешная авторизация | `{slug, lobby_chat_id, projects[], online[]}` |
| `auth.error` | Ошибка авторизации | `{message}` |
| `message.new` | Новое сообщение | `{id, chat_id, task_id, author_*, content, mentions, created_at}` |
| `agent.status` | Изменение статуса агента | `{slug, status}` |
| `task.created` | Создана задача | `{...TaskData}` (TODO: не реализовано) |
| `task.updated` | Обновлена задача | `{...TaskData}` (TODO: не реализовано) |
| `task.assigned` | Задача назначена | `{...TaskData}` (TODO: не реализовано) |
### 4.4 Фильтрация событий
События фильтруются на сервере по настройкам агента:
**message.new:**
- `chat_listen: "all"` — все сообщения в подписанных проектах
- `chat_listen: "mentions"` — только сообщения с @упоминанием
**task.* (будущее):**
- `task_listen: "all"` — все события задач в подписанных проектах
- `task_listen: "mentions"` — только задачи где агент assignee/reviewer/watcher
### 4.5 Auth Flow
```
1. WebSocket Connect
2. Client → {"type": "auth", "token": "tb-xxx"}
3. Server validates token & creates session
4. Server → {"type": "auth.ok", "data": {...}}
5. Client → {"type": "project.subscribe", "project_id": "uuid"} (для каждого проекта)
6. Start heartbeat loop (каждые 30 секунд)
```
### 4.6 Heartbeat
- **Интервал:** Каждые 30 секунд
- **Timeout:** 90 секунд без heartbeat → `status=offline`
- **Формат:** `{"type": "heartbeat", "status": "online|busy|idle"}`
- **Реакция сервера:** Обновление `Member.status`, уведомление `agent.status`
---
## 5. REST API
**Base URL:** `http://localhost:8100/api/v1` (прямой) или `https://dev.team.uix.su/agent-api/api/v1` (через nginx)
### 5.1 Projects
| Метод | Путь | Описание | Параметры |
|-------|------|----------|-----------|
| GET | `/projects` | Список проектов | — |
| GET | `/projects/{slug}` | Проект по slug | — |
| POST | `/projects` | Создать проект | `{name, slug, description?, repo_urls?}` |
| PATCH | `/projects/{slug}` | Обновить проект | `{name?, description?, repo_urls?, status?}` |
| DELETE | `/projects/{slug}` | Удалить проект | — |
### 5.2 Tasks
| Метод | Путь | Описание | Параметры |
|-------|------|----------|-----------|
| GET | `/tasks` | Список задач | `?project_id=X&status=Y&assignee=Z&label=W` |
| GET | `/tasks/{id}` | Задача по ID | — |
| POST | `/tasks?project_slug=X` | Создать задачу | `{title, description?, type?, status?, priority?, labels?, parent_id?, assignee_slug?, depends_on?}` |
| PATCH | `/tasks/{id}` | Обновить задачу | `{title?, description?, type?, status?, priority?, labels?, assignee_slug?, reviewer_slug?, position?}` |
| DELETE | `/tasks/{id}` | Удалить задачу | — |
**Специальные операции с задачами:**
| Метод | Путь | Описание | Параметры |
|-------|------|----------|-----------|
| POST | `/tasks/{id}/take?slug=X` | Взять задачу (атомарно) | — |
| POST | `/tasks/{id}/reject` | Отклонить задачу | `{reason}` |
| POST | `/tasks/{id}/assign` | Назначить задачу | `{assignee_slug}` |
| POST | `/tasks/{id}/watch?slug=X` | Подписаться на задачу | — |
| DELETE | `/tasks/{id}/watch?slug=X` | Отписаться от задачи | — |
### 5.3 Steps
| Метод | Путь | Описание | Параметры |
|-------|------|----------|-----------|
| GET | `/tasks/{id}/steps` | Список шагов | — |
| POST | `/tasks/{id}/steps` | Создать шаг | `{title}` |
| PATCH | `/tasks/{tid}/steps/{sid}` | Обновить шаг | `{title?, done?}` |
| DELETE | `/tasks/{tid}/steps/{sid}` | Удалить шаг | — |
### 5.4 Messages (Unified)
| Метод | Путь | Описание | Параметры |
|-------|------|----------|-----------|
| GET | `/messages` | Список сообщений | `?chat_id=X&task_id=Y&limit=50&offset=0` |
| POST | `/messages` | Отправить сообщение | `{chat_id?, task_id?, content, author_type?, author_slug?, mentions?}` |
| GET | `/messages/{id}/replies` | Треды сообщения | — |
### 5.5 Members
| Метод | Путь | Описание | Параметры |
|-------|------|----------|-----------|
| GET | `/members` | Список участников | — |
| GET | `/members/{slug}` | Участник по slug | — |
| POST | `/members` | Создать участника | `{name, slug, type?, agent_config?}` |
| PATCH | `/members/{slug}` | Обновить участника | `{name?, role?, status?, agent_config?}` |
| POST | `/members/{slug}/regenerate-token` | Перегенерировать токен | — |
| POST | `/members/{slug}/revoke-token` | Отозвать токен | — |
### 5.6 Attachments (TODO)
| Метод | Путь | Описание | Статус |
|-------|------|----------|--------|
| POST | `/messages/{id}/attachments` | Загрузить файл | **TODO** |
| GET | `/attachments/{id}` | Скачать файл | **TODO** |
| GET | `/attachments?task_id=X` | Файлы задачи | **TODO** |
---
## 6. Агенты
### 6.1 Концепция
- **Один процесс = один агент** (picogent)
- **Одна сессия на агента** — видит всё: задачи, чат, ответы
- **Роль = конфигурация** в agent.json
### 6.2 Конфигурация агента (agent.json)
```json
{
"name": "Кодер",
"slug": "coder",
"prompt": "Ты опытный разработчик...",
"model": "sonnet",
"capabilities": ["coding", "review"],
"chat_listen": "mentions",
"task_listen": "mentions",
"tracker_url": "http://localhost:8100",
"token": "tb-agent-xxx"
}
```
### 6.3 Режимы прослушивания
**Chat Listen:**
- `all` — получает все сообщения в подписанных проектах
- `mentions` — только при @упоминании
**Task Listen:**
- `all` — получает все события задач в подписанных проектах
- `mentions` — только задачи где агент assignee/reviewer/watcher
### 6.4 Capabilities (способности)
Массив строк, описывающих что умеет агент:
- `"coding"` — написание кода
- `"review"` — ревью кода
- `"testing"` — тестирование
- `"documentation"` — документация
- `"architecture"` — архитектурные решения
### 6.5 Жизненный цикл агента
1. **Запуск:** Читает agent.json, подключается к Tracker
2. **Auth:** Отправляет токен, получает контекст
3. **Subscribe:** Подписывается на нужные проекты
4. **Listen:** Получает события по WebSocket
5. **Action:** Выполняет действия через REST API
6. **Heartbeat:** Каждые 30 секунд сообщает о статусе
7. **Disconnect:** При отключении статус → offline
### 6.6 Checkpoint Pattern
**Проблема:** LLM блокирующий — агент не может получать события во время обдумывания.
**Решение:**
- Короткие задачи (5-10 минут)
- Проверка входящих событий между шагами
- Уведомления о статусе `busy` во время работы
---
## 7. BFF (Backend for Frontend)
### 7.1 Роль BFF
- **Прокси** между Web Client и Tracker
- **Авторизация** пользователей (JWT)
- **WebSocket прокси** с токен-аутентификацией
- **Трансформация данных** (при необходимости)
### 7.2 Технологии
- Python, FastAPI
- JWT авторизация
- HTTP Client (httpx)
- WebSocket прокси
### 7.3 Конфигурация (environment)
```bash
# Tracker
TRACKER_URL=http://localhost:8100
TRACKER_WS_URL=ws://localhost:8100/ws
TRACKER_TOKEN=tb-admin-xxx
# Auth
JWT_SECRET=secret-key
AUTH_USER=admin
AUTH_PASS=password
# Server
BFF_HOST=0.0.0.0
BFF_PORT=8200
```
### 7.4 WebSocket прокси
1. **Client подключение:** `wss://dev.team.uix.su/ws?token={jwt}`
2. **Валидация JWT:** Проверка токена, извлечение user
3. **Tracker подключение:** `ws://localhost:8100/ws` с TRACKER_TOKEN
4. **Двусторонний relay:** Client ↔ BFF ↔ Tracker
### 7.5 REST прокси
Все API запросы проксируются с добавлением:
- **Авторизация:** Проверка JWT
- **Трансформация:** Добавление `author_slug` в сообщения
- **Логирование:** Запросы и ответы
- **CORS:** Для фронтенда
---
## 8. Фронтенд (Web Client)
### 8.1 Технологии
- **Framework:** Next.js 15 (App Router)
- **Styling:** Tailwind CSS
- **State:** React hooks (useState, useEffect)
- **HTTP:** fetch API
- **WebSocket:** Native WebSocket API
### 8.2 Структура страниц
- `/login` — Авторизация
- `/` — Список проектов
- `/projects/[slug]` — Канбан доска проекта
- `/projects/[slug]/settings` — Настройки проекта (TODO)
- `/agents` — Управление агентами (TODO)
### 8.3 Компоненты
| Компонент | Описание | Статус |
|-----------|----------|--------|
| `KanbanBoard` | Drag & drop доска + mobile tabs | ✅ Реализован |
| `TaskModal` | Модалка задачи (title, description, assignee, delete) | ✅ Базовая версия |
| `ChatPanel` | Чат (lobby) | ✅ Базовая версия |
| `CreateTaskModal` | Создание задачи | ✅ Реализован |
| `CreateProjectModal` | Создание проекта | ✅ Реализован |
| `AuthGuard` | Проверка авторизации | ✅ Реализован |
### 8.4 API клиент (api.ts)
- **Base URL:** `process.env.NEXT_PUBLIC_API_URL`
- **Авторизация:** JWT из localStorage
- **Обработка ошибок:** 401 → редирект на /login
- **TypeScript типы** для всех моделей
### 8.5 WebSocket клиент (ws.ts)
```typescript
class WSClient {
// Подключение через BFF с JWT токеном
connect() // ws://bff/ws?token=jwt
// Event handlers
on(type: string, handler: Function)
// Convenience methods
subscribeProject(projectId: string)
sendChat(chatId: string, content: string)
sendTaskComment(taskId: string, content: string)
heartbeat(status: string)
}
```
### 8.6 Состояние приложения
- **Авторизация:** JWT в localStorage
- **Проекты:** Загружаются при входе в систему
- **Задачи:** Загружаются для каждого проекта
- **WebSocket:** Глобальный клиент, подписка по проектам
- **Real-time:** Обновления через WebSocket события
---
## 9. Деплой
### 9.1 Docker Compose (разработка)
```yaml
services:
tracker:
build: ./tracker
ports: ["8100:8100"]
depends_on: [postgres, redis]
postgres:
image: postgres:16-alpine
ports: ["5433:5432"]
redis:
image: redis:7-alpine
ports: ["6380:6379"]
```
### 9.2 Systemd сервисы (продакшен)
**Tracker:** Docker Compose + systemd unit
**BFF + Web Client:** systemd сервисы на хосте
**Picogent:** systemd unit на агента
### 9.3 Nginx конфигурация
```nginx
# Web Client
location / {
proxy_pass http://localhost:3100;
}
# BFF API
location /api/ {
proxy_pass http://localhost:8200/api/;
}
# BFF WebSocket
location /ws {
proxy_pass http://localhost:8200/ws;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Agent API (через nginx → Tracker)
location /agent-api/ {
proxy_pass http://localhost:8100/api/;
}
# Agent WebSocket
location /agent-ws {
proxy_pass http://localhost:8100/ws;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
```
### 9.4 SSL/HTTPS
- **Dev:** `dev.team.uix.su` (действующий)
- **Prod:** `team.uix.su` (placeholder)
- **Cертификаты:** Let's Encrypt через certbot
### 9.5 База данных
- **Разработка:** PostgreSQL в Docker
- **Продакшен:** PostgreSQL на хосте
- **Миграции:** Нет (recreate from scratch)
- **Бэкапы:** pg_dump (TODO)
### 9.6 Процесс деплоя
1. **Git push** → git.uix.su/team-board/docs
2. **Manual deploy** на сервере
3. **Restart services:** systemctl restart team-board-*
4. **Health check:** /health endpoints
**CI/CD:** Пока ручной деплой. В будущем — Gitea Actions.
---
## 10. Нереализованные части (TODO)
### 10.1 Backend TODO
- ❌ **Attachments API** — загрузка/скачивание файлов
- ❌ **Task events** через WebSocket — task.created/updated/assigned
- ❌ **Agent token auth** для REST API (только WS)
- ❌ **Chat threads** — parent_id поддержка в UI
- ❌ **Task dependencies** — визуализация и валидация
- ❌ **БД миграции** — пока только recreate
### 10.2 Frontend TODO
- ❌ **Task comments** в TaskModal
- ❌ **Task steps** (live progress) в TaskModal
- ❌ **Task watchers** — подписка/отписка
- ❌ **Agent management** — страница /agents
- ❌ **Project dashboard** — метрики и активность
- ❌ **Mobile UI** — адаптация под телефоны
### 10.3 Agent TODO
- ❌ **MCP Tools** — полный набор инструментов для picogent
- ❌ **Session resume** — восстановление контекста при переподключении
- ❌ **Multi-instance** — несколько экземпляров одного агента
- ❌ **Agent home** — workspace, memory, sessions
### 10.4 Infrastructure TODO
- ❌ **Telegram Bridge** — дублирование чата в Telegram
- ❌ **OAuth/Authentik** — мультипользовательский режим
- ❌ **Redis integration** — event bus и кеширование
- ❌ **CI/CD pipeline** — автоматический деплой
- ❌ **Monitoring** — метрики и логи
- ❌ **Backup strategy** — регулярные бэкапы БД
---
## Заключение
Этот документ является единой точкой правды для всех концепций Team Board. Он основан на реальном коде и документации по состоянию на 2026-02-23.
**Версионирование:** При значимых изменениях в архитектуре или API обновляется версия документа и дата.
**Обратная связь:** Если код не соответствует документу — приоритет у кода (он правдивее), документ нужно обновить.