# Структура и архитектура 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) | ## Дерево репозитория ``` ├── 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 ```mermaid 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 | ## База данных ```mermaid 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`. ```bash cd apps/api && alembic upgrade head ``` CHECK constraints на `role`, `status`; superuser только при `role=admin`. Cleanup expired tokens при старте API. ### Seed: стандартные логины (dev) | Email | Пароль | 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 § логины](./deploy.md#стандартные-логины-dev). ## Переменные окружения (ключевые) | Переменная | Где | Назначение | |------------|-----|------------| | `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. ## Тесты ```bash 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`.