# Техническое задание ## Платформа «Комптон» — 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// ├── __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=; 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://; connect-src 'self' https://; 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 версии.*