543 lines
17 KiB
Markdown
543 lines
17 KiB
Markdown
# 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/` на дату создания спецификации. |