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:
parent
223be901aa
commit
cad887daf4
@ -1,7 +1,8 @@
|
|||||||
# Team Board — Полная Спецификация
|
# Team Board — Полная Спецификация (Aurora Edition)
|
||||||
|
|
||||||
Версия: 1.0
|
Версия: 1.1
|
||||||
Дата: 2026-03-13
|
Дата: 2026-03-13
|
||||||
|
Автор: Аврора
|
||||||
Статус: В разработке
|
Статус: В разработке
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -21,6 +22,13 @@
|
|||||||
11. [Инфраструктура](#11-инфраструктура)
|
11. [Инфраструктура](#11-инфраструктура)
|
||||||
12. [Функциональность](#12-функциональность)
|
12. [Функциональность](#12-функциональность)
|
||||||
13. [Дорожная карта](#13-дорожная-карта)
|
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*
|
*Документ поддерживается Авророй. Последнее обновление: 2026-03-13*
|
||||||
|
*Версия: Aurora Edition 1.1*
|
||||||
Loading…
Reference in New Issue
Block a user