Files
site/TZ (1).md
T

60 KiB
Raw Blame History

Техническое задание

Платформа «Комптон» — React-приложение с модульной архитектурой

Испольнителю следовать плану реализации с особым пристрастрием

Версия документа: 1.0
Дата: 09.07.2026
Разработчик: Huli


Содержание

  1. Общие сведения
  2. Цели и границы проекта
  3. Профиль нагрузки и масштабирование
  4. Технологический стек
  5. Архитектура системы
  6. Модульная структура Frontend (React)
  7. Модульная структура Backend (API)
  8. Модель данных
  9. API-контракты
  10. Аутентификация и авторизация
  11. UI/UX и дизайн-система
  12. Нефункциональные требования
  13. Инфраструктура и DevOps
  14. Безопасность
  15. Тестирование и качество
  16. Этапы разработки
  17. Критерии приёмки
  18. Риски и допущения

1. Общие сведения

1.1. Наименование проекта

Комптон® — веб-платформа бренда «Organic Tech» с публичной витриной, личным кабинетом пользователя и административной панелью.

1.2. Текущее состояние

  • Чисто поржать на ошибках и нейронке
  • Заглушка на Flask (main.py) с одностраничным лендингом.
  • Визуальная идентичность задана не полностью: цвета, шрифты (Inter, JetBrains Mono), hero-блок, бегущая строка.
  • Рефакторинг текщего состояния не возможен, задача переписать проект.
  • Функциональность отсутствует: нет регистрации, контента, API, БД.

1.3. Заказчик / продукт

Еблан который зовет себя Huli. Документ описывает целевую архитектуру для замены заглушки полноценным продуктом.

1.4. Термины

Термин Определение
Модуль (feature) Изолированный функциональный блок с собственными компонентами, API-слоем, типами и тестами
Shared Переиспользуемый код без бизнес-логики конкретного модуля
Core Ядро приложения: роутинг, провайдеры, конфигурация, HTTP-клиент
MAU Monthly Active Users — уникальные пользователи за месяц
CCU Concurrent Users — одновременно онлайн

2. Цели и границы проекта

2.1. Бизнес-цели

  1. Заменить заглушку работающим сайтом с сохранением бренда.
  2. Обеспечить регистрацию и работу до 1 000 зарегистрированных пользователей (~100150 DAU) без деградации UX.
  3. Заложить архитектуру, позволяющую масштабироваться до 10 000+ пользователей без переписывания модулей.
  4. Обеспечить независимую разработку модулей разными разработчиками.
  5. Каждый шаг реализации (задача / PR / модуль) поставляется только с полным набором тестов: unit/integration логики + E2E пользовательских сценариев (§15).

2.2. Функциональный scope (MVP → v1.0)

MVP (фаза 1)

Модуль Функции
Landing Hero, бегущая строка, «О бренде», контакты, SEO-мета
Auth Регистрация, вход, выход, восстановление пароля, подтверждение email (требует SMTP в MVP — см. §16)
Profile Просмотр/редактирование профиля, аватар, смена пароля
Content Статические страницы (О нас, Политика, Условия) из CMS или markdown
Admin Управление пользователями, контентом, просмотр метрик

v1.0 (фаза 2, опционально)

Модуль Функции
Catalog Каталог продуктов/услуг, карточки, фильтры
Orders Корзина, оформление заявки (без оплаты — см. §2.3), история
Notifications In-app уведомления; email-рассылки через очередь (Celery)
Analytics Дашборд событий, экспорт

2.3. Out of scope (не входит в v1.0)

  • Мобильное нативное приложение (только responsive web).
  • Мультиязычность (заложить i18n-структуру, реализовать позже).
  • Платёжные шлюзы (интеграция — отдельный этап). Модуль Orders в v1.0 работает как заявка/бронирование без оплаты.
  • Real-time чат / WebRTC.

3. Профиль нагрузки и масштабирование

3.1. Целевые метрики (1000 пользователей)

Метрика Значение Комментарий
Зарегистрированных пользователей 1 000 Целевой объём на старте
DAU 100150 (1015%) Типичный коэффициент для B2C
CCU (пик) 3050 Одновременные сессии
RPS API (пик) 2050 req/s С запасом ×3
Размер БД < 5 GB Профили, контент, логи
Медиа < 50 GB CDN для статики

3.2. Путь масштабирования

flowchart LR
    subgraph phase1 [Фаза 1: до 1K]
        A1[Monolith API]
        A2[PostgreSQL]
        A3[Redis cache]
        A4[CDN static]
    end

    subgraph phase2 [Фаза 2: 1K10K]
        B1[2× API instances]
        B2[Read replica PG]
        B3[Redis cluster]
        B4[Object storage S3]
    end

    subgraph phase3 [Фаза 3: 10K+]
        C1[Horizontal API scale]
        C2[Extract heavy modules]
        C3[Message queue]
        C4[Separate admin]
    end

    phase1 --> phase2 --> phase3

Принцип: на 1000 пользователей достаточно модульного монолита (один backend-процесс, чёткие границы модулей). Микросервисы не нужны до 10K+ и только для узких «тяжёлых» модулей (уведомления, аналитика).

3.3. SLA (целевые)

Параметр MVP v1.0
Uptime 99.5% 99.9%
TTFB публичных страниц < 500 ms < 300 ms
API p95 latency < 300 ms < 200 ms
LCP (Lighthouse mobile) < 2.5 s < 2.0 s

4. Технологический стек

4.1. Frontend

Слой Технология Обоснование
Framework React 19 + TypeScript 5 Экосистема, типизация
Bundler Vite 6 Быстрая сборка, HMR
Routing React Router 7 Стандарт de facto
Server state TanStack Query 5 Кеш, retry, invalidation
Client state Zustand Лёгкий, без boilerplate
Forms React Hook Form + Zod Валидация, DX
UI Tailwind CSS 4 + headless (Radix UI) Соответствие дизайн-системе
HTTP Axios или fetch-обёртка Interceptors, типизация
i18n (заготовка) react-i18next Структура без реализации
Tests Vitest + Testing Library + Playwright + pytest Unit + integration + E2E на каждом PR (§15)

4.2. Backend

Слой Технология Обоснование
Runtime Python 3.12 Преемственность Flask-проекта
Framework FastAPI Async, OpenAPI, производительность
ORM SQLAlchemy 2 + Alembic Миграции, типизация
Validation Pydantic v2 Согласованность с OpenAPI
Auth JWT (access + refresh rotation) + passlib/bcrypt Stateless access, revocable refresh
Task queue (v1.0) Celery + Redis Email, фоновые задачи
Email SMTP / SendGrid / Resend MVP: синхронная отправка verify/reset; v1.0: Celery queue

4.3. Data & Infra

Компонент Технология
Primary DB PostgreSQL 16
Cache / sessions Redis 7
File storage S3-compatible (MinIO dev / Yandex S3 / AWS prod)
Reverse proxy Nginx
Containerization Docker + Docker Compose (dev/staging)
CI/CD GitHub Actions
Monitoring Prometheus + Grafana (или managed: Datadog)
Logging Structured JSON → Loki или cloud logs
Error tracking Sentry

4.4. Архитектурный стиль Frontend

Feature-Sliced Design (FSD) — адаптированная версия с явными модулями:

app → pages → modules → shared
  • app — инициализация, провайдеры, глобальный роутер.
  • pages — композиция модулей в маршруты (тонкий слой).
  • modules — бизнес-фичи (auth, profile, catalog…).
  • shared — UI-kit, utils, API client, types без доменной логики.

5. Архитектура системы

5.1. Общая схема

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)

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)

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. Индексы

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: pending403 EMAIL_NOT_VERIFIED.
  • login при status: blocked403 ACCOUNT_BLOCKED.
  • login при блокировке brute-force → 429 ACCOUNT_TEMPORARILY_LOCKED.

Response login (200):

{
  "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

# 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).

Механизм Применение
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 (из текущей заглушки)

: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)

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

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)

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. Команды (локально)

# 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 ≥ 95100% (§15.2).
  • Frontend coverage ≥ 85% (src/), hooks/api ≥ 90%.
  • Все E2E сценарии §15.7 — 10/10 pass на staging.
  • 0 skipped tests без waiver.
  • CI pipeline §13.3 — все gates green на main.
  • Каждый модуль MVP имеет строки в матрице §15.4 (закрыты).

Документация:

  • README: как запускать test, test:ci, e2e.
  • OpenAPI, .env.example.

17.2. Load test сценарий (k6, API-only)

// 50 VU, ramp 5 min, target: api:8000 через Nginx
// 35% GET  /api/v1/content/pages
// 25% POST /api/v1/auth/login        (test credentials pool)
// 20% GET  /api/v1/users/me         (authenticated)
// 10% POST /api/v1/auth/refresh     (cookie)
// 10% GET  /api/v1/content/pages/{slug}

Pass: error rate < 1%, p95 < 300ms, 0 auth bypass.

Frontend (GET /) — отдельный Lighthouse-тест, не смешивать с API load test.


18. Риски и допущения

18.1. Допущения

  1. 1000 пользователей — registered, не 1000 RPS.
  2. Контент преимущественно текст + изображения, без video streaming.
  3. Один регион хостинга (RU/EU), latency < 100ms для целевой аудитории.
  4. Команда: 1–3 fullstack-разработчика.

18.2. Риски

Риск Вероятность Митигация
Scope creep (catalog/orders раньше MVP) Высокая Жёсткое следование фазам
SPA SEO проблемы Средняя Prerender landing, meta tags
Cross-module imports ломают архитектуру Средняя ESLint boundaries в CI
Auth flow complexity (rotation, verify) Средняя TDD + integration tests §15.415.7
Flaky E2E блокируют CI Средняя fixtures, isolated data §15.8, trace-on-retry
Перегрузка monolith при росте Низкая (до 10K) Redis cache, horizontal scale

Приложение A — Карта модулей (summary)

  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)

VITE_API_URL=http://localhost:8000
VITE_APP_NAME=Комpton
VITE_SENTRY_DSN=

Backend (apps/api/.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 версии.