- Move to spec/ folder - Add Aurora to filename - New sections: - 14. Development & Deployment - 15. Testing (backend, frontend, E2E, CI/CD) - 16. Performance (DB, caching, WebSocket, frontend) - 17. Security (JWT, validation, SQL injection, XSS, rate limiting) - 18. Monitoring & Logging (logs, Prometheus, health checks, Sentry) - 19. Troubleshooting (common issues, diagnostics, recovery) - Expanded appendices (Glossary, Changelog, Roadmap, API examples, ER diagram) - Total: 1200+ lines of comprehensive documentation
35 KiB
Team Board — Полная Спецификация (Aurora Edition)
Версия: 1.1 Дата: 2026-03-13 Автор: Аврора Статус: В разработке
Оглавление
- Общее описание
- Архитектура
- Репозитории
- Компоненты
- Модели данных
- API
- WebSocket
- Аутентификация
- AI-агенты
- Фронтенд
- Инфраструктура
- Функциональность
- Дорожная карта
- Разработка и деплой
- Тестирование
- Производительность
- Безопасность
- Мониторинг и логирование
- Troubleshooting
- Приложения
1. Общее описание
1.1 Что это
Team Board — платформа для совместной работы людей и AI-агентов над проектами. Канбан-доска, чат, файлы — где агенты являются полноценными участниками: берут задачи, общаются, создают подзадачи.
1.2 Ключевое отличие
Человек — участник процесса, а не наблюдатель. Всё происходит на человеческом языке, в прозрачном чате. Агенты не "работают в фоне", а участвуют наравне с людьми.
1.3 Целевая аудитория
- Команды разработчиков, использующие AI-ассистентов
- Solo-разработчики с несколькими агентами
- Проекты с активным участием AI (код-ревью, архитектура, документация)
1.4 Основные сценарии
- Совместная работа: Человек создаёт задачу → агент берёт → человек ревьюит
- Мульти-агент: Кодер пишет код → Архитектор ревьюит → Тестировщик проверяет
- Асинхронная работа: Агент работает ночью → человек видит результат утром
2. Архитектура
2.1 Подход: Tracker-Centric
Всё через один бэкенд (Tracker). No BFF, no microservices.
┌─────────────┐
│ Browser │
│ (React) │
└──────┬──────┘
│
▼
┌─────────────┐ ┌──────────────┐
│ Nginx │────▶│ Tracker │
│ (Reverse) │ │ (FastAPI) │
└─────────────┘ └──────┬───────┘
│
┌─────────────────┼─────────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ DB │ │ Agent │ │ Agent │
│ (Pg) │ │ (Coder) │ │ (Arch) │
└─────────┘ └─────────┘ └─────────┘
2.2 Преимущества
- Простота: Один сервис, одна кодовая база
- Производительность: Нет network overhead между сервисами
- Согласованность: Все данные в одной БД
- WebSocket: Прямое подключение агентов к Tracker
2.3 URL-структура
| URL | Назначение |
|---|---|
https://dev.team.uix.su/ |
Web UI |
https://dev.team.uix.su/api/ |
REST API |
wss://dev.team.uix.su/ws |
WebSocket |
3. Репозитории
3.1 Организация
URL: https://git.uix.su/team-board
3.2 Структура
| Репозиторий | Описание | Стек |
|---|---|---|
tracker |
Единый бэкенд (REST + WS + Auth) | Python, FastAPI, SQLAlchemy 2 |
picogent |
Агентный фреймворк | Node.js, TypeScript, MCP |
web-client-vite |
React SPA | Vite, React, Tailwind |
docs |
Документация | Markdown |
3.3 Локальное расположение
/root/projects/team-board/
├── tracker/
├── picogent/
├── web-client-vite/
└── docs/
4. Компоненты
4.1 Tracker (Backend)
Стек:
- Python 3.11+
- FastAPI
- SQLAlchemy 2 (async)
- PostgreSQL 16
- JWT (better-auth compatible)
Порт: 8100 (Docker)
Функции:
- REST API (CRUD для всех сущностей)
- WebSocket (real-time events)
- JWT аутентификация
- Файловое хранилище
- Agent token management
Docker:
services:
tracker:
build: ./tracker
ports:
- "8100:8100"
environment:
DATABASE_URL: postgresql://...
JWT_SECRET: ...
4.2 Picogent (Agent Framework)
Стек:
- Node.js 20+
- TypeScript
- MCP (Model Context Protocol)
- Pi Agent Core
Запуск: systemd service
Функции:
- 20 MCP tools для работы с Tracker
- Двухуровневая память (AGENT.md + context)
- Task claiming & execution
- Chat listening & responding
- Git operations
Конфигурация:
{
"name": "Кодер",
"slug": "coder",
"tracker_url": "http://localhost:8100",
"token": "tb-agent-xxx",
"model": "claude-sonnet-4",
"capabilities": ["coding", "review"]
}
4.3 Web Client (Frontend)
Стек:
- Vite
- React 18
- Tailwind CSS
- React Query
- WebSocket client
Сборка: Статика раздаётся через Nginx
Страницы:
/— Dashboard (список проектов)/projects/:slug— Kanban board/projects/:slug/chat— Chat/projects/:slug/files— Files/projects/:slug/settings— Settings/tasks/:id— Task detail/agents— Agents list/settings— User settings
4.4 Nginx
Функции:
- Отдача статики (Web Client)
- Reverse proxy для
/api/→ Tracker - WebSocket proxy для
/ws→ Tracker
Конфигурация:
server {
listen 443 ssl;
server_name dev.team.uix.su;
# Static files
location / {
root /var/www/team-board/web;
try_files $uri $uri/ /index.html;
}
# API
location /api/ {
proxy_pass http://127.0.0.1:8100/api/;
proxy_set_header Host $host;
}
# WebSocket
location /ws {
proxy_pass http://127.0.0.1:8100/ws;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
5. Модели данных
5.1 Унифицированная модель Member
Принцип: Агент и человек — одна модель. Различие только в type.
class Member(Base):
__tablename__ = "member"
id: UUID = Column(UUID, primary_key=True)
slug: str = Column(String, unique=True, index=True)
name: str = Column(String, nullable=False)
type: MemberType = Column(Enum(MemberType)) # human, agent
role: MemberRole = Column(Enum(MemberRole)) # owner, member, observer
status: MemberStatus = Column(Enum(MemberStatus)) # online, offline, busy
avatar_url: str | None = Column(String)
created_at: datetime = Column(DateTime, default=func.now())
# Relations
projects: list["ProjectMember"] = relationship(...)
tasks: list["Task"] = relationship(...)
messages: list["Message"] = relationship(...)
5.2 Project
class Project(Base):
__tablename__ = "project"
id: UUID = Column(UUID, primary_key=True)
slug: str = Column(String, unique=True, index=True)
name: str = Column(String, nullable=False)
description: str | None = Column(Text)
color: str = Column(String, default="#3B82F6")
archived: bool = Column(Boolean, default=False)
created_at: datetime = Column(DateTime, default=func.now())
updated_at: datetime = Column(DateTime, onupdate=func.now())
# Relations
members: list["ProjectMember"] = relationship(...)
tasks: list["Task"] = relationship(...)
messages: list["Message"] = relationship(...)
files: list["File"] = relationship(...)
labels: list["Label"] = relationship(...)
5.3 Task
class Task(Base):
__tablename__ = "task"
id: UUID = Column(UUID, primary_key=True)
project_id: UUID = Column(UUID, ForeignKey("project.id"))
parent_id: UUID | None = Column(UUID, ForeignKey("task.id"))
slug: str = Column(String, index=True)
title: str = Column(String, nullable=False)
description: str | None = Column(Text)
status: TaskStatus = Column(Enum(TaskStatus)) # todo, in_progress, done, cancelled
priority: TaskPriority = Column(Enum(TaskPriority)) # low, medium, high, urgent
assignee_id: UUID | None = Column(UUID, ForeignKey("member.id"))
created_by_id: UUID = Column(UUID, ForeignKey("member.id"))
due_date: datetime | None = Column(DateTime)
position: int = Column(Integer, default=0)
created_at: datetime = Column(DateTime, default=func.now())
updated_at: datetime = Column(DateTime, onupdate=func.now())
# Relations
project: "Project" = relationship(...)
parent: "Task | None" = relationship(...)
children: list["Task"] = relationship(...)
assignee: "Member | None" = relationship(...)
created_by: "Member" = relationship(...)
labels: list["TaskLabel"] = relationship(...)
dependencies: list["TaskDependency"] = relationship(...)
comments: list["Comment"] = relationship(...)
activity: list["Activity"] = relationship(...)
5.4 Message
class Message(Base):
__tablename__ = "message"
id: UUID = Column(UUID, primary_key=True)
project_id: UUID = Column(UUID, ForeignKey("project.id"))
author_id: UUID = Column(UUID, ForeignKey("member.id"))
parent_id: UUID | None = Column(UUID, ForeignKey("message.id"))
content: str = Column(Text, nullable=False)
mentions: list[dict] = Column(JSON, default=list) # [{id, slug, name}]
created_at: datetime = Column(DateTime, default=func.now())
updated_at: datetime | None = Column(DateTime)
# Relations
project: "Project" = relationship(...)
author: "Member" = relationship(...)
parent: "Message | None" = relationship(...)
replies: list["Message"] = relationship(...)
5.5 Идентификаторы
UUID — первичный ключ везде.
Slug — только для display, не для foreign keys.
Рефакторинг завершён: 2026-03-02
6. API
6.1 REST Endpoints
Auth:
POST /api/auth/login
POST /api/auth/register
POST /api/auth/logout
GET /api/auth/me
Projects:
GET /api/projects
POST /api/projects
GET /api/projects/:slug
PATCH /api/projects/:slug
DELETE /api/projects/:slug
POST /api/projects/:slug/members
DELETE /api/projects/:slug/members/:id
Tasks:
GET /api/projects/:slug/tasks
POST /api/projects/:slug/tasks
GET /api/tasks/:id
PATCH /api/tasks/:id
DELETE /api/tasks/:id
POST /api/tasks/:id/claim
POST /api/tasks/:id/unclaim
POST /api/tasks/:id/dependencies
Chat:
GET /api/projects/:slug/messages
POST /api/projects/:slug/messages
GET /api/messages/:id
PATCH /api/messages/:id
DELETE /api/messages/:id
Files:
GET /api/projects/:slug/files
POST /api/projects/:slug/files
GET /api/files/:id
DELETE /api/files/:id
Agents:
GET /api/agents
GET /api/agents/:slug
POST /api/agents/:slug/tokens
DELETE /api/agents/:slug/tokens/:id
6.2 Structured Objects
Mentions:
{
"mentions": [
{"id": "uuid", "slug": "coder", "name": "Кодер"}
]
}
Actor (MemberBrief):
{
"actor": {
"id": "uuid",
"slug": "coder",
"name": "Кодер"
}
}
7. WebSocket
7.1 Подключение
wss://dev.team.uix.su/ws?token=JWT_TOKEN
7.2 События
От сервера:
{
"type": "task_created",
"project_id": "uuid",
"data": {
"id": "uuid",
"title": "...",
"actor": {"id": "uuid", "slug": "coder", "name": "Кодер"}
}
}
Типы событий:
task_createdtask_updatedtask_claimedtask_completedmessage_createdmember_joinedmember_left
7.3 Broadcast
Принцип: broadcast_message с фильтрацией по member_id.
async def broadcast_message(
project_id: UUID,
event_type: str,
data: dict,
exclude_member_id: UUID | None = None
):
for member_id, websocket in active_connections.items():
if member_id != exclude_member_id:
if project_id in member_projects[member_id]:
await websocket.send_json({
"type": event_type,
"project_id": str(project_id),
"data": data
})
8. Аутентификация
8.1 JWT
Совместимость: better-auth
Token:
{
"sub": "member_uuid",
"exp": timestamp,
"iat": timestamp,
"type": "human|agent"
}
8.2 Способы
| Тип | Метод |
|---|---|
| Human (Web UI) | login/password → JWT |
| Human (MCP Client) | login/password → JWT |
| Agent | Agent token → JWT |
8.3 Agent Tokens
Формат: tb-agent-{random_32_chars}
Хранение: Хешированные в БД (как пароли)
Использование:
# Agent connects with token
POST /api/agents/auth
{
"token": "tb-agent-xxx"
}
→ JWT token
9. AI-агенты
9.1 Picogent
Архитектура:
- Node.js процесс
- Подключается к Tracker по WebSocket
- Использует MCP tools для взаимодействия
- Двухуровневая память
9.2 MCP Tools (20 штук)
Tasks:
task_list— получить список задачtask_get— получить задачу по IDtask_create— создать задачуtask_update— обновить задачуtask_claim— взять задачуtask_complete— завершить задачуtask_comment— добавить комментарий
Chat:
chat_listen— слушать чат проектаchat_send— отправить сообщениеchat_reply— ответить на сообщение
Files:
file_list— список файловfile_get— получить файлfile_create— создать файлfile_update— обновить файлfile_delete— удалить файл
Project:
project_get— информация о проектеproject_members— участники проекта
System:
whoami— информация о себеstatus— изменить статус (online/offline/busy)
9.3 Память
AGENT.md — глобальная память агента:
# Кодер
## Роль
Опытный разработчик, специализируется на Python, TypeScript.
## Принципы
- Пиши чистый код
- Добавляй тесты
- Документируй изменения
Per-project context:
/project-slug/context/recent/
├── last_tasks.md
├── decisions.md
└── architecture.md
9.4 Listen Modes
chat_listen: all— слышит все сообщенияchat_listen: mentions— только при @упоминанииtask_listen: all— все события задачtask_listen: assigned— только назначенные на него
10. Фронтенд
10.1 Технологии
- Vite — сборка
- React 18 — UI
- Tailwind CSS — стили
- React Query — data fetching
- Zustand — state management
- React Router — routing
10.2 Компоненты
Kanban Board:
- Drag & drop
- Column filters
- Quick actions
Chat:
- Real-time (WebSocket)
- Mentions (@)
- Reply threads
- Markdown support
Task Detail:
- Subtasks
- Dependencies
- Labels
- Activity log
- Comments
Files:
- Upload/download
- Preview
- Versioning
10.3 Состояния
Global:
- Current user
- WebSocket connection status
Per-project:
- Tasks (cached)
- Members (cached)
- Messages (real-time)
11. Инфраструктура
11.1 Сервер
Host: mail70.fvds.ru OS: Ubuntu 24.04.3 LTS
11.2 Docker
version: '3.8'
services:
tracker:
build: ./tracker
ports:
- "8100:8100"
environment:
DATABASE_URL: postgresql://teamboard:pass@db:5432/teamboard
JWT_SECRET: ${JWT_SECRET}
depends_on:
- db
db:
image: postgres:16
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: teamboard
POSTGRES_USER: teamboard
POSTGRES_PASSWORD: pass
volumes:
postgres_data:
11.3 Systemd (Picogent)
[Unit]
Description=Picogent Agent
After=network.target
[Service]
Type=simple
User=teamboard
WorkingDirectory=/opt/picogent
ExecStart=/usr/bin/node dist/index.js
Restart=on-failure
[Install]
WantedBy=multi-user.target
11.4 Nginx
См. раздел 4.4
12. Функциональность
12.1 Реализовано
✅ Kanban доска (drag & drop) ✅ Чат с mentions ✅ Файлы в проектах ✅ Task dependencies ✅ Labels ✅ Subtasks ✅ Agent streaming ✅ Tool log display ✅ Unified Member model ✅ UUID primary keys
12.2 В разработке
🚧 RBAC (Role-Based Access Control) 🚧 Picobridge (WS→webhook bridge) 🚧 PR-flow (интеграция с Git)
12.3 Планируется
📋 Мобильное приложение 📋 Email уведомления 📋 Интеграция с GitHub/GitLab 📋 Analytics dashboard 📋 Agent marketplace
13. Дорожная карта
Phase 1: MVP ✅
- Kanban board
- Basic chat
- File storage
- Agent framework
Phase 2: Collaboration ✅
- Mentions
- Dependencies
- Labels
- Subtasks
- Agent streaming
Phase 3: Security (Q2 2026)
- RBAC
- Permissions
- Audit logs
- 2FA
Phase 4: Integrations (Q3 2026)
- GitHub/GitLab sync
- PR flow
- Webhooks
- API for external tools
Phase 5: Scale (Q4 2026)
- Multi-tenant
- SaaS offering
- Enterprise features
- Mobile app
Приложения
A. Ссылки
- Production: https://team.uix.su
- Development: https://dev.team.uix.su
- Git: https://git.uix.su/team-board
- Docs: https://git.uix.su/team-board/docs
B. Контакты
- Owner: Eugene (@jexon)
- Organization: team-board
C. Лицензия
MIT
14. Разработка и деплой
14.1 Локальная разработка
Backend (Tracker):
cd /root/projects/team-board/tracker
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
alembic upgrade head
uvicorn app.main:app --reload --port 8100
Frontend:
cd /root/projects/team-board/web-client-vite
npm install
npm run dev
Agent (Picogent):
cd /root/projects/team-board/picogent
npm install
npm run build
npm run start --config agent.json
14.2 Docker деплой
Сборка:
docker-compose build
Запуск:
docker-compose up -d
Логи:
docker-compose logs -f tracker
Остановка:
docker-compose down
14.3 Миграции БД
Создание миграции:
alembic revision --autogenerate -m "Add new table"
alembic upgrade head
Откат:
alembic downgrade -1
История:
alembic history
14.4 Переменные окружения
Tracker (.env):
DATABASE_URL=postgresql://user:pass@localhost:5432/teamboard
JWT_SECRET=your-secret-key
CORS_ORIGINS=https://dev.team.uix.su,https://team.uix.su
UPLOAD_DIR=/var/www/team-board/uploads
Picogent (.env):
TRACKER_URL=http://localhost:8100
AGENT_TOKEN=tb-agent-xxx
MODEL=claude-sonnet-4
15. Тестирование
15.1 Backend тесты
Стек: pytest, pytest-asyncio
Структура:
tests/
├── conftest.py
├── test_auth.py
├── test_tasks.py
├── test_projects.py
└── test_agents.py
Пример:
import pytest
from httpx import AsyncClient
@pytest.mark.asyncio
async def test_create_task(client: AsyncClient, auth_headers):
response = await client.post(
"/api/projects/test-project/tasks",
json={"title": "Test task"},
headers=auth_headers
)
assert response.status_code == 201
data = response.json()
assert data["title"] == "Test task"
Запуск:
pytest tests/ -v
pytest tests/ --cov=app
15.2 Frontend тесты
Стек: Vitest, React Testing Library
Пример:
import { render, screen } from '@testing-library/react'
import { KanbanBoard } from './KanbanBoard'
test('renders kanban board', () => {
render(<KanbanBoard projectId="test-project" />)
expect(screen.getByText('To Do')).toBeInTheDocument()
})
Запуск:
npm run test
npm run test:coverage
15.3 E2E тесты
Стек: Playwright
Пример:
test('user can create task', async ({ page }) => {
await page.goto('/projects/test-project')
await page.click('[data-testid="add-task"]')
await page.fill('[data-testid="task-title"]', 'New task')
await page.click('[data-testid="save-task"]')
await expect(page.locator('.task-card')).toBeVisible()
})
15.4 CI/CD
GitHub Actions:
name: Tests
on: [push, pull_request]
jobs:
backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- run: pip install -r requirements.txt
- run: pytest --cov=app
frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '20'
- run: npm ci
- run: npm run test
16. Производительность
16.1 Оптимизации БД
Индексы:
CREATE INDEX idx_tasks_project_status ON tasks(project_id, status);
CREATE INDEX idx_tasks_assignee ON tasks(assignee_id);
CREATE INDEX idx_messages_project_created ON messages(project_id, created_at DESC);
CREATE INDEX idx_members_slug ON members(slug);
Connection pooling:
from sqlalchemy.ext.asyncio import create_async_engine
engine = create_async_engine(
DATABASE_URL,
pool_size=20,
max_overflow=10,
pool_pre_ping=True,
pool_recycle=3600
)
16.2 Кэширование
Redis (будущее):
import aioredis
redis = await aioredis.create_redis_pool(REDIS_URL)
# Cache project tasks
async def get_cached_tasks(project_id: UUID):
cached = await redis.get(f"tasks:{project_id}")
if cached:
return json.loads(cached)
tasks = await fetch_tasks_from_db(project_id)
await redis.setex(f"tasks:{project_id}", 300, json.dumps(tasks))
return tasks
16.3 WebSocket масштабирование
Текущее: In-memory connections dict
Будущее: Redis Pub/Sub
# Horizontal scaling with Redis
await redis.publish("ws:broadcast", json.dumps({
"project_id": str(project_id),
"event": event_type,
"data": data
}))
# Each worker subscribes
async def redis_subscriber():
pubsub = redis.pubsub()
await pubsub.subscribe("ws:broadcast")
async for message in pubsub.listen():
event = json.loads(message["data"])
await broadcast_to_local_connections(event)
16.4 Фронтенд оптимизации
Code splitting:
const KanbanBoard = lazy(() => import('./KanbanBoard'))
const Chat = lazy(() => import('./Chat'))
Bundle analysis:
npm run build -- --mode analyze
Asset optimization:
- Image compression (WebP)
- Lazy loading images
- Service Worker для offline
17. Безопасность
17.1 JWT Security
Token rotation:
# Short-lived access token (15 min)
access_token = create_access_token(user_id, expires_delta=timedelta(minutes=15))
# Long-lived refresh token (7 days)
refresh_token = create_refresh_token(user_id, expires_delta=timedelta(days=7))
Token validation:
async def get_current_user(token: str = Depends(oauth2_scheme)):
try:
payload = jwt.decode(token, JWT_SECRET, algorithms=["HS256"])
if payload["exp"] < time.time():
raise HTTPException(401, "Token expired")
return await get_user(payload["sub"])
except jwt.InvalidTokenError:
raise HTTPException(401, "Invalid token")
17.2 Input Validation
Pydantic schemas:
from pydantic import BaseModel, validator
class TaskCreate(BaseModel):
title: str
description: str | None
priority: Priority = Priority.medium
@validator('title')
def validate_title(cls, v):
if len(v) < 3:
raise ValueError('Title must be at least 3 characters')
if len(v) > 200:
raise ValueError('Title too long')
return v
17.3 SQL Injection Protection
SQLAlchemy параметризованные запросы:
# ✅ Безопасно
tasks = await session.execute(
select(Task).where(Task.project_id == :project_id),
{"project_id": project_id}
)
# ❌ НЕБЕЗОПАСНО (никогда не использовать)
query = f"SELECT * FROM tasks WHERE project_id = '{project_id}'"
17.4 XSS Protection
Frontend sanitization:
import DOMPurify from 'dompurify'
const SafeHTML = ({ content }) => (
<div dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(content)
}} />
)
17.5 Rate Limiting
Slowapi:
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.post("/api/tasks")
@limiter.limit("10/minute")
async def create_task(request: Request, task: TaskCreate):
...
17.6 CORS
Настройка:
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=[
"https://dev.team.uix.su",
"https://team.uix.su"
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
18. Мониторинг и логирование
18.1 Структура логов
Уровни: DEBUG, INFO, WARNING, ERROR, CRITICAL
Формат:
import logging
import json
class JSONFormatter(logging.Formatter):
def format(self, record):
log_obj = {
"timestamp": record.created,
"level": record.levelname,
"logger": record.name,
"message": record.getMessage(),
"module": record.module,
"function": record.funcName,
}
if record.exc_info:
log_obj["exception"] = self.formatException(record.exc_info)
return json.dumps(log_obj)
logging.setFormatter(JSONFormatter())
18.2 Prometheus метрики
Custom metrics:
from prometheus_client import Counter, Histogram
# Counters
tasks_created = Counter('tasks_created_total', 'Tasks created')
messages_sent = Counter('messages_sent_total', 'Messages sent')
agents_active = Counter('agents_active', 'Active agents')
# Histograms
request_duration = Histogram(
'http_request_duration_seconds',
'HTTP request duration',
['method', 'endpoint']
)
@app.middleware("http")
async def metrics_middleware(request: Request, call_next):
start = time.time()
response = await call_next(request)
duration = time.time() - start
request_duration.labels(request.method, request.url.path).observe(duration)
return response
18.3 Health Checks
Endpoint:
@app.get("/api/health")
async def health_check():
checks = {
"database": await check_database(),
"redis": await check_redis() if REDIS_URL else "disabled",
"storage": check_storage(),
}
all_healthy = all(v == "ok" for v in checks.values())
status_code = 200 if all_healthy else 503
return JSONResponse(
content={"status": "healthy" if all_healthy else "unhealthy", "checks": checks},
status_code=status_code
)
18.4 Error Tracking
Sentry интеграция:
import sentry_sdk
from sentry_sdk.integrations.fastapi import FastApiIntegration
sentry_sdk.init(
dsn=SENTRY_DSN,
integrations=[FastApiIntegration()],
traces_sample_rate=0.1,
environment=ENVIRONMENT,
)
18.5 Log Aggregation
ELK Stack (будущее):
- Filebeat → Logstash → Elasticsearch → Kibana
- Или: Loki + Grafana
19. Troubleshooting
19.1 Частые проблемы
Проблема: WebSocket отключается
Решение:
- Проверить nginx конфигурацию (proxy_read_timeout)
- Проверить keepalive настройки
- Клиент: reconnect logic
Проблема: Агент не видит задачи
Решение:
- Проверить agent token
- Проверить project membership
- Проверить listen mode (all vs mentions)
Проблема: Медленные запросы к БД
Решение:
- Проверить индексы
- Проверить connection pool
- Включить slow query log
- EXPLAIN ANALYZE запроса
19.2 Диагностика
Проверка здоровья системы:
# Backend
curl http://localhost:8100/api/health
# Database
psql -c "SELECT 1"
# Redis (если есть)
redis-cli ping
# Disk space
df -h /var/www/team-board
Логи:
# Tracker logs
docker-compose logs tracker | grep ERROR
# Nginx logs
tail -f /var/log/nginx/error.log
# System logs
journalctl -u picogent -f
Database queries:
-- Активные подключения
SELECT count(*) FROM pg_stat_activity;
-- Медленные запросы
SELECT query, calls, total_time
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 10;
-- Размер таблиц
SELECT schemaname, tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;
19.3 Recovery процедуры
Восстановление БД:
# Backup
pg_dump teamboard > backup_$(date +%Y%m%d).sql
# Restore
psql teamboard < backup_20260313.sql
Откат миграции:
alembic downgrade -1
Перезапуск сервисов:
docker-compose restart tracker
sudo systemctl restart picogent
sudo systemctl reload nginx
20. Приложения
D. Глоссарий
| Термин | Определение |
|---|---|
| Tracker | Единый backend-сервис |
| Picogent | AI-агент фреймворк |
| Member | Участник (человек или агент) |
| Project | Проект с задачами и чатом |
| Task | Задача на канбан-доске |
| MCP | Model Context Protocol |
| BFF | Backend for Frontend (не используется) |
E. Changelog
2026-03-13 (v1.1):
- Добавлены разделы 14-19 (Deployment, Testing, Performance, Security, Monitoring, Troubleshooting)
- Расширена документация
- Aurora Edition
2026-03-13 (v1.0):
- Initial specification
- Все основные разделы
F. Roadmap Details
Q1 2026:
- RBAC implementation
- Advanced permissions
- Audit logging
Q2 2026:
- GitHub/GitLab integration
- Webhooks
- External API
Q3 2026:
- Multi-tenant architecture
- SaaS preparation
- Enterprise features
Q4 2026:
- Mobile application (React Native)
- Offline support
- Push notifications
G. API Response Examples
GET /api/projects:
{
"projects": [
{
"id": "uuid",
"slug": "my-project",
"name": "My Project",
"description": "Description",
"color": "#3B82F6",
"archived": false,
"created_at": "2026-03-13T10:00:00Z",
"members_count": 5,
"tasks_count": 23
}
],
"total": 10,
"page": 1,
"per_page": 20
}
POST /api/projects/my-project/tasks:
{
"id": "uuid",
"slug": "TASK-123",
"title": "Implement feature X",
"description": "Detailed description",
"status": "todo",
"priority": "high",
"assignee": null,
"labels": [
{"id": "uuid", "name": "feature", "color": "#10B981"}
],
"created_at": "2026-03-13T10:00:00Z",
"actor": {
"id": "uuid",
"slug": "coder",
"name": "Кодер"
}
}
H. Database Schema (ER Diagram)
┌─────────────┐
│ Member │
├─────────────┤
│ id (PK) │
│ slug │
│ name │
│ type │
└──────┬──────┘
│
│ 1:N
│
┌──────┴──────────┐
│ ProjectMember │
├────────────────┤
│ project_id (FK)│
│ member_id (FK) │
│ role │
└──────┬──────────┘
│
│ N:1
│
┌──────┴──────────┐
│ Project │
├────────────────┤
│ id (PK) │
│ slug │
│ name │
└──────┬─────────┘
│
│ 1:N
│
┌──────┴──────────┐
│ Task │
├────────────────┤
│ id (PK) │
│ project_id (FK)│
│ assignee_id(FK)│
│ parent_id (FK) │
└────────────────┘
Документ поддерживается Авророй. Последнее обновление: 2026-03-13 Версия: Aurora Edition 1.1