8.1 KiB
Структура и архитектура
Monorepo-lite: статический лендинг + React SPA + FastAPI + PostgreSQL + Redis + MinIO.
Если вы искали микросервисы на Kubernetes — это другой коридор.
Стек
| Слой | Технологии |
|---|---|
| Frontend | React 19, TS, Vite, React Router, TanStack Query, Zustand, RHF+Zod, Ant Design |
| Backend | FastAPI, SQLAlchemy 2, Alembic, Pydantic v2 |
| Данные | PostgreSQL 16, Redis 7, MinIO |
| Инфра | Docker Compose, Nginx, GitHub Actions |
| Качество | Vitest, Playwright, pytest (≥90% / ≥85% cov) |
Дерево репозитория
site/
├── apps/
│ ├── api/ # Backend
│ │ ├── app/
│ │ │ ├── core/ # crypto, jwt_denylist, redis, install_secrets…
│ │ │ ├── db/ # models, seed, migrations helpers
│ │ │ └── modules/ # auth, users, content, admin, media, test
│ │ ├── migrations/ # Alembic
│ │ ├── scripts/ # bootstrap_install.py, docker_entrypoint.py
│ │ ├── tests/
│ │ └── data/
│ │ ├── secrets/ # install.env (gitignore!)
│ │ └── logs/ # server.log, admin-audit.jsonl (gitignore)
│ └── web/
│ ├── index.html # лендинг /
│ ├── app.html # SPA entry
│ ├── main/ # статика лендинга (CSS/JS/video)
│ ├── src/
│ │ ├── app/ # router, guards
│ │ ├── modules/ # auth, profile, admin, content, landing
│ │ ├── pages/
│ │ └── shared/ # api client, ui
│ └── e2e/ # Playwright
├── packages/ # eslint-config, shared-types (target)
├── infra/
│ ├── docker/ # staging/prod compose, deploy.sh
│ ├── nginx/ # default.conf, default.tls.conf
│ ├── k6/ # load test §17.2
│ └── scripts/ # backup, health, smoke
├── docs/ # вы здесь
├── docker-compose.yml # dev
└── docker-compose.test.yml # CI / E2E
Runtime
flowchart TB
subgraph browser [Браузер]
L[index.html /]
S[app.html SPA]
end
subgraph edge [Nginx :80/:443]
N[TLS + headers]
end
subgraph internal [Docker internal]
W[web]
A[api]
PG[(PostgreSQL)]
R[(Redis)]
M[(MinIO)]
end
L --> N
S --> N
N --> W
N --> A
A --> PG
A --> R
A --> M
Prod/staging: наружу только nginx. Postgres, Redis, MinIO — без host-портов.
Frontend
Два входа (dual-entry)
| Entry | URL | Содержимое |
|---|---|---|
index.html |
/ |
Маркетинговый лендинг (main/) |
app.html |
/login, /admin, … |
React SPA |
Vite переписывает SPA-пути на app.html (vite.main-static.ts).
Маршруты
| Путь | Guard | Кто |
|---|---|---|
/ |
— | все |
/login, /register, /forgot-password, /reset-password |
GuestGuard | гости |
/verify, /pages/:slug |
— | публично |
/profile |
AuthGuard | user |
/admin |
AdminGuard | admin |
Auth UX:
- Access JWT — только в памяти (Zustand), не localStorage
- Refresh — HttpOnly cookie,
Path=/api/v1/auth - После login: admin →
/admin, user →/profile - Кнопка «На сайт» в админке — полный переход на
/(не React Router)
Админка (WESP-style)
| Раздел | Кому | Что |
|---|---|---|
| Users | admin | CRUD пользователей |
| Content | admin | CMS |
| Security | superuser | runtime settings, Install Secrets |
| Diagnostics | superuser | health checks |
| Activity | admin | audit feed, server log |
Тема Light/Dark — localStorage.wespAdminTheme. Auth-страницы — zootech-карточки (#48816d).
Backend API
База: /api/v1
| Модуль | Эндпоинты (основное) |
|---|---|
| health | GET /health |
| auth | register, login, logout, refresh, verify, forgot/reset password |
| users | GET/PATCH /me, password, avatar |
| content | публичные pages + admin CRUD |
| admin | users, stats, settings, diagnostics, secrets, activity |
| media | подписанные URL файлов |
| test | /test/emails/latest-token — только E2E |
Core (apps/api/app/core/)
| Модуль | Зачем |
|---|---|
crypto.py |
bcrypt, JWT, HMAC, token hash — одна точка |
jwt_denylist.py |
мгновенный revoke access JWT |
install_secrets.py |
bootstrap + lock |
dependencies.py |
get_current_user |
redis.py |
rate limit + JWT revoke |
storage.py |
MinIO / memory |
База данных
erDiagram
users ||--o| user_profiles : has
users ||--o{ refresh_tokens : owns
users ||--o{ password_reset_tokens : owns
users ||--o{ email_verification_tokens : owns
Таблицы: users, user_profiles, refresh_tokens, password_reset_tokens, email_verification_tokens, content_pages.
cd apps/api && alembic upgrade head
CHECK constraints на role, status; superuser только при role=admin. Cleanup expired tokens при старте API.
Seed: стандартные логины (dev)
| Пароль | Env | |
|---|---|---|
| admin@compton.example | Admin1234 | ADMIN_INITIAL_PASSWORD |
| ops@compton.example | OpsAdmin1234 | DEMO_OPS_PASSWORD |
| user@compton.example | User1234 | DEMO_USER_PASSWORD |
CMS: about, privacy, terms. Подробнее — deploy.md § логины.
Переменные окружения (ключевые)
| Переменная | Где | Назначение |
|---|---|---|
DATABASE_URL |
api | PostgreSQL |
APP_ENV |
api | development / staging / production |
JWT_ACCESS_SECRET, JWT_REFRESH_PEPPER |
api | токены |
REDIS_URL |
api | rate limit + JWT revoke (prod обязателен) |
SEED_DEMO_USERS |
api | false на staging/prod |
ADMIN_INITIAL_PASSWORD |
api | пароль admin при seed (default Admin1234) |
DEMO_USER_PASSWORD, DEMO_OPS_PASSWORD |
api | demo user/ops (только dev) |
ENABLE_DOCS |
api | false на prod |
ENABLE_TEST_ROUTES |
api | true только E2E |
EMAIL_DELIVERY_MODE |
api | memory (dev) / smtp (prod) |
STORAGE_MODE |
api | s3 / memory |
VITE_API_URL |
web | http://api:8000 в Docker |
VITE_USE_API_PROXY |
web | true в dev |
Полные примеры: apps/api/.env.example, apps/api/.env.production.example.
Runtime settings
apps/api/data/compton_settings.json — toggles без секретов. Superuser: GET/PATCH /admin/settings. Env с тем же ключом = lock (нельзя менять из UI).
Docker Compose
| Файл | Когда |
|---|---|
docker-compose.yml |
локальная разработка |
docker-compose.dev-ports.yml |
PG/Redis/MinIO на хост (DBeaver) |
docker-compose.test.yml |
CI, Playwright |
infra/docker/docker-compose.staging.yml |
staging VPS |
infra/docker/docker-compose.prod.yml |
production VPS |
CI
.github/workflows/ci.yml: lint → types → mypy → tests → audit → Bandit → gitleaks → E2E.
Тесты
pnpm --filter web test:ci
cd apps/api && python -m pytest --cov=app --cov-fail-under=90
pnpm --filter web e2e
E2E поднимает API :8001 + Vite :5175. Против staging: E2E_BASE_URL=… E2E_START_API=false.