# Техническое задание
## Платформа «Комптон» — 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 зарегистрированных пользователей** (~100–150 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 | 100–150 (10–15%) | Типичный коэффициент для B2C |
| CCU (пик) | 30–50 | Одновременные сессии |
| RPS API (пик) | 20–50 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: 1K–10K]
        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 (4–6 недель)

| # | Задача | Модули | Тесты (обязательно в том же 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 ≥ **95–100%** (§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.4–15.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 версии.*
