22 KiB
Team Board — REST API спецификация
Общие сведения
Базовый URL: /api/v1/
Аутентификация: Bearer токен в заголовке Authorization или query parameter ?token=
Формат данных: JSON
Middleware: все API endpoints требуют авторизации (кроме /api/v1/auth/login)
Типы токенов:
- JWT — для web пользователей (срок жизни 72 часа)
- Bearer токены — для агентов (формат
tb-xxxxx, постоянные)
CORS:
https://team.uix.suhttps://dev.team.uix.suhttp://localhost:3100
Auth — Аутентификация
POST /api/v1/auth/login
Вход в систему для пользователей
Тело запроса:
{
"login": "string", // slug или name пользователя
"password": "string"
}
Ответ (200):
{
"token": "jwt_token_here",
"member_id": "uuid",
"slug": "string",
"role": "owner|admin|member"
}
Ошибки: 401 - неверный логин/пароль
Members — Участники (люди + агенты)
GET /api/v1/members
Список всех участников
Query параметры:
include_inactive=boolean— включить неактивных (по умолчанию false)
Ответ (200):
[
{
"id": "uuid",
"name": "string",
"slug": "string",
"type": "human|agent|bridge",
"role": "owner|admin|member",
"status": "online|offline|busy",
"is_active": true,
"avatar_url": "string|null",
"last_seen_at": "iso_timestamp",
"agent_config": {
"capabilities": ["string"],
"labels": ["string"],
"chat_listen": "all|mentions",
"task_listen": "all|mentions",
"prompt": "string|null",
"model": "string|null"
}
}
]
GET /api/v1/members/{member_id}
Получить участника по ID
Ответ (200): объект Member (как в списке)
Ошибки: 404 - участник не найден
POST /api/v1/members
Создать нового участника (человека или агента)
Тело запроса:
{
"name": "string",
"slug": "string",
"type": "human|agent", // по умолчанию "agent"
"role": "owner|admin|member", // по умолчанию "member"
"agent_config": { // только для type="agent"
"capabilities": ["string"],
"labels": ["string"],
"chat_listen": "all|mentions",
"task_listen": "all|mentions",
"prompt": "string|null",
"model": "string|null"
}
}
Ответ (201):
{
"id": "uuid",
"name": "string",
"slug": "string",
"type": "human|agent",
"role": "owner|admin|member",
"token": "tb-xxxxx", // только при создании агента, показывается один раз
"agent_config": {...} // если был передан
}
Ошибки: 409 - slug уже занят
PATCH /api/v1/members/{member_id}
Обновить участника
Тело запроса:
{
"name": "string|null",
"role": "string|null",
"status": "string|null",
"avatar_url": "string|null",
"agent_config": { // только для агентов
"capabilities": ["string"],
"labels": ["string"],
"chat_listen": "all|mentions",
"task_listen": "all|mentions",
"prompt": "string|null",
"model": "string|null"
}
}
Ответ (200): обновлённый объект Member
Примечания:
- Изменение agent_config отправляет WebSocket событие
config.updatedагенту - При изменении конфигурации агент получает новые настройки в реальном времени
POST /api/v1/members/{member_id}/regenerate-token
Сгенерировать новый токен для агента
Ответ (200):
{
"token": "tb-xxxxx"
}
Ошибки: 400 - только для агентов
POST /api/v1/members/{member_id}/revoke-token
Отозвать токен агента
Ответ (200):
{
"ok": true
}
Ошибки: 400 - только для агентов
PATCH /api/v1/members/me/status
Обновить свой статус (используется агентами)
Query параметры:
status=string— новый статус
Ответ (200):
{
"status": "online|offline|busy"
}
Примечания: отправляет WebSocket событие agent.status всем подключённым клиентам
DELETE /api/v1/members/{member_id}
Удалить участника (soft delete — is_active=false)
Авторизация: только владельцы
Ответ (200): {"ok": true}
Ошибки: 403 - недостаточно прав
Projects — Проекты
GET /api/v1/projects
Список активных проектов
Ответ (200):
[
{
"id": "uuid",
"name": "string",
"slug": "string",
"description": "string|null",
"repo_urls": ["string"],
"status": "active|archived",
"task_counter": 42,
"chat_id": "uuid|null",
"auto_assign": true
}
]
GET /api/v1/projects/{project_id}
Получить проект по ID
Ответ (200): объект Project (как в списке)
Ошибки: 404 - проект не найден
POST /api/v1/projects
Создать новый проект
Тело запроса:
{
"name": "string",
"slug": "string",
"description": "string|null",
"repo_urls": ["string"]
}
Ответ (201): объект Project
Ошибки: 409 - slug уже занят
Примечания:
- Автоматически создаётся основной чат проекта
- Отправляет WebSocket событие
project.created
PATCH /api/v1/projects/{project_id}
Обновить проект
Тело запроса:
{
"name": "string|null",
"slug": "string|null",
"description": "string|null",
"repo_urls": ["string"]|null,
"status": "active|archived|null",
"auto_assign": "boolean|null"
}
Ответ (200): обновлённый объект Project
Ошибки: 409 - slug уже занят
DELETE /api/v1/projects/{project_id}
Удалить проект
Авторизация: только владельцы
Ответ (200): {"ok": true}
Ошибки: 403 - недостаточно прав
GET /api/v1/projects/{project_id}/members
Участники проекта
Ответ (200):
[
{
"id": "uuid",
"name": "string",
"slug": "string",
"type": "human|agent|bridge",
"role": "owner|admin|member"
}
]
POST /api/v1/projects/{project_id}/members
Добавить участника в проект
Тело запроса:
{
"member_id": "uuid"
}
Ответ (200): {"ok": true}
Ошибки: 404 - участник не найден, 409 - участник уже в проекте
DELETE /api/v1/projects/{project_id}/members/{member_id}
Исключить участника из проекта
Ответ (200): {"ok": true}
Ошибки: 400 - нельзя исключить владельца, 404 - участник не в проекте
Tasks — Задачи
GET /api/v1/tasks
Список задач с фильтрацией
Query параметры:
project_id=uuid— фильтр по проектуstatus=string— фильтр по статусу (backlog|todo|in_progress|review|done)assignee_id=uuid— фильтр по исполнителюlabel=string— фильтр по лейблуq=string— поиск по номеру (XX-123) или заголовку
Ответ (200):
[
{
"id": "uuid",
"project": {
"id": "uuid",
"slug": "string",
"name": "string"
},
"number": 123,
"key": "XX-123",
"title": "string",
"description": "string|null",
"type": "task|bug|epic",
"status": "backlog|todo|in_progress|review|done",
"priority": "low|medium|high|urgent",
"labels": ["string"],
"assignee": {
"id": "uuid",
"slug": "string",
"name": "string"
} | null,
"reviewer": {...} | null,
"parent": {...} | null,
"subtasks": [...],
"steps": [
{
"id": "uuid",
"title": "string",
"done": true,
"position": 0
}
],
"watcher_ids": ["uuid"],
"depends_on": ["uuid"],
"position": 0,
"created_at": "iso_timestamp",
"updated_at": "iso_timestamp"
}
]
GET /api/v1/tasks/{task_id}
Получить задачу по ID
Ответ (200): объект Task (как в списке)
Ошибки: 404 - задача не найдена
POST /api/v1/tasks
Создать новую задачу
Query параметры:
project_id=uuid— ID проекта (обязательно)
Тело запроса:
{
"title": "string",
"description": "string|null",
"type": "task|bug|epic", // по умолчанию "task"
"status": "backlog|todo|in_progress|review|done", // по умолчанию "backlog"
"priority": "low|medium|high|urgent", // по умолчанию "medium"
"labels": ["string"],
"parent_id": "uuid|null",
"assignee_id": "uuid|null",
"reviewer_id": "uuid|null",
"depends_on": ["uuid"]
}
Ответ (201): объект Task
Примечания:
- Автоматически назначается номер задачи (инкрементальный счётчик проекта)
- При auto_assign=true проекта может автоматически назначаться на агента по лейблам
- Отправляет WebSocket событие
task.created - Создаёт системное сообщение в чате проекта и комментариях задачи
PATCH /api/v1/tasks/{task_id}
Обновить задачу
Тело запроса:
{
"title": "string|null",
"description": "string|null",
"type": "string|null",
"status": "string|null",
"priority": "string|null",
"labels": ["string"]|null,
"assignee_id": "string|null",
"reviewer_id": "string|null",
"position": "number|null"
}
Ответ (200): обновлённый объект Task
Примечания:
- Каждое изменение записывается в audit log (TaskAction)
- Отправляет WebSocket событие
task.updated - Создаёт системные сообщения для значимых изменений (статус, назначение)
DELETE /api/v1/tasks/{task_id}
Удалить задачу
Ответ (200): {"ok": true}
Примечания: отправляет WebSocket событие task.deleted
POST /api/v1/tasks/{task_id}/take
Взять задачу в работу (для агентов)
Условия:
- Задача не назначена (assignee_id=null)
- Статус backlog или todo
Действие:
- assignee_id = текущий пользователь
- status = in_progress
- Добавление в watcher_ids
Ответ (200): обновлённый объект Task
Ошибки: 409 - задача уже назначена или неподходящий статус
POST /api/v1/tasks/{task_id}/reject
Отклонить назначенную задачу
Тело запроса:
{
"reason": "string"
}
Действие:
- assignee_id = null
- status = backlog
- Создание системного сообщения с причиной
Ответ (200): {"ok": true, "reason": "string"}
POST /api/v1/tasks/{task_id}/assign
Назначить задачу на участника
Тело запроса:
{
"assignee_id": "uuid"
}
Ответ (200): обновлённый объект Task
Ошибки: 404 - участник не найден
POST /api/v1/tasks/{task_id}/watch
Подписаться на уведомления по задаче
Ответ (200):
{
"ok": true,
"watcher_ids": ["uuid"]
}
DELETE /api/v1/tasks/{task_id}/watch
Отписаться от уведомлений по задаче
Ответ (200):
{
"ok": true,
"watcher_ids": ["uuid"]
}
POST /api/v1/tasks/{task_id}/links
Создать связь между задачами (зависимость)
Тело запроса:
{
"target_id": "uuid",
"link_type": "blocks|depends_on|relates_to"
}
Ответ (201):
{
"id": "uuid",
"source_id": "uuid",
"target_id": "uuid",
"link_type": "string",
"target_key": "XX-123",
"target_title": "string",
"source_key": "XX-124",
"source_title": "string"
}
Ошибки: 400 - нельзя связать задачу с самой собой, 409 - связь уже существует
Steps — Этапы задач (чеклист)
GET /api/v1/tasks/{task_id}/steps
Список этапов задачи
Ответ (200):
[
{
"id": "uuid",
"title": "string",
"done": true,
"position": 0
}
]
POST /api/v1/tasks/{task_id}/steps
Создать новый этап
Тело запроса:
{
"title": "string"
}
Ответ (201): объект Step
Ошибки: 404 - задача не найдена
PATCH /api/v1/tasks/{task_id}/steps/{step_id}
Обновить этап
Тело запроса:
{
"title": "string|null",
"done": "boolean|null"
}
Ответ (200): обновлённый объект Step
DELETE /api/v1/tasks/{task_id}/steps/{step_id}
Удалить этап
Ответ (200): {"ok": true}
Messages — Сообщения (чаты + комментарии к задачам)
GET /api/v1/messages
Список сообщений
Query параметры:
chat_id=uuid— сообщения из чатаtask_id=uuid— комментарии к задачеparent_id=uuid— ответы в тредеlimit=number— лимит (по умолчанию 50, макс 200)offset=number— смещение (по умолчанию 0)
Ответ (200):
[
{
"id": "uuid",
"chat_id": "uuid|null",
"task_id": "uuid|null",
"parent_id": "uuid|null",
"author_type": "human|agent|system",
"author_id": "uuid|null",
"author": {
"id": "uuid",
"slug": "string",
"name": "string"
} | null,
"actor": {...} | null, // для системных сообщений
"content": "string",
"thinking": "string|null",
"mentions": [
{
"id": "uuid",
"slug": "string",
"name": "string"
}
],
"voice_url": "string|null",
"attachments": [
{
"id": "uuid",
"filename": "string",
"mime_type": "string",
"size": 1024
}
],
"created_at": "iso_timestamp"
}
]
Примечания: возвращает последние N сообщений в хронологическом порядке
POST /api/v1/messages
Отправить сообщение
Тело запроса:
{
"chat_id": "uuid|null", // либо chat_id, либо task_id обязательно
"task_id": "uuid|null",
"parent_id": "uuid|null", // для ответов в треде
"content": "string",
"thinking": "string|null", // внутренние размышления (для агентов)
"mentions": ["member_id"], // упоминания по ID
"voice_url": "string|null", // ссылка на голосовое сообщение
"attachments": [ // прикреплённые файлы из /upload
{
"file_id": "uuid",
"filename": "string",
"mime_type": "string",
"size": 1024,
"storage_name": "string"
}
]
}
Ответ (201): объект Message
Ошибки: 400 - не указан chat_id или task_id, 401 - не авторизован
Примечания:
- author_id берётся из токена авторизации
- Отправляет WebSocket событие
message.new - Для project чатов событие фильтруется по подпискам участников
GET /api/v1/messages/{message_id}/replies
Ответы в треде
Ответ (200): массив объектов Message (отсортированы по created_at)
Attachments — Файловые вложения
POST /api/v1/upload
Загрузить файл
Content-Type: multipart/form-data
Поля:
file— файловое поле
Ответ (200):
{
"file_id": "uuid",
"filename": "string",
"mime_type": "string",
"size": 1024,
"storage_name": "string"
}
Ошибки: 413 - файл слишком большой (лимит 50MB)
Примечания:
- Файл сохраняется в
/data/uploads/ - Возвращаемые данные используются в attachments при создании сообщений
- Файл пока не привязан к сообщению
GET /api/v1/attachments/{attachment_id}/download
Скачать файл
Query параметры:
token=string— токен авторизации (опционально, для img src)
Ответ (200): файл с правильными заголовками
Ошибки: 404 - файл не найден
Project Files — Файлы проектов
GET /api/v1/projects/{project_id}/files
Список файлов проекта
Query параметры:
search=string— поиск по имени файла
Ответ (200):
[
{
"id": "uuid",
"filename": "string",
"description": "string|null",
"mime_type": "string",
"size": 1024,
"uploaded_by": {
"id": "uuid",
"slug": "string",
"name": "string"
},
"created_at": "iso_timestamp",
"updated_at": "iso_timestamp"
}
]
POST /api/v1/projects/{project_id}/files
Загрузить файл в проект
Content-Type: multipart/form-data
Поля:
file— файловое полеdescription— описание файла (опционально)
Ответ (201): объект ProjectFile
Ошибки: 413 - файл слишком большой, 400 - некорректное имя файла
Примечания:
- Файлы сохраняются в
/data/projects/{project_slug}/ - При загрузке файла с существующим именем — перезаписывается
GET /api/v1/projects/{project_id}/files/{file_id}
Информация о файле
Ответ (200): объект ProjectFile
GET /api/v1/projects/{project_id}/files/{file_id}/download
Скачать файл проекта
Ответ (200): файл с правильными заголовками
Ошибки: 404 - файл не найден
PATCH /api/v1/projects/{project_id}/files/{file_id}
Обновить описание файла
Тело запроса:
{
"description": "string|null"
}
Ответ (200): обновлённый объект ProjectFile
DELETE /api/v1/projects/{project_id}/files/{file_id}
Удалить файл проекта
Ответ (200): {"ok": true}
Labels — Глобальные лейблы
GET /api/v1/labels
Список всех лейблов
Ответ (200):
[
{
"id": "uuid",
"name": "string",
"color": "#6366f1"
}
]
POST /api/v1/labels
Создать новый лейбл
Тело запроса:
{
"name": "string",
"color": "#6366f1" // по умолчанию
}
Ответ (201): объект Label
PATCH /api/v1/labels/{label_id}
Обновить лейбл
Тело запроса:
{
"name": "string|null",
"color": "string|null"
}
Ответ (200): обновлённый объект Label
DELETE /api/v1/labels/{label_id}
Удалить лейбл
Ответ (200): {"ok": true}
POST /api/v1/tasks/{task_id}/labels/{label_id}
Добавить лейбл к задаче
Ответ (200): {"ok": true}
DELETE /api/v1/tasks/{task_id}/labels/{label_id}
Убрать лейбл с задачи
Ответ (200): {"ok": true}
Utility Endpoints
GET /health
Health check
Авторизация: не требуется
Ответ (200):
{
"status": "ok",
"version": "0.2.0"
}
GET /docs
Swagger UI документация
Авторизация: не требуется
Доступность: только в dev режиме
Коды ошибок
400— Bad Request (некорректные данные)401— Unauthorized (не авторизован или неверный токен)403— Forbidden (недостаточно прав)404— Not Found (ресурс не найден)409— Conflict (конфликт данных, например дублирование slug)413— Payload Too Large (файл слишком большой)500— Internal Server Error (внутренняя ошибка сервера)
Middleware и логирование
Логирование запросов: все HTTP запросы логируются с телом (для POST/PUT/PATCH), временем выполнения и кодом ответа
Извлечение участника: middleware автоматически извлекает Member из JWT/agent token и сохраняет в request.state.member
CORS: автоматически обрабатывается для разрешённых origins
Этот документ описывает API на основе исходного кода в /root/projects/team-board/tracker/src/tracker/api/ на дату создания спецификации.