Files
site/docs/TZ.md
T

1511 lines
60 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Техническое задание
## Платформа «Комптон» — React-приложение с модульной архитектурой
### Испольнителю следовать плану реализации с особым пристрастрием
**Версия документа:** 1.0
**Дата:** 09.07.2026
**Разработчик:** Huli
---
## Содержание
1. [Общие сведения](#1-общие-сведения)
2. [Цели и границы проекта](#2-цели-и-границы-проекта)
3. [Профиль нагрузки и масштабирование](#3-профиль-нагрузки-и-масштабирование)
4. [Технологический стек](#4-технологический-стек)
5. [Архитектура системы](#5-архитектура-системы)
6. [Модульная структура Frontend (React)](#6-модульная-структура-frontend-react)
7. [Модульная структура Backend (API)](#7-модульная-структура-backend-api)
8. [Модель данных](#8-модель-данных)
9. [API-контракты](#9-api-контракты)
10. [Аутентификация и авторизация](#10-аутентификация-и-авторизация)
11. [UI/UX и дизайн-система](#11-uiux-и-дизайн-система)
12. [Нефункциональные требования](#12-нефункциональные-требования)
13. [Инфраструктура и DevOps](#13-инфраструктура-и-devops)
14. [Безопасность](#14-безопасность)
15. [Тестирование и качество](#15-тестирование-и-качество)
16. [Этапы разработки](#16-этапы-разработки)
17. [Критерии приёмки](#17-критерии-приёмки)
18. [Риски и допущения](#18-риски-и-допущения)
---
## 1. Общие сведения
### 1.1. Наименование проекта
**Комптон®** — веб-платформа бренда «Organic Tech» с публичной витриной, личным кабинетом пользователя и административной панелью.
### 1.2. Текущее состояние
- Чисто поржать на ошибках и нейронке
- Заглушка на Flask (`main.py`) с одностраничным лендингом.
- Визуальная идентичность задана не полностью: цвета, шрифты (Inter, JetBrains Mono), hero-блок, бегущая строка.
- Рефакторинг текщего состояния не возможен, задача переписать проект.
- Функциональность отсутствует: нет регистрации, контента, API, БД.
### 1.3. Заказчик / продукт
Еблан который зовет себя Huli. Документ описывает целевую архитектуру для замены заглушки полноценным продуктом.
### 1.4. Термины
| Термин | Определение |
|--------|-------------|
| **Модуль (feature)** | Изолированный функциональный блок с собственными компонентами, API-слоем, типами и тестами |
| **Shared** | Переиспользуемый код без бизнес-логики конкретного модуля |
| **Core** | Ядро приложения: роутинг, провайдеры, конфигурация, HTTP-клиент |
| **MAU** | Monthly Active Users — уникальные пользователи за месяц |
| **CCU** | Concurrent Users — одновременно онлайн |
---
## 2. Цели и границы проекта
### 2.1. Бизнес-цели
1. Заменить заглушку работающим сайтом с сохранением бренда.
2. Обеспечить регистрацию и работу **до 1 000 зарегистрированных пользователей** (~100150 DAU) без деградации UX.
3. Заложить архитектуру, позволяющую масштабироваться до **10 000+ пользователей** без переписывания модулей.
4. Обеспечить независимую разработку модулей разными разработчиками.
5. **Каждый шаг реализации** (задача / PR / модуль) поставляется **только с полным набором тестов**: unit/integration логики + E2E пользовательских сценариев (§15).
### 2.2. Функциональный scope (MVP → v1.0)
#### MVP (фаза 1)
| Модуль | Функции |
|--------|---------|
| **Landing** | Hero, бегущая строка, «О бренде», контакты, SEO-мета |
| **Auth** | Регистрация, вход, выход, восстановление пароля, подтверждение email *(требует SMTP в MVP — см. §16)* |
| **Profile** | Просмотр/редактирование профиля, аватар, смена пароля |
| **Content** | Статические страницы (О нас, Политика, Условия) из CMS или markdown |
| **Admin** | Управление пользователями, контентом, просмотр метрик |
#### v1.0 (фаза 2, опционально)
| Модуль | Функции |
|--------|---------|
| **Catalog** | Каталог продуктов/услуг, карточки, фильтры |
| **Orders** | Корзина, оформление заявки (без оплаты — см. §2.3), история |
| **Notifications** | In-app уведомления; email-рассылки через очередь (Celery) |
| **Analytics** | Дашборд событий, экспорт |
### 2.3. Out of scope (не входит в v1.0)
- Мобильное нативное приложение (только responsive web).
- Мультиязычность (заложить i18n-структуру, реализовать позже).
- Платёжные шлюзы (интеграция — отдельный этап). Модуль Orders в v1.0 работает как **заявка/бронирование без оплаты**.
- Real-time чат / WebRTC.
---
## 3. Профиль нагрузки и масштабирование
### 3.1. Целевые метрики (1000 пользователей)
| Метрика | Значение | Комментарий |
|---------|----------|-------------|
| Зарегистрированных пользователей | 1 000 | Целевой объём на старте |
| DAU | 100150 (1015%) | Типичный коэффициент для B2C |
| CCU (пик) | 30–50 | Одновременные сессии |
| RPS API (пик) | 2050 req/s | С запасом ×3 |
| Размер БД | < 5 GB | Профили, контент, логи |
| Медиа | < 50 GB | CDN для статики |
### 3.2. Путь масштабирования
```mermaid
flowchart LR
subgraph phase1 [Фаза 1: до 1K]
A1[Monolith API]
A2[PostgreSQL]
A3[Redis cache]
A4[CDN static]
end
subgraph phase2 [Фаза 2: 1K10K]
B1[2× API instances]
B2[Read replica PG]
B3[Redis cluster]
B4[Object storage S3]
end
subgraph phase3 [Фаза 3: 10K+]
C1[Horizontal API scale]
C2[Extract heavy modules]
C3[Message queue]
C4[Separate admin]
end
phase1 --> phase2 --> phase3
```
**Принцип:** на 1000 пользователей достаточно **модульного монолита** (один backend-процесс, чёткие границы модулей). Микросервисы не нужны до 10K+ и только для узких «тяжёлых» модулей (уведомления, аналитика).
### 3.3. SLA (целевые)
| Параметр | MVP | v1.0 |
|----------|-----|------|
| Uptime | 99.5% | 99.9% |
| TTFB публичных страниц | < 500 ms | < 300 ms |
| API p95 latency | < 300 ms | < 200 ms |
| LCP (Lighthouse mobile) | < 2.5 s | < 2.0 s |
---
## 4. Технологический стек
### 4.1. Frontend
| Слой | Технология | Обоснование |
|------|------------|-------------|
| Framework | **React 19** + **TypeScript 5** | Экосистема, типизация |
| Bundler | **Vite 6** | Быстрая сборка, HMR |
| Routing | **React Router 7** | Стандарт de facto |
| Server state | **TanStack Query 5** | Кеш, retry, invalidation |
| Client state | **Zustand** | Лёгкий, без boilerplate |
| Forms | **React Hook Form** + **Zod** | Валидация, DX |
| UI | **Tailwind CSS 4** + headless (Radix UI) | Соответствие дизайн-системе |
| HTTP | **Axios** или fetch-обёртка | Interceptors, типизация |
| i18n (заготовка) | **react-i18next** | Структура без реализации |
| Tests | **Vitest** + **Testing Library** + **Playwright** + **pytest** | Unit + integration + E2E на каждом PR (§15) |
### 4.2. Backend
| Слой | Технология | Обоснование |
|------|------------|-------------|
| Runtime | **Python 3.12** | Преемственность Flask-проекта |
| Framework | **FastAPI** | Async, OpenAPI, производительность |
| ORM | **SQLAlchemy 2** + **Alembic** | Миграции, типизация |
| Validation | **Pydantic v2** | Согласованность с OpenAPI |
| Auth | **JWT** (access + refresh rotation) + **passlib/bcrypt** | Stateless access, revocable refresh |
| Task queue (v1.0) | **Celery** + Redis | Email, фоновые задачи |
| Email | **SMTP** / SendGrid / Resend | MVP: синхронная отправка verify/reset; v1.0: Celery queue |
### 4.3. Data & Infra
| Компонент | Технология |
|-----------|------------|
| Primary DB | **PostgreSQL 16** |
| Cache / sessions | **Redis 7** |
| File storage | **S3-compatible** (MinIO dev / Yandex S3 / AWS prod) |
| Reverse proxy | **Nginx** |
| Containerization | **Docker** + **Docker Compose** (dev/staging) |
| CI/CD | **GitHub Actions** |
| Monitoring | **Prometheus** + **Grafana** (или managed: Datadog) |
| Logging | Structured JSON → **Loki** или cloud logs |
| Error tracking | **Sentry** |
### 4.4. Архитектурный стиль Frontend
**Feature-Sliced Design (FSD)** — адаптированная версия с явными модулями:
```
app → pages → modules → shared
```
- **app** — инициализация, провайдеры, глобальный роутер.
- **pages** — композиция модулей в маршруты (тонкий слой).
- **modules** — бизнес-фичи (auth, profile, catalog…).
- **shared** — UI-kit, utils, API client, types без доменной логики.
---
## 5. Архитектура системы
### 5.1. Общая схема
```mermaid
flowchart TB
subgraph client [Клиент]
Browser[Browser / Mobile Web]
SPA[React SPA]
end
subgraph edge [Edge]
CDN[CDN — static assets]
Nginx[Nginx — TLS, gzip, rate limit]
end
subgraph backend [Backend]
API[FastAPI Monolith]
subgraph modules_api [Modules]
M1[auth]
M2[users]
M3[content]
M4[admin]
end
end
subgraph data [Data Layer]
PG[(PostgreSQL)]
Redis[(Redis)]
S3[(Object Storage)]
end
Browser --> CDN
Browser --> Nginx
Nginx -->|static| SPA
SPA -->|REST JSON /api| Nginx
Nginx --> API
API --> modules_api
modules_api --> PG
modules_api --> Redis
modules_api --> S3
```
### 5.2. Принципы модульности
1. **Вертикальные срезы** — каждый модуль владеет UI + API + схемой БД (таблицы через общий ORM, но namespace по модулю).
2. **Запрет cross-import между modules** — общение только через:
- публичный API модуля (`modules/auth/api/index.ts`);
- shared-слой;
- backend REST/events.
3. **Публичный контракт модуля**`index.ts` экспортирует только то, что нужно снаружи.
4. **Приватная реализация**`internal/` не импортируется из других модулей.
### 5.3. Репозиторий (monorepo-lite)
```
compton/
├── apps/
│ ├── web/ # React SPA
│ └── api/ # FastAPI
├── packages/
│ ├── shared-types/ # OpenAPI-generated TS types
│ └── eslint-config/ # Общие lint rules
├── infra/
│ ├── docker/
│ ├── nginx/
│ └── terraform/ # опционально
├── docs/
│ └── TZ.md
└── docker-compose.yml
```
На старте допустим **single repo** без Turborepo; `packages/shared-types` генерируется из OpenAPI при CI.
---
## 6. Модульная структура Frontend (React)
### 6.1. Дерево каталогов `apps/web/src`
```
src/
├── app/
│ ├── App.tsx
│ ├── providers/
│ │ ├── QueryProvider.tsx
│ │ ├── AuthProvider.tsx
│ │ └── ThemeProvider.tsx
│ ├── router/
│ │ ├── routes.tsx
│ │ └── guards/
│ │ ├── AuthGuard.tsx
│ │ └── AdminGuard.tsx
│ └── styles/
│ └── globals.css
├── pages/
│ ├── HomePage/
│ ├── LoginPage/
│ ├── RegisterPage/
│ ├── ProfilePage/
│ ├── ContentPage/
│ └── AdminPage/
├── modules/
│ ├── landing/
│ │ ├── index.ts # public API
│ │ ├── components/
│ │ │ ├── HeroSection.tsx
│ │ │ └── MarqueeSection.tsx
│ │ ├── hooks/
│ │ └── types/
│ │
│ ├── auth/
│ │ ├── index.ts
│ │ ├── api/
│ │ │ └── authApi.ts
│ │ ├── components/
│ │ │ ├── LoginForm.tsx
│ │ │ └── RegisterForm.tsx
│ │ ├── hooks/
│ │ │ ├── useLogin.ts
│ │ │ └── useAuth.ts
│ │ ├── store/
│ │ │ └── authStore.ts
│ │ └── types/
│ │
│ ├── profile/
│ │ ├── index.ts
│ │ ├── api/
│ │ ├── components/
│ │ ├── hooks/
│ │ └── types/
│ │
│ ├── content/
│ │ ├── index.ts
│ │ ├── api/
│ │ ├── components/
│ │ └── hooks/
│ │
│ ├── admin/
│ │ ├── index.ts
│ │ ├── api/
│ │ ├── components/
│ │ └── hooks/
│ │
│ └── catalog/ # v1.0
│ └── ...
├── __tests__/ # cross-module integration (frontend)
│ └── setup.ts
└── shared/
├── api/
│ ├── client.ts
│ ├── client.test.ts
│ ├── errors.ts
│ └── types.ts
├── ui/
│ ├── Button/
│ │ ├── Button.tsx
│ │ └── Button.test.tsx
│ └── ...
└── ...
# Каждый module обязан содержать:
modules/<name>/
├── __tests__/ # unit: hooks, utils, store
├── components/
│ └── *.test.tsx # component tests (Testing Library)
└── api/
└── *.test.ts # API client + mock handlers
```
### 6.2. Правила зависимостей (import rules)
```mermaid
flowchart TD
app --> pages
pages --> modules
modules --> shared
modules -.->|FORBIDDEN| modules
shared -.->|FORBIDDEN| modules
shared -.->|FORBIDDEN| pages
```
Enforcement через **ESLint** (`eslint-plugin-boundaries` или custom rules):
| From → To | app | pages | modules | shared |
|-----------|-----|-------|---------|--------|
| app | ✓ | ✓ | ✓ | ✓ |
| pages | — | ✓ | ✓ | ✓ |
| modules | — | — | ✓ (own) | ✓ |
| shared | — | — | ✗ | ✓ |
### 6.3. Описание модулей Frontend
#### 6.3.1. `landing`
**Ответственность:**
- Буду ебать за каждый нейрослоп
**Зависимости:** только `shared/ui`, `shared/hooks`.
#### 6.3.2. `auth`
**Ответственность:** аутентификация, сессия, guards.
| Export (public API) | Описание |
|---------------------|----------|
| `LoginForm`, `RegisterForm` | Формы |
| `useAuth()` | `{ user, isAuthenticated, login, logout, refreshSession }` |
**Guards** (`AuthGuard`, `GuestGuard`, `AdminGuard`) живут в `app/router/guards/` — они **импортируют** `useAuth` из модуля `auth`, но не экспортируются из него (слой `app` композирует модули).
**Store:** `accessToken` только in-memory (Zustand). `refreshToken` **только** httpOnly Secure cookie (`SameSite=Lax`). Хранение refresh в `localStorage` / `sessionStorage` **запрещено**.
#### 6.3.3. `profile`
**Ответственность:** CRUD профиля пользователя.
| Функции | API endpoints |
|---------|---------------|
| Просмотр профиля | `GET /api/v1/users/me` |
| Редактирование | `PATCH /api/v1/users/me` |
| Смена пароля (авторизован) | `POST /api/v1/users/me/password` |
| Загрузка аватара | `POST /api/v1/users/me/avatar` |
#### 6.3.4. `content`
**Ответственность:** рендер CMS-страниц по slug. Запись — только для `admin` (через те же роуты с RBAC-проверкой; отдельный `admin`-модуль не дублирует CRUD контента).
| Функции | Описание |
|---------|----------|
| `ContentPage` | `/about`, `/privacy`, `/terms` |
| SEO | meta title, description, og:image |
#### 6.3.5. `admin`
**Ответственность:** панель администратора (role: `admin`).
| Раздел | Функции |
|--------|---------|
| Users | список, блокировка, смена роли *(с ограничениями — §14.10)* |
| Content | — *(CRUD контента — модуль `content`, §9.4)* |
| Dashboard | базовые метрики (users count, registrations/day) |
### 6.4. Роутинг
| Маршрут | Page | Guard | Модуль(и) |
|---------|------|-------|-----------|
| `/` | HomePage | — | landing |
| `/login` | LoginPage | guest only | auth |
| `/register` | RegisterPage | guest only | auth |
| `/profile` | ProfilePage | AuthGuard | profile |
| `/pages/:slug` | ContentPage | — | content |
| `/admin/*` | AdminPage | AdminGuard | admin |
### 6.5. Code splitting
- Lazy load: `admin`, `profile`, `catalog`.
- Prefetch on hover для `/login`, `/register`.
- Landing — в initial bundle (LCP-critical).
---
## 7. Модульная структура Backend (API)
### 7.1. Дерево каталогов `apps/api`
```
app/
├── main.py # FastAPI app factory
├── core/
│ ├── config.py
│ ├── database.py
│ ├── redis.py
│ ├── security.py # JWT, password hashing
│ ├── dependencies.py # get_db, get_current_user
│ └── exceptions.py
├── modules/
│ ├── auth/
│ │ ├── router.py
│ │ ├── service.py
│ │ ├── schemas.py
│ │ └── repository.py
│ │
│ ├── users/
│ │ ├── router.py
│ │ ├── service.py
│ │ ├── models.py
│ │ ├── schemas.py
│ │ └── repository.py
│ │
│ ├── content/
│ │ ├── router.py
│ │ ├── service.py
│ │ ├── models.py
│ │ └── schemas.py
│ │
│ ├── media/
│ │ ├── router.py
│ │ ├── service.py # S3 upload
│ │ └── schemas.py
│ │
│ └── admin/
│ ├── router.py
│ ├── service.py
│ └── schemas.py
├── migrations/ # Alembic
└── tests/
├── conftest.py # fixtures: db, client, test users
├── factories.py # user/content factories
├── modules/
│ ├── auth/
│ │ ├── test_service.py # unit: бизнес-логика
│ │ ├── test_router.py # integration: HTTP + DB
│ │ └── test_security.py # rotation, lockout, enumeration
│ ├── users/
│ ├── content/
│ └── admin/
└── e2e/ # pytest API smoke (optional layer)
└── test_health.py
```
### 7.2. Слои внутри модуля (Clean Architecture lite)
```
Router → Service → Repository → Model
Schemas (Pydantic)
```
| Слой | Ответственность |
|------|-----------------|
| **Router** | HTTP, status codes, dependency injection |
| **Service** | Бизнес-логика, orchestration |
| **Repository** | SQL-запросы, абстракция БД |
| **Schemas** | Request/Response DTO |
| **Models** | SQLAlchemy ORM |
**Правило:** модуль не импортирует `repository` другого модуля. Межмодульные вызовы — только через **публичный `service`-фасад** (например, `users.public.get_by_id()`) или domain events.
### 7.3. Версионирование API
- Префикс: `/api/v1/`
- Breaking changes → `/api/v2/`
- OpenAPI: `/api/v1/openapi.json`
- Swagger UI: `/api/v1/docs` (только dev/staging)
---
## 8. Модель данных
### 8.1. ER-диаграмма (MVP)
```mermaid
erDiagram
users ||--o| user_profiles : has
users ||--o{ refresh_tokens : has
users ||--o{ password_reset_tokens : has
users ||--o{ content_pages : creates
users {
uuid id PK
string email UK
string password_hash
enum role "user|admin"
enum status "active|blocked|pending"
timestamp email_verified_at
int failed_login_attempts
timestamp locked_until
timestamp created_at
timestamp updated_at
}
user_profiles {
uuid user_id PK,FK
string display_name
string avatar_url
json metadata
}
refresh_tokens {
uuid id PK
uuid user_id FK
string token_hash UK
uuid family_id
timestamp expires_at
timestamp revoked_at
timestamp created_at
}
password_reset_tokens {
uuid id PK
uuid user_id FK
string token_hash UK
timestamp expires_at
timestamp used_at
}
content_pages {
uuid id PK
string slug UK
string title
text body
enum status "draft|published"
uuid author_id FK
timestamp published_at
timestamp updated_at
}
```
### 8.2. Индексы
```sql
CREATE UNIQUE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_status ON users(status);
CREATE INDEX idx_content_slug ON content_pages(slug);
CREATE INDEX idx_content_status ON content_pages(status);
CREATE INDEX idx_refresh_tokens_user ON refresh_tokens(user_id);
CREATE INDEX idx_refresh_tokens_family ON refresh_tokens(family_id);
CREATE INDEX idx_password_reset_user ON password_reset_tokens(user_id);
```
### 8.3. Миграции
- Alembic, одна миграция = одна логическая задача.
- Rollback обязателен для каждой миграции.
- Seed: admin user, demo content pages.
---
## 9. API-контракты
### 9.1. Общие соглашения
| Аспект | Стандарт |
|--------|----------|
| Format | JSON, UTF-8 |
| Dates | ISO 8601 UTC (`2026-07-09T12:00:00Z`) |
| IDs | UUID v4 |
| Pagination | `?page=1&limit=20`, response: `{ data, meta: { total, page, limit } }` |
| Errors | `{ "error": { "code": "VALIDATION_ERROR", "message": "...", "details": [] } }` |
### 9.2. Auth endpoints
| Method | Path | Auth | Описание |
|--------|------|------|----------|
| POST | `/api/v1/auth/register` | — | Регистрация → `status: pending`, письмо с подтверждением |
| POST | `/api/v1/auth/login` | — | Вход → access в body, refresh в `Set-Cookie` |
| POST | `/api/v1/auth/refresh` | refresh cookie | Новая пара access + refresh (rotation) |
| POST | `/api/v1/auth/logout` | refresh cookie | Revoke token family, очистка cookie |
| POST | `/api/v1/auth/verify-email` | — | Body: `{ "token": "..." }``status: active` |
| POST | `/api/v1/auth/resend-verification` | — | Повторная отправка (rate limited) |
| POST | `/api/v1/auth/forgot-password` | — | Отправка reset-link (без раскрытия наличия email) |
| POST | `/api/v1/auth/reset-password` | — | Смена пароля по одноразовому token |
**Правила ответов auth (anti-enumeration):**
- `register` с существующим email → **200** с нейтральным телом *или* **409** без указания причины в prod (на выбор; зафиксировать в реализации).
- `forgot-password` → всегда **200** «Если email зарегистрирован, письмо отправлено».
- `login` при неверных данных → **401** с общим сообщением «Неверный email или пароль».
- `login` при `status: pending`**403** `EMAIL_NOT_VERIFIED`.
- `login` при `status: blocked`**403** `ACCOUNT_BLOCKED`.
- `login` при блокировке brute-force → **429** `ACCOUNT_TEMPORARILY_LOCKED`.
**Response login (200):**
```json
{
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 900,
"user": {
"id": "uuid",
"email": "user@example.com",
"role": "user",
"status": "active"
}
}
```
**Set-Cookie (login / refresh — обязательно):**
```
Set-Cookie: refresh_token=<opaque>; HttpOnly; Secure; SameSite=Lax; Path=/api/v1/auth; Max-Age=2592000
```
> Refresh token **никогда** не возвращается в JSON-body.
### 9.3. Users endpoints
| Method | Path | Auth | Описание |
|--------|------|------|----------|
| GET | `/api/v1/users/me` | user | Текущий пользователь + profile |
| PATCH | `/api/v1/users/me` | user | Обновление профиля (whitelist полей) |
| POST | `/api/v1/users/me/password` | user | `{ current_password, new_password }` |
| POST | `/api/v1/users/me/avatar` | user | multipart upload |
| DELETE | `/api/v1/users/me` | user | Удаление аккаунта (v1.0, soft-delete + anonymize) |
### 9.4. Content endpoints
| Method | Path | Auth | Описание |
|--------|------|------|----------|
| GET | `/api/v1/content/pages` | — | Список published pages |
| GET | `/api/v1/content/pages/{slug}` | — | Страница по slug |
| POST | `/api/v1/content/pages` | admin | Создание |
| PATCH | `/api/v1/content/pages/{id}` | admin | Обновление |
| DELETE | `/api/v1/content/pages/{id}` | admin | Удаление |
### 9.5. Admin endpoints
| Method | Path | Auth | Описание |
|--------|------|------|----------|
| GET | `/api/v1/admin/users` | admin | Список пользователей (pagination, без password_hash) |
| PATCH | `/api/v1/admin/users/{id}` | admin | Блокировка, смена роли *(§14.10)* |
| GET | `/api/v1/admin/stats` | admin | Базовые метрики |
| GET | `/api/v1/admin/audit-log` | admin | Журнал действий админов (v1.0) |
### 9.6. Rate limiting
| Endpoint group | Limit | Key |
|----------------|-------|-----|
| Auth: login | 5 req/min | IP + email (composite) |
| Auth: register | 3 req/hour | IP |
| Auth: forgot-password, resend-verification | 3 req/hour | IP + email |
| Auth: refresh | 30 req/min | user_id (из token) |
| Public API | 100 req/min | IP |
| Authenticated API | 300 req/min | user_id (fallback: IP) |
| Upload (avatar) | 10 req/hour | user_id |
При превышении → **429** + заголовок `Retry-After`.
**Brute-force (login):** после 5 неудачных попыток за 15 мин — `locked_until = now + 15 min` (поле в `users`).
---
## 10. Аутентификация и авторизация
### 10.1. JWT Strategy
| Token | Формат | TTL | Storage | Передача |
|-------|--------|-----|---------|----------|
| Access | JWT (HS256 или RS256) | 15 min | In-memory (JS) | `Authorization: Bearer` |
| Refresh | Opaque random (256 bit) | 30 days | httpOnly Secure cookie | Cookie `refresh_token` |
**Claims access JWT:** `sub` (user_id), `role`, `iat`, `exp`, `jti` (уникальный ID для optional denylist).
**Refresh token:**
- В БД хранится **только SHA-256 hash**, не plaintext.
- **Rotation:** каждый `/auth/refresh` выдаёт новый refresh, старый revoke.
- **Reuse detection:** повторное использование revoked token → revoke всей `family_id`, принудительный logout на всех устройствах.
- Cookie `Path=/api/v1/auth` — не отправляется на остальные API-роуты (минимизация поверхности CSRF).
### 10.2. RBAC
| Role | Permissions |
|------|-------------|
| `guest` | Чтение опубликованного контента |
| `user` (`status: active`) | Управление своим профилем |
| `admin` | Управление пользователями, контентом, stats; **не может** изменить собственную роль (§14.10) |
**Проверка на каждом protected endpoint:**
1. Валидный access JWT (подпись, exp, jti).
2. Пользователь существует и `status != blocked`.
3. Для admin-роутов — `role == admin`.
4. Для user-роутов — `sub == resource owner` (защита от IDOR).
`pending`-пользователь может вызвать только: verify-email, resend-verification, logout.
### 10.3. Password policy
- Минимум 8 символов, 1 uppercase, 1 lowercase, 1 digit.
- Denylist топ-10k паролей (Have I Been Pwned или локальный список).
- bcrypt, cost factor 12.
- Reset/verify token: 256 bit random, **hash в БД**, TTL 1 hour, одноразовый.
- При смене/сбросе пароля — revoke все `refresh_tokens` пользователя.
### 10.4. CORS и credentials
```python
# FastAPI CORSMiddleware
allow_origins = CORS_ORIGINS # whitelist, без wildcard в prod
allow_credentials = True # обязательно для refresh cookie
allow_methods = ["GET", "POST", "PATCH", "DELETE", "OPTIONS"]
allow_headers = ["Authorization", "Content-Type", "X-Request-ID"]
```
Frontend HTTP-клиент: `withCredentials: true` только для auth-запросов (login, refresh, logout).
### 10.5. CSRF (cookie-based refresh)
| Механизм | Применение |
|----------|------------|
| `SameSite=Lax` на refresh cookie | Блокирует cross-site POST в большинстве браузеров |
| `Path=/api/v1/auth` | Cookie не уходит на PATCH/POST других ресурсов |
| Проверка `Origin` / `Referer` на auth-роутах | Backend отклоняет запросы с чужого origin |
| Access JWT в header (не cookie) | State-changing API через Bearer не уязвим к CSRF |
Дополнительный CSRF-token **не требуется** при соблюдении схемы выше. Если refresh cookie когда-либо расширят на весь `/api` — добавить double-submit CSRF token.
---
## 11. UI/UX и дизайн-система
### 11.1. Design tokens (из текущей заглушки)
```css
:root {
--bg: #F6F6F4;
--foreground: #1A1E1C;
--primary: #48816D;
--muted: #4A5A52;
--marquee-bg: #EBEBE5;
}
```
### 11.2. Типографика
| Назначение | Шрифт |
|------------|-------|
| UI / body | Inter (400, 500, 600) |
| Mono / акценты | JetBrains Mono (400, 500) |
| Декоративный (опционально) | Oktyabrina Script |
### 11.3. Breakpoints
| Token | Width |
|-------|-------|
| `sm` | 380px |
| `md` | 480px |
| `lg` | 768px |
| `xl` | 1024px |
| `2xl` | 1280px |
### 11.4. Компоненты shared/ui (MVP)
- Button (primary, secondary, ghost)
- Input, Textarea
- Label, ErrorMessage
- Card, Modal, Spinner
- Header, Footer, Container
- Avatar, Badge
### 11.5. Accessibility
- WCAG 2.1 AA для MVP.
- Keyboard navigation, focus visible.
- `alt` для всех изображений.
- `prefers-reduced-motion` — отключение marquee-анимации.
---
## 12. Нефункциональные требования
### 12.1. Performance
| Метрика | Target |
|---------|--------|
| Initial JS bundle (landing) | < 150 KB gzip |
| Total JS (app loaded) | < 350 KB gzip |
| API cache (public content) | Redis TTL 5 min |
| Static assets | CDN, cache-control 1 year (hash in filename) |
### 12.2. SEO
- SSR/SSG **не обязателен** для MVP (SPA + prerender landing через Vite SSG plugin).
- Meta tags, sitemap.xml, robots.txt.
- Semantic HTML (`header`, `main`, `section`).
### 12.3. Observability
| Signal | Tool |
|--------|------|
| Logs | JSON structured, correlation-id |
| Metrics | request duration, error rate, DB pool |
| Traces | OpenTelemetry (optional v1.0) |
| Frontend errors | Sentry browser SDK |
### 12.4. Backup & Recovery
- PostgreSQL: daily backup, retention 30 days.
- RPO: 24 hours, RTO: 4 hours (на 1000 users достаточно).
---
## 13. Инфраструктура и DevOps
### 13.1. Окружения
| Env | Назначение | URL |
|-----|------------|-----|
| local | разработка | localhost:5173 (web), :8000 (api) |
| staging | QA, demo | staging.compton.example |
| production | prod | compton.example |
### 13.2. Docker Compose (local)
```yaml
services:
web:
build: ./apps/web
ports: ["5173:5173"]
api:
build: ./apps/api
ports: ["8000:8000"]
depends_on: [postgres, redis]
postgres:
image: postgres:16
redis:
image: redis:7-alpine
minio:
image: minio/minio # S3-compatible dev
# apps/web/e2e/ — Playwright specs (§15.3)
# docker-compose.test.yml — postgres + redis + api + web для CI/E2E
```
### 13.3. CI/CD Pipeline
```mermaid
flowchart LR
Push[Git Push / PR] --> Lint[Lint + Typecheck]
Lint --> Unit[Unit + Integration]
Unit --> Cov{Coverage ≥ threshold?}
Cov -->|No| Block1[❌ Block merge]
Cov -->|Yes| Build[Build Docker]
Build --> DeployStaging[Deploy Staging]
DeployStaging --> E2E[Playwright E2E]
E2E --> E2EPass{All E2E pass?}
E2EPass -->|No| Block2[❌ Block merge]
E2EPass -->|Yes| Review[Code Review]
Review --> ManualApprove[Manual Approve]
ManualApprove --> DeployProd[Deploy Production]
```
**Checks на каждый PR (обязательны, merge заблокирован при падении):**
| Gate | Команда | Условие pass |
|------|---------|--------------|
| Lint | `eslint`, `ruff`, `prettier --check` | 0 errors |
| Types | `tsc --noEmit`, `mypy` | 0 errors |
| Unit (FE) | `vitest run --coverage` | ≥ порогов §15.2 |
| Unit + Integration (BE) | `pytest --cov=app --cov-fail-under=...` | ≥ порогов §15.2 |
| OpenAPI | schema diff | no breaking без bump version |
| E2E | `playwright test` | 100% pass, 0 flaky retries exhausted |
| Security | `pip-audit`, `npm audit`, gitleaks | no unwaived critical |
> **Правило:** PR без тестов на изменённую логику **не ревьюится** и **не мержится**.
### 13.4. Production topology (1000 users)
```
1× VPS (4 vCPU, 8 GB RAM) или managed PaaS
├── Nginx
├── API container (uvicorn, 2 workers)
├── Web static (built SPA)
├── PostgreSQL (managed или co-located)
└── Redis (managed или co-located)
```
**Запас на рост:** второй API instance за load balancer при CPU > 70% sustained.
---
## 14. Безопасность
### 14.1. Threat model (STRIDE, MVP)
| Угроза | Вектор | Митигация |
|--------|--------|-----------|
| **Spoofing** | Подделка JWT / session | Подпись JWT, короткий TTL, rotation refresh |
| **Tampering** | Изменение чужих данных | RBAC + owner check (`sub == user_id`) |
| **Repudiation** | Отрицание admin-действий | Audit log (v1.0), correlation-id в логах |
| **Information disclosure** | Enumeration email, утечка PII | Anti-enumeration (§9.2), маскировка логов |
| **Denial of service** | Flood login/register | Rate limit + account lockout (§9.6) |
| **Elevation of privilege** | user → admin | RBAC middleware, admin self-edit запрещён |
**Trust boundaries:**
1. Browser (недоверенный) ↔ Nginx (TLS termination)
2. Nginx ↔ API (internal network / docker network)
3. API ↔ PostgreSQL / Redis / S3 (credentials via env)
### 14.2. Transport и security headers
**Обязательно в production (Nginx / middleware):**
| Header | Значение |
|--------|----------|
| `Strict-Transport-Security` | `max-age=31536000; includeSubDomains` |
| `X-Content-Type-Options` | `nosniff` |
| `X-Frame-Options` | `DENY` |
| `Referrer-Policy` | `strict-origin-when-cross-origin` |
| `Permissions-Policy` | `camera=(), microphone=(), geolocation=()` |
| `Content-Security-Policy` | см. §14.3 |
- TLS 1.2+ only, сильные cipher suites.
- Swagger UI (`/docs`) и OpenAPI JSON — **отключены в production** (env flag `ENABLE_DOCS=false`).
### 14.3. Content Security Policy
```
default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' data: https://<cdn-domain>;
connect-src 'self' https://<api-domain>;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
```
- Inline scripts в SPA — через nonce или только bundled (Vite).
- Google Fonts — допустимое исключение; при ужесточении CSP — self-host шрифтов.
### 14.4. XSS и инъекции
| Поверхность | Защита |
|-------------|--------|
| React UI | Auto-escaping JSX |
| CMS `content_pages.body` (HTML) | Server-side sanitize (**bleach** / **nh3**) + client DOMPurify allowlist перед `dangerouslySetInnerHTML` |
| User input (profile) | Pydantic validation, max length, strip control chars |
| SQL | SQLAlchemy ORM, parameterized queries; raw SQL запрещён без review |
| Log injection | Structured JSON logging, sanitize `\n\r` в user input |
**Allowlist HTML-тегов CMS:** `p, h1-h4, ul, ol, li, a, strong, em, br, img` — без `script`, `iframe`, `on*` attributes.
### 14.5. IDOR и авторизация
| Endpoint | Правило |
|----------|---------|
| `GET/PATCH /users/me` | `current_user.id` из JWT, не из body |
| `POST /users/me/avatar` | только свой user_id |
| `PATCH /admin/users/{id}` | admin + business rules (§14.10) |
| `GET /content/pages/{slug}` | только `status=published` для non-admin |
| `PATCH /content/pages/{id}` | admin only; проверка существования id |
**Запрещено:** принимать `user_id` / `role` из request body для повышения привилегий.
### 14.6. Загрузка файлов (avatar)
| Проверка | Значение |
|----------|----------|
| Max size | 2 MB |
| MIME (whitelist) | `image/jpeg`, `image/png`, `image/webp` |
| Magic bytes | python-magic / file signature check |
| Filename | UUID + ext, без user-supplied path |
| Storage | S3 private bucket; URL — signed / через CDN proxy |
| Processing | Re-encode (Pillow) для удаления EXIF и embedded payload |
**Запрещено:** SVG upload (XSS vector), исполнение файлов на сервере.
### 14.7. Secrets и криптография
| Secret | Хранение | Rotation |
|--------|----------|----------|
| `JWT_ACCESS_SECRET` | env / vault | при компрометации, quarterly |
| `JWT_REFRESH_PEPPER` | env / vault | отдельный от access secret |
| DB credentials | env / managed DB | managed rotation |
| S3 keys | IAM role (preferred) или env | quarterly |
- `.env` в `.gitignore`; `.env.example` без реальных значений.
- Pre-commit hook / CI: **gitleaks** или **trufflehog**.
- JWT secret ≥ 256 bit entropy.
### 14.8. Сессии и logout
- **Logout:** revoke refresh token family + clear cookie (`Max-Age=0`).
- **Password change / reset:** revoke **все** refresh tokens пользователя.
- **Block user (admin):** revoke tokens немедленно.
- Optional: Redis denylist для access JWT by `jti` до exp (для instant revoke admin-сессий).
### 14.9. Логирование и PII
**Логировать:**
- `request_id`, method, path, status, duration, user_id (if auth), IP (hashed в prod опционально).
**Не логировать:**
- Passwords, tokens, reset links, full email в debug (mask: `u***@example.com`).
**Retention:** application logs 30 days; audit log admin-действий 1 year.
### 14.10. Admin security rules
| Правило | Описание |
|---------|----------|
| Last admin | Нельзя удалить/понизить последнего admin |
| Self-demotion | Admin не может снять с себя роль admin |
| Self-block | Admin не может заблокировать себя |
| Role escalation | Только admin может назначать admin; 2FA для admin — v1.0 (recommended) |
| Seed admin | Создаётся миграцией; пароль из env при первом deploy, затем смена |
### 14.11. Supply chain
- Dependabot / Renovate — auto PR на CVE.
- CI: `pip-audit` (backend), `npm audit` (frontend), **Trivy** scan Docker images.
- Pin dependencies (`poetry.lock`, `package-lock.json`).
- Block merge при critical/high без explicit waiver.
### 14.12. GDPR / 152-ФЗ
| Требование | Реализация |
|------------|------------|
| Согласие | Checkbox при регистрации + ссылка на политику |
| Политика конфиденциальности | CMS-страница `/privacy` |
| Право на удаление | `DELETE /users/me` (v1.0): soft-delete, anonymize PII, retain audit/legal minimum |
| Data minimization | `metadata` json — только необходимые поля |
| Хранение | RU/EU region hosting (допущение §18.1) |
| Breach notification | Runbook в docs (v1.0) |
### 14.13. Security checklist (pre-production)
- [ ] HTTPS + HSTS
- [ ] CSP, security headers (§14.2)
- [ ] CORS whitelist, `allow_credentials` только для trusted origins
- [ ] Refresh: httpOnly, Secure, SameSite, Path, rotation + reuse detection
- [ ] Access JWT in memory only
- [ ] Anti-enumeration на auth endpoints
- [ ] Rate limiting + brute-force lockout
- [ ] IDOR tests на все `/me` и admin routes
- [ ] File upload validation + private S3
- [ ] CMS HTML sanitization
- [ ] Secrets not in git; gitleaks in CI
- [ ] Swagger disabled in prod
- [ ] Dependency scan clean (no unwaived critical)
- [ ] OWASP ASVS Level 1 review
- [ ] Sentry: scrub PII from breadcrumbs
### 14.14. Security testing (дополнение к §15)
| Тест | Tool / метод |
|------|--------------|
| SAST | Bandit (Python), ESLint security plugins |
| DAST | OWASP ZAP baseline scan на staging |
| Auth flows | pytest: token rotation, reuse detection, lockout |
| IDOR | pytest: user A cannot access user B |
| Fuzzing upload | Invalid MIME, oversized, polyglot files |
---
## 15. Тестирование и качество
> **Базовое правило проекта:** функция считается реализованной только когда поставлены **тесты логики** (unit + integration) **и E2E-сценарии** для затронутых пользовательских потоков. Исключений нет.
### 15.1. Пирамида и обязательные уровни
| Уровень | Что покрывает | Tools | Обязательность |
|---------|---------------|-------|----------------|
| **Unit** | service, repository, hooks, store, utils, pure components | Vitest, pytest | **Обязательно** на каждый PR с логикой |
| **Integration** | API routers + DB + Redis; form → API client | pytest + TestClient, MSW | **Обязательно** для backend и API-слоя frontend |
| **Component** | UI: render, a11y, user events | Testing Library | **Обязательно** для новых/изменённых компонентов |
| **E2E** | Сквозные user journeys в браузере | Playwright | **Обязательно** на каждый модуль / фазу (§15.5) |
| **Visual** | Landing regression | Percy/Chromatic | Опционально |
| **Load** | API под CCU | k6 | Перед релизом MVP/v1.0 |
| **Security** | auth, IDOR, upload | pytest + ZAP | Перед релизом (§14.14) |
### 15.2. Пороги покрытия (coverage gates)
Измерение: **line coverage** (Vitest v8 / pytest-cov). CI падает при падении ниже порога.
| Область | Минимум | Примечание |
|---------|---------|------------|
| `apps/api/app/modules/*/service.py` | **≥ 95%** | Бизнес-логика backend |
| `apps/api/app/modules/*/repository.py` | **≥ 90%** | SQL, edge cases |
| `apps/api/app/core/security.py` | **100%** | JWT, hash, lockout |
| `apps/web/src/modules/*/hooks`, `store`, `api` | **≥ 90%** | Логика frontend |
| `apps/web/src/shared/lib`, `shared/api` | **≥ 90%** | Общие утилиты |
| `apps/web/src/modules/*/components` | **≥ 80%** | UI; допускается исключать pure layout |
| **Overall backend** `app/` | **≥ 90%** | `--cov-fail-under=90` |
| **Overall frontend** `src/` | **≥ 85%** | `--coverage.thresholds.lines=85` |
**Diff coverage (рекомендуется):** новые/changed строки в PR — **≥ 95%** (Codecov / diff-cover).
**Критические модули** (`auth`, `admin`, `core/security`) — **100% branch coverage** для функций авторизации и token rotation.
### 15.3. Структура E2E (Playwright)
```
apps/web/e2e/
├── fixtures/
│ ├── auth.fixture.ts # login helpers, test users
│ └── api.fixture.ts # seed via API
├── landing/
│ └── landing.spec.ts
├── auth/
│ ├── register.spec.ts
│ ├── login.spec.ts
│ └── password-reset.spec.ts
├── profile/
│ └── profile.spec.ts
├── content/
│ └── content-pages.spec.ts
├── admin/
│ └── admin-users.spec.ts
└── playwright.config.ts
```
**Конфигурация:**
- Бrowsers: Chromium (CI), + Firefox/WebKit локально.
- Retry: 1 в CI только для infra flakes; повторный flake → bug.
- Trace/video: on-first-retry.
- Параллельность: по файлам, isolated test users.
- E2E против **staging** в CI post-deploy; PR — против docker-compose stack.
### 15.4. Матрица тестов по модулям (MVP)
Каждая строка — **минимальный обязательный набор** перед merge задачи.
| Модуль | Unit / Integration (логика) | E2E (Playwright) |
|--------|----------------------------|------------------|
| **landing** | Hero/Marquee render, breakpoints, reduced-motion | `/` загрузка, marquee visible, a11y snapshot |
| **auth** | register, login, refresh rotation, reuse detection, lockout, anti-enumeration, verify-email | register → verify → login; wrong password; pending/blocked redirect |
| **profile** | PATCH whitelist, avatar validation (MIME, size), IDOR | edit name, upload avatar, change password |
| **content** | slug unique, draft vs published, HTML sanitize | public page by slug; admin publish → visible |
| **admin** | last-admin rule, self-block forbidden, RBAC | admin list users, block user, blocked cannot login |
| **shared/ui** | Button, Input, Form validation states | используются в module E2E |
### 15.5. Тесты на каждом шаге реализации (workflow)
```mermaid
flowchart TD
Task[Задача из §16] --> Impl[Реализация]
Impl --> Unit[Unit tests]
Unit --> Int[Integration tests]
Int --> Comp[Component tests если UI]
Comp --> E2E[E2E spec для flow]
E2E --> CI[CI green]
CI --> DoD[Definition of Done §15.6]
DoD --> Merge[Merge allowed]
```
**Порядок TDD (рекомендуется, не optional для auth/security):**
1. Написать failing test (unit или e2e).
2. Реализовать минимальный код.
3. Довести coverage до порога.
4. Открыть PR — CI должен быть green.
**Запрещено:**
- Откладывать тесты «на потом» / отдельным PR.
- Merge с `@pytest.mark.skip` / `test.todo` / `it.skip` без linked issue и срока.
- Mock всего подряд в integration — DB/Redis должны быть real (testcontainers или docker-compose).
### 15.6. Definition of Done (модуль / задача)
- [ ] TypeScript strict / mypy — 0 errors
- [ ] **Unit tests** для всей новой/изменённой бизнес-логики
- [ ] **Integration tests** для новых/изменённых API endpoints
- [ ] **Component tests** для новых/изменённых React-компонентов
- [ ] **E2E spec** для затронутых user flows (§15.4)
- [ ] Coverage ≥ порогов §15.2 (CI enforced)
- [ ] API documented in OpenAPI
- [ ] ESLint boundaries pass
- [ ] Security tests пройдены (если модуль auth/admin/media)
- [ ] Code review approved
- [ ] 0 flaky E2E за 3 прогона CI
### 15.7. Critical E2E scenarios (регрессия релиза)
Полный прогон перед каждым релизом MVP/v1.0:
1. Landing: LCP < 2.5s, hero + marquee, `prefers-reduced-motion`.
2. Register → verify email → login → profile edit → change password → logout.
3. Forgot password → reset → login with new password.
4. Admin: create content → publish → visible on `/pages/:slug`.
5. Admin: block user → blocked user gets 403 on login.
6. Pending user cannot access `/profile`.
7. Refresh rotation: old refresh token rejected; reuse revokes family.
8. IDOR: user A cannot GET/PATCH user B profile.
9. Admin cannot demote/block self; last admin protected.
10. Avatar: reject .svg, oversize, wrong MIME.
### 15.8. Test data и изоляция
| Аспект | Правило |
|--------|---------|
| Test DB | Отдельная `compton_test`; транзакционный rollback per test |
| Seed users | factories.py: `user`, `admin`, `pending_user`, `blocked_user` |
| E2E users | Создаются через API fixture перед spec, cleanup after |
| Secrets in tests | Только `test-*` keys из `.env.test` |
| Parallel | Изolated data via UUID suffix emails |
### 15.9. Команды (локально)
```bash
# Frontend
pnpm --filter web test # vitest watch
pnpm --filter web test:ci # vitest run --coverage
pnpm --filter web e2e # playwright test
pnpm --filter web e2e:ui # playwright --ui
# Backend
cd apps/api && pytest # all
pytest tests/modules/auth -v # module
pytest --cov=app --cov-report=term-missing --cov-fail-under=90
# Full stack (pre-push)
docker compose -f docker-compose.test.yml up -d
pnpm test:ci && pytest && playwright test
```
---
## 16. Этапы разработки
### Фаза 0 — Подготовка (1–2 недели)
| # | Задача | Результат | Тесты (обязательно) |
|---|--------|-----------|---------------------|
| 0.1 | Monorepo: Vite, FastAPI skeleton | `apps/web`, `apps/api` | smoke: `vitest` 1 test, `pytest` health 1 test |
| 0.2 | Docker Compose + `docker-compose.test.yml` | dev + test stack | CI job: lint + smoke green |
| 0.3 | Shared UI kit + design tokens | Button, Input, Layout | component tests ≥80%; Storybook optional |
| 0.4 | ESLint boundaries, OpenAPI codegen, coverage gates | Quality gates в CI | CI блокирует merge без coverage config |
| 0.5 | Playwright + pytest fixtures | `e2e/`, `conftest.py`, factories | E2E smoke: landing page loads |
### Фаза 1 — MVP (4–6 недель)
> Каждая задача завершается **своим** набором unit + integration + E2E. Задача 1.6 — финальный регресс, не «первые E2E».
| # | Задача | Модули | Тесты (обязательно в том же PR) |
|---|--------|--------|----------------------------------|
| 1.1 | Landing (перенос заглушки) | landing | unit: breakpoints; E2E: `landing.spec.ts` |
| 1.2 | Auth + SMTP | auth | unit: service/security; integration: all auth routes; E2E: register/login/verify/reset |
| 1.2b | Security baseline | core, auth | 100% coverage `security.py`; tests: lockout, rotation, enumeration |
| 1.3 | Profile CRUD | profile | unit: validation; integration: `/users/me`; E2E: edit + avatar + password |
| 1.4 | Content pages | content | unit: sanitize; integration: CRUD; E2E: publish → public view |
| 1.5 | Admin panel | admin | unit: business rules; integration: admin routes; E2E: block user flow |
| 1.6 | Staging deploy + **полный регресс** | — | Playwright §15.7 (all 10 scenarios); coverage ≥ §15.2 |
### Фаза 2 — v1.0 (46 недель)
| # | Задача | Модули | Тесты (обязательно в том же PR) |
|---|--------|--------|----------------------------------|
| 2.1 | Celery + email queue | notifications | unit: task handlers; integration: queue + mock SMTP; E2E: notification received |
| 2.2 | Catalog + Orders | catalog, orders | unit + integration per module; E2E: browse → cart → submit order |
| 2.3 | Analytics dashboard | admin | integration: stats API; E2E: dashboard renders metrics |
| 2.4 | Performance + monitoring | infra | k6 load test §17.2; no coverage regression |
### Фаза 3 — Scale prep (по необходимости)
- Read replica PostgreSQL
- Celery workers
- CDN + object storage migration
- Horizontal API scaling
---
## 17. Критерии приёмки
### 17.1. MVP
**Функциональность:**
- [ ] Landing визуально соответствует текущей заглушке (hero, marquee, цвета).
- [ ] Регистрация и вход работают; load test **50 CCU** на API.
- [ ] Профиль редактируется, аватар загружается.
- [ ] Admin создаёт/редактирует контент-страницы.
**Производительность и безопасность:**
- [ ] API p95 < 300 ms при 50 CCU (k6).
- [ ] Lighthouse Performance ≥ 85 на mobile.
- [ ] Security checklist §14.13 — все пункты закрыты.
- [ ] OWASP ZAP baseline — 0 high/critical на staging.
**Тестирование (обязательно):**
- [ ] Backend coverage ≥ **90%** (`app/`), auth/security ≥ **95100%** (§15.2).
- [ ] Frontend coverage ≥ **85%** (`src/`), hooks/api ≥ **90%**.
- [ ] Все E2E сценарии §15.7 — **10/10 pass** на staging.
- [ ] 0 skipped tests без waiver.
- [ ] CI pipeline §13.3 — все gates green на `main`.
- [ ] Каждый модуль MVP имеет строки в матрице §15.4 (закрыты).
**Документация:**
- [ ] README: как запускать `test`, `test:ci`, `e2e`.
- [ ] OpenAPI, `.env.example`.
### 17.2. Load test сценарий (k6, API-only)
```javascript
// 50 VU, ramp 5 min, target: api:8000 через Nginx
// 35% GET /api/v1/content/pages
// 25% POST /api/v1/auth/login (test credentials pool)
// 20% GET /api/v1/users/me (authenticated)
// 10% POST /api/v1/auth/refresh (cookie)
// 10% GET /api/v1/content/pages/{slug}
```
**Pass:** error rate < 1%, p95 < 300ms, 0 auth bypass.
> Frontend (`GET /`) — отдельный Lighthouse-тест, не смешивать с API load test.
---
## 18. Риски и допущения
### 18.1. Допущения
1. 1000 пользователей — registered, не 1000 RPS.
2. Контент преимущественно текст + изображения, без video streaming.
3. Один регион хостинга (RU/EU), latency < 100ms для целевой аудитории.
4. Команда: 1–3 fullstack-разработчика.
### 18.2. Риски
| Риск | Вероятность | Митигация |
|------|-------------|-----------|
| Scope creep (catalog/orders раньше MVP) | Высокая | Жёсткое следование фазам |
| SPA SEO проблемы | Средняя | Prerender landing, meta tags |
| Cross-module imports ломают архитектуру | Средняя | ESLint boundaries в CI |
| Auth flow complexity (rotation, verify) | Средняя | TDD + integration tests §15.415.7 |
| Flaky E2E блокируют CI | Средняя | fixtures, isolated data §15.8, trace-on-retry |
| Перегрузка monolith при росте | Низкая (до 10K) | Redis cache, horizontal scale |
---
## Приложение A — Карта модулей (summary)
```mindmap
root((Комpton))
Frontend
app
pages
modules
landing
auth
profile
content
admin
catalog
shared
Backend
core
modules
auth
users
content
media
admin
Infra
PostgreSQL
Redis
S3
Nginx
"CI/CD"
```
---
## Приложение B — Переменные окружения
### Frontend (`apps/web/.env`)
```env
VITE_API_URL=http://localhost:8000
VITE_APP_NAME=Комpton
VITE_SENTRY_DSN=
```
### Backend (`apps/api/.env`)
```env
DATABASE_URL=postgresql+asyncpg://user:pass@localhost:5432/compton
REDIS_URL=redis://localhost:6379/0
JWT_ACCESS_SECRET= # ≥ 32 bytes random, NOT commit
JWT_REFRESH_PEPPER= # отдельный секрет для hash refresh tokens
JWT_ACCESS_TTL_MIN=15
JWT_REFRESH_TTL_DAYS=30
ENABLE_DOCS=true # false в production
CORS_ORIGINS=http://localhost:5173
S3_ENDPOINT=http://localhost:9000
S3_BUCKET=compton-media
S3_ACCESS_KEY=
S3_SECRET_KEY=
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASSWORD=
SMTP_FROM=noreply@compton.example
ADMIN_INITIAL_PASSWORD= # только first deploy, затем сменить
```
---
## Приложение C — Согласование
| Роль | ФИО | Подпись | Дата |
|------|-----|---------|------|
| Product Owner | | | |
| Tech Lead | | | |
| Developer | | | |
---
*Документ является живым артеfactом. Изменения фиксируются через PR в `docs/TZ.md` с bump версии.*