Align the project baseline with the latest admin interface styling and layout structure while documenting setup and usage updates in README.
60 KiB
Техническое задание
Платформа «Комптон» — React-приложение с модульной архитектурой
Испольнителю следовать плану реализации с особым пристрастрием
Версия документа: 1.0
Дата: 09.07.2026
Разработчик: Huli
Содержание
- Общие сведения
- Цели и границы проекта
- Профиль нагрузки и масштабирование
- Технологический стек
- Архитектура системы
- Модульная структура Frontend (React)
- Модульная структура Backend (API)
- Модель данных
- API-контракты
- Аутентификация и авторизация
- UI/UX и дизайн-система
- Нефункциональные требования
- Инфраструктура и DevOps
- Безопасность
- Тестирование и качество
- Этапы разработки
- Критерии приёмки
- Риски и допущения
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 000 зарегистрированных пользователей (~100–150 DAU) без деградации UX.
- Заложить архитектуру, позволяющую масштабироваться до 10 000+ пользователей без переписывания модулей.
- Обеспечить независимую разработку модулей разными разработчиками.
- Каждый шаг реализации (задача / 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. Путь масштабирования
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, фоновые задачи |
| 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. Принципы модульности
- Вертикальные срезы — каждый модуль владеет UI + API + схемой БД (таблицы через общий ORM, но namespace по модулю).
- Запрет cross-import между modules — общение только через:
- публичный API модуля (
modules/auth/api/index.ts); - shared-слой;
- backend REST/events.
- публичный API модуля (
- Публичный контракт модуля —
index.tsэкспортирует только то, что нужно снаружи. - Приватная реализация —
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: pending→ 403EMAIL_NOT_VERIFIED.loginприstatus: blocked→ 403ACCOUNT_BLOCKED.loginпри блокировке brute-force → 429ACCOUNT_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:
- Валидный access JWT (подпись, exp, jti).
- Пользователь существует и
status != blocked. - Для admin-роутов —
role == admin. - Для 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).
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 (из текущей заглушки)
: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:
- Browser (недоверенный) ↔ Nginx (TLS termination)
- Nginx ↔ API (internal network / docker network)
- 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 flagENABLE_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):
- Написать failing test (unit или e2e).
- Реализовать минимальный код.
- Довести coverage до порога.
- Открыть 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:
- Landing: LCP < 2.5s, hero + marquee,
prefers-reduced-motion. - Register → verify email → login → profile edit → change password → logout.
- Forgot password → reset → login with new password.
- Admin: create content → publish → visible on
/pages/:slug. - Admin: block user → blocked user gets 403 on login.
- Pending user cannot access
/profile. - Refresh rotation: old refresh token rejected; reuse revokes family.
- IDOR: user A cannot GET/PATCH user B profile.
- Admin cannot demote/block self; last admin protected.
- 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 ≥ 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)
// 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. Допущения
- 1000 пользователей — registered, не 1000 RPS.
- Контент преимущественно текст + изображения, без video streaming.
- Один регион хостинга (RU/EU), latency < 100ms для целевой аудитории.
- Команда: 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)
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 версии.