Files
site/docs/project.md
T

221 lines
8.1 KiB
Markdown

# Структура и архитектура
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
```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`.