docs/specs/MODELS.md
2026-03-13 22:56:04 +01:00

543 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Team Board — Модели данных
## Базовая модель (Base)
**Таблица:** все таблицы наследуются от Base
**Файл:** `base.py`
### Общие поля:
```python
id: UUID # Primary key, автогенерируемый UUID4
created_at: TIMESTAMP WITH TIMEZONE # Автоматически при создании
updated_at: TIMESTAMP WITH TIMEZONE # Автоматически при обновлении
```
---
## Members — Участники системы
**Таблица:** `members`
**Файл:** `member.py`
### Поля:
```python
id: UUID # Primary key
name: str # Отображаемое имя
slug: str # Уникальный идентификатор (URL-safe)
type: str # human | agent | bridge
role: str # owner | member | observer | bridge
auth_method: str # password | oauth | token
password_hash: str? # Bcrypt hash (только для type=human)
token: str? # Bearer токен (только для type=agent/bridge)
status: str # online | offline | busy
avatar_url: str? # Ссылка на аватар
is_active: bool # Флаг активности (soft delete)
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `agent_config`**AgentConfig** (1:1, optional)
- `project_memberships`**ProjectMember[]** (1:many)
### Индексы:
- `UNIQUE (slug)`
- `UNIQUE (token)` где `token IS NOT NULL`
---
## AgentConfig — Конфигурация агентов
**Таблица:** `agent_configs`
**Файл:** `member.py`
### Поля:
```python
id: UUID # Primary key
member_id: UUID # FK → members.id (UNIQUE)
capabilities: str[] # Массив возможностей агента
labels: str[] # Лейблы для auto-assign (соответствие с задачами)
chat_listen: str # all | mentions | none
task_listen: str # all | mentions | none
prompt: text? # Системный промпт
model: str? # Модель ИИ (gpt-4, claude-3, etc)
provider: str? # Провайдер (openai, anthropic, etc)
max_concurrent_tasks: int # Лимит одновременных задач (по умолчанию 2)
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `member`**Member** (1:1)
---
## Projects — Проекты
**Таблица:** `projects`
**Файл:** `project.py`
### Поля:
```python
id: UUID # Primary key
name: str # Название проекта
slug: str # Уникальный идентификатор (для URL и префиксов задач)
description: text? # Описание проекта
repo_urls: str[] # Массив ссылок на репозитории
status: str # active | archived | paused
task_counter: int # Счётчик задач для генерации номеров (инкрементальный)
auto_assign: bool # Включена ли автоназначение задач по лейблам
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `tasks`**Task[]** (1:many, CASCADE DELETE)
- `chats`**Chat[]** (1:many, CASCADE DELETE)
- `members`**ProjectMember[]** (1:many, CASCADE DELETE)
### Индексы:
- `UNIQUE (slug)`
---
## ProjectMember — Участники проектов
**Таблица:** `project_members`
**Файл:** `project.py`
### Поля:
```python
id: UUID # Primary key
project_id: UUID # FK → projects.id (CASCADE DELETE)
member_id: UUID # FK → members.id (CASCADE DELETE)
role: str # owner | member
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `project`**Project** (many:1)
- `member`**Member** (many:1)
### Ограничения:
- `UNIQUE (project_id, member_id)` — один участник не может быть дважды в проекте
---
## Tasks — Задачи
**Таблица:** `tasks`
**Файл:** `task.py`
### Поля:
```python
id: UUID # Primary key
project_id: UUID # FK → projects.id
parent_id: UUID? # FK → tasks.id (для иерархии: эпик → история → задача)
number: int # Номер в рамках проекта (XX-1, XX-2, XX-3)
title: str # Заголовок задачи
description: text? # Детальное описание
type: str # task | bug | feature
status: str # backlog | todo | in_progress | in_review | done
priority: str # critical | high | medium | low
labels: str[] # Массив лейблов (для фильтрации и auto-assign)
assignee_id: UUID? # FK → members.id (исполнитель)
reviewer_id: UUID? # FK → members.id (ревьюер)
watcher_ids: UUID[] # Массив ID участников, подписанных на уведомления
depends_on: UUID[] # Массив ID задач-зависимостей
position: int # Позиция в колонке канбана
time_spent: int # Потраченное время в минутах
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `project`**Project** (many:1)
- `assignee`**Member** (many:1, optional)
- `reviewer`**Member** (many:1, optional)
- `parent`**Task** (many:1, self-reference)
- `subtasks`**Task[]** (1:many, self-reference)
- `steps`**Step[]** (1:many, CASCADE DELETE, ordered by position)
---
## Steps — Этапы задач (чеклист)
**Таблица:** `steps`
**Файл:** `task.py`
### Поля:
```python
id: UUID # Primary key
task_id: UUID # FK → tasks.id (CASCADE DELETE)
title: str # Название этапа
done: bool # Выполнен ли (по умолчанию false)
position: int # Порядок в списке
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `task`**Task** (many:1)
---
## Labels — Глобальные лейблы
**Таблица:** `labels`
**Файл:** `task.py`
### Поля:
```python
id: UUID # Primary key
name: str # Название лейбла
color: str # HEX цвет (по умолчанию "#6366f1")
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Индексы:
- `UNIQUE (name)`
---
## TaskLabel — Связи задач и лейблов
**Таблица:** `task_labels`
**Файл:** `task.py`
### Поля:
```python
id: UUID # Primary key
task_id: UUID # FK → tasks.id (CASCADE DELETE)
label_id: UUID # FK → labels.id (CASCADE DELETE)
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- Связывает **Task** и **Label** (many:many)
---
## TaskLink — Зависимости между задачами
**Таблица:** `task_links`
**Файл:** `task.py`
### Поля:
```python
id: UUID # Primary key
source_id: UUID # FK → tasks.id (CASCADE DELETE) - исходная задача
target_id: UUID # FK → tasks.id (CASCADE DELETE) - целевая задача
link_type: str # blocks | depends_on | relates_to
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `source`**Task** (many:1)
- `target`**Task** (many:1)
### Типы связей:
- `blocks` — source блокирует target (target заблокирована source)
- `depends_on` — source зависит от target (source заблокирована target)
- `relates_to` — информационная связь (двусторонняя)
---
## TaskAction — Аудит действий с задачами
**Таблица:** `task_actions`
**Файл:** `task.py`
### Поля:
```python
id: UUID # Primary key
task_id: UUID # FK → tasks.id (CASCADE DELETE)
actor_id: UUID # FK → members.id (кто совершил действие)
action: str # created | status_changed | assigned | etc.
field: str? # Какое поле изменилось
old_value: text? # Старое значение
new_value: text? # Новое значение
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `task`**Task** (many:1)
- `actor`**Member** (many:1)
---
## Chats — Чаты
**Таблица:** `chats`
**Файл:** `chat.py`
### Поля:
```python
id: UUID # Primary key
project_id: UUID? # FK → projects.id (null для lobby чата)
kind: str # lobby | project
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `project`**Project** (many:1, optional)
- `messages`**Message[]** (1:many, CASCADE DELETE)
---
## Messages — Сообщения
**Таблица:** `messages`
**Файл:** `chat.py`
**Универсальная модель:** работает и для чатов, и для комментариев к задачам.
### Поля:
```python
id: UUID # Primary key
chat_id: UUID? # FK → chats.id (для сообщений в чате)
task_id: UUID? # FK → tasks.id (для комментариев к задаче, CASCADE DELETE)
parent_id: UUID? # FK → messages.id (для тредов - ответов на сообщения)
author_type: str # human | agent | system
author_id: UUID? # FK → members.id (автор сообщения)
actor_id: UUID? # FK → members.id (инициатор действия для системных сообщений)
tool_log: JSON? # JSON массив вызовов инструментов [{name, args, result, error}]
content: text # Текст сообщения
thinking: text? # Внутренние размышления ИИ (для агентов)
mentions: str[] # Массив ID упомянутых участников
voice_url: str? # Ссылка на голосовое сообщение
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `chat`**Chat** (many:1, optional)
- `author`**Member** (many:1, optional)
- `actor`**Member** (many:1, optional)
- `attachments`**Attachment[]** (1:many, CASCADE DELETE)
- `replies`**Message[]** (1:many, self-reference для тредов)
- `parent`**Message** (many:1, self-reference)
### Ограничения:
- Должно быть заполнено либо `chat_id`, либо `task_id` (не оба)
---
## Attachments — Файловые вложения
**Таблица:** `attachments`
**Файл:** `chat.py`
### Поля:
```python
id: UUID # Primary key
message_id: UUID # FK → messages.id
filename: str # Исходное имя файла
mime_type: str? # MIME тип файла
size: int # Размер в байтах (по умолчанию 0)
storage_path: str # Путь к файлу в файловой системе
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `message`**Message** (many:1)
### Хранение:
- Файлы сохраняются в `/data/uploads/`
- `storage_path` содержит имя файла на диске (UUID + расширение)
---
## ProjectFile — Файлы проектов
**Таблица:** `project_files`
**Файл:** `project_file.py`
### Поля:
```python
id: UUID # Primary key
project_id: UUID # FK → projects.id (CASCADE DELETE)
filename: str # Имя файла
description: text? # Описание файла
mime_type: str? # MIME тип файла
size: int # Размер в байтах
uploaded_by: UUID # FK → members.id (кто загрузил, CASCADE DELETE)
storage_path: str # Относительный путь внутри папки проекта
created_at: TIMESTAMP
updated_at: TIMESTAMP
```
### Связи:
- `project`**Project** (many:1)
- `uploader`**Member** (many:1)
### Хранение:
- Файлы сохраняются в `/data/projects/{project_slug}/`
- `storage_path` содержит относительный путь (обычно совпадает с `filename`)
---
## Enums — Перечисления
**Файл:** `enums.py`
### MemberType
```python
HUMAN = "human" # Обычный пользователь
AGENT = "agent" # ИИ агент
BRIDGE = "bridge" # Мост (например, Telegram)
```
### MemberRole
```python
OWNER = "owner" # Владелец (все права)
MEMBER = "member" # Обычный участник
BRIDGE = "bridge" # Мост (ограниченные права)
```
### MemberStatus
```python
ONLINE = "online" # В сети
OFFLINE = "offline" # Не в сети
```
### AuthMethod
```python
PASSWORD = "password" # Аутентификация по паролю
TOKEN = "token" # Аутентификация по Bearer токену
```
### ChatKind
```python
LOBBY = "lobby" # Общий чат
PROJECT = "project" # Чат проекта
```
### ListenMode
```python
ALL = "all" # Получать все уведомления
MENTIONS = "mentions" # Только при упоминаниях
ASSIGNED = "assigned" # Назначенные задачи + упоминания
NONE = "none" # Не получать уведомления
```
### ProjectStatus
```python
ACTIVE = "active" # Активный проект
ARCHIVED = "archived" # Архивный проект
PAUSED = "paused" # Приостановленный проект
```
### TaskStatus
```python
BACKLOG = "backlog" # В беклоге
TODO = "todo" # Готово к работе
IN_PROGRESS = "in_progress" # В работе
IN_REVIEW = "in_review" # На ревью
DONE = "done" # Завершено
```
### TaskType
```python
TASK = "task" # Обычная задача
BUG = "bug" # Баг
FEATURE = "feature" # Новая функциональность
```
### TaskPriority
```python
LOW = "low" # Низкий приоритет
MEDIUM = "medium" # Средний приоритет
HIGH = "high" # Высокий приоритет
CRITICAL = "critical" # Критический приоритет
```
### AuthorType
```python
HUMAN = "human" # Сообщение от человека
AGENT = "agent" # Сообщение от агента
SYSTEM = "system" # Системное сообщение
```
### TaskActionType
```python
CREATED = "created"
STATUS_CHANGED = "status_changed"
ASSIGNED = "assigned"
UNASSIGNED = "unassigned"
PRIORITY_CHANGED = "priority_changed"
TITLE_CHANGED = "title_changed"
DESCRIPTION_CHANGED = "description_changed"
REVIEWER_CHANGED = "reviewer_changed"
WATCHER_ADDED = "watcher_added"
WATCHER_REMOVED = "watcher_removed"
DELETED = "deleted"
```
### TaskLinkType
```python
BLOCKS = "blocks" # source блокирует target
DEPENDS_ON = "depends_on" # source зависит от target
RELATES_TO = "relates_to" # информационная связь
```
### WSEventType
```python
# Auth события
AUTH = "auth"
AUTH_OK = "auth.ok"
AUTH_ERROR = "auth.error"
# Системные
HEARTBEAT = "heartbeat"
ACK = "ack"
ERROR = "error"
# Чат и подписки
CHAT_SEND = "chat.send"
PROJECT_SUBSCRIBE = "project.subscribe"
PROJECT_UNSUBSCRIBE = "project.unsubscribe"
MESSAGE_NEW = "message.new"
# Задачи
TASK_CREATED = "task.created"
TASK_UPDATED = "task.updated"
TASK_ASSIGNED = "task.assigned"
TASK_DELETED = "task.deleted"
# Агенты
AGENT_STATUS = "agent.status"
AGENT_STREAM_START = "agent.stream.start"
AGENT_STREAM_DELTA = "agent.stream.delta"
AGENT_STREAM_TOOL = "agent.stream.tool"
AGENT_STREAM_END = "agent.stream.end"
CONFIG_UPDATED = "config.updated"
```
---
## Схема связей
```
Member 1:1 AgentConfig
Member 1:N ProjectMember N:1 Project
Project 1:N Task
Task 1:N Step
Task N:M Label (через TaskLabel)
Task 1:N TaskLink N:1 Task
Task 1:N TaskAction N:1 Member
Project 1:N Chat
Chat 1:N Message
Message 1:N Attachment
Message 1:N Message (parent/replies)
Project 1:N ProjectFile N:1 Member
```
Этот документ описывает структуру базы данных на основе моделей SQLAlchemy в `/root/projects/team-board/tracker/src/tracker/models/` на дату создания спецификации.