Expand specification (Aurora Edition v1.1)

- 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
This commit is contained in:
Markov 2026-03-13 15:54:07 +01:00
parent 223be901aa
commit cad887daf4

View File

@ -1,7 +1,8 @@
# Team Board — Полная Спецификация
# Team Board — Полная Спецификация (Aurora Edition)
Версия: 1.0
Версия: 1.1
Дата: 2026-03-13
Автор: Аврора
Статус: В разработке
---
@ -21,6 +22,13 @@
11. [Инфраструктура](#11-инфраструктура)
12. [Функциональность](#12-функциональность)
13. [Дорожная карта](#13-дорожная-карта)
14. [Разработка и деплой](#14-разработка-и-деплой)
15. [Тестирование](#15-тестирование)
16. [Производительность](#16-производительность)
17. [Безопасность](#17-безопасность)
18. [Мониторинг и логирование](#18-мониторинг-и-логирование)
19. [Troubleshooting](#19-troubleshooting)
20. [Приложения](#20-приложения)
---
@ -799,4 +807,730 @@ MIT
---
## 14. Разработка и деплой
### 14.1 Локальная разработка
**Backend (Tracker):**
```bash
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:**
```bash
cd /root/projects/team-board/web-client-vite
npm install
npm run dev
```
**Agent (Picogent):**
```bash
cd /root/projects/team-board/picogent
npm install
npm run build
npm run start --config agent.json
```
### 14.2 Docker деплой
**Сборка:**
```bash
docker-compose build
```
**Запуск:**
```bash
docker-compose up -d
```
**Логи:**
```bash
docker-compose logs -f tracker
```
**Остановка:**
```bash
docker-compose down
```
### 14.3 Миграции БД
**Создание миграции:**
```bash
alembic revision --autogenerate -m "Add new table"
alembic upgrade head
```
**Откат:**
```bash
alembic downgrade -1
```
**История:**
```bash
alembic history
```
### 14.4 Переменные окружения
**Tracker (.env):**
```bash
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):**
```bash
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
```
**Пример:**
```python
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"
```
**Запуск:**
```bash
pytest tests/ -v
pytest tests/ --cov=app
```
### 15.2 Frontend тесты
**Стек:** Vitest, React Testing Library
**Пример:**
```typescript
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()
})
```
**Запуск:**
```bash
npm run test
npm run test:coverage
```
### 15.3 E2E тесты
**Стек:** Playwright
**Пример:**
```typescript
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:**
```yaml
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 Оптимизации БД
**Индексы:**
```sql
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:**
```python
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 (будущее):**
```python
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
```python
# 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:**
```typescript
const KanbanBoard = lazy(() => import('./KanbanBoard'))
const Chat = lazy(() => import('./Chat'))
```
**Bundle analysis:**
```bash
npm run build -- --mode analyze
```
**Asset optimization:**
- Image compression (WebP)
- Lazy loading images
- Service Worker для offline
---
## 17. Безопасность
### 17.1 JWT Security
**Token rotation:**
```python
# 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:**
```python
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:**
```python
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 параметризованные запросы:**
```python
# ✅ Безопасно
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:**
```typescript
import DOMPurify from 'dompurify'
const SafeHTML = ({ content }) => (
<div dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(content)
}} />
)
```
### 17.5 Rate Limiting
**Slowapi:**
```python
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
**Настройка:**
```python
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
**Формат:**
```python
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:**
```python
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:**
```python
@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 интеграция:**
```python
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 Диагностика
**Проверка здоровья системы:**
```bash
# Backend
curl http://localhost:8100/api/health
# Database
psql -c "SELECT 1"
# Redis (если есть)
redis-cli ping
# Disk space
df -h /var/www/team-board
```
**Логи:**
```bash
# 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:**
```sql
-- Активные подключения
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 процедуры
**Восстановление БД:**
```bash
# Backup
pg_dump teamboard > backup_$(date +%Y%m%d).sql
# Restore
psql teamboard < backup_20260313.sql
```
**Откат миграции:**
```bash
alembic downgrade -1
```
**Перезапуск сервисов:**
```bash
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:**
```json
{
"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:**
```json
{
"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*