удаление test-контура (дополнение)
This commit is contained in:
@@ -16,21 +16,22 @@
|
||||
backend/ FastAPI: ядро, REST API, БД, миграции Alembic, seed, тесты
|
||||
frontend/ React + Vite SPA
|
||||
deploy/ публикация и эксплуатация: vps/ (Caddy), pi/ (прод), tunnel/ и backup/ (образы)
|
||||
scripts/ build-push.* (сборка и пуш образов), fs-backup.* (бэкапы с ПК), export-*.sh
|
||||
scripts/ build-push.* (сборка и пуш образов), fs-backup.* (бэкапы с ПК), export-prod.sh
|
||||
Dockerfile multi-stage сборка (фронт собирается node, отдаётся FastAPI)
|
||||
docker-compose.yml прод на Pi: app + tunnel + backup
|
||||
docker-compose.test.yml тест-клон прода на ПК: app + tunnel + backup
|
||||
docker-compose.temp.yml временный прод на ПК вместо Pi: app + tunnel
|
||||
run.ps1 / run.sh единый лаунчер dev/test
|
||||
run.ps1 / run.sh единый лаунчер dev
|
||||
.env.example шаблон единого .env
|
||||
```
|
||||
|
||||
## Локальная разработка
|
||||
|
||||
Всё проверяется в `development` — отдельного тестового контейнера нет.
|
||||
|
||||
### Единый лаунчер (`run.ps1` / `run.sh`)
|
||||
|
||||
После разовой настройки (ниже) dev и test запускаются **одной командой** — что именно,
|
||||
решает `APP_ENV` в корневом `.env`:
|
||||
После разовой настройки (ниже) dev запускается **одной командой** (лаунчер читает
|
||||
`APP_ENV` в корневом `.env`):
|
||||
|
||||
```powershell
|
||||
.\run.ps1 # Windows (Linux / macOS / Git Bash: ./run.sh)
|
||||
@@ -39,8 +40,8 @@ run.ps1 / run.sh единый лаунчер dev/test
|
||||
| `APP_ENV` в `.env` | что делает лаунчер |
|
||||
|---|---|
|
||||
| `development` | сначала `alembic upgrade head`, затем `uvicorn --reload` (бэк) + `vite` (фронт) нативно: `run.ps1` — в отдельных окнах, `run.sh` — в текущем терминале (Ctrl+C останавливает оба). При `LOCAL_PUBLIC=vps` дополнительно поднимает SSH-туннель на `forbidden-stars.ru` |
|
||||
| `test` | `docker compose -f docker-compose.test.yml up --build -d` — прод-клон (app + tunnel + backup); портов на хост нет, открывается на `https://forbidden-stars.ru` |
|
||||
| `production` | не запускает — прод деплоится отдельно (см. «Production» и «Git и деплой») |
|
||||
| другое значение | отказ: допустимы только `development` и `production` (бэкенд тоже не стартует) |
|
||||
|
||||
Разовая настройка перед первым запуском — поднять venv бэка и зависимости фронта
|
||||
(после неё повседневный цикл — просто `.\run.ps1`). Vite проксирует `/api` на бэкенд.
|
||||
@@ -128,46 +129,19 @@ docker compose up -d # pull_policy: always — тянет свежие
|
||||
при первом создании админа, дальше его смена в `.env` ни на что не влияет (задача #73).
|
||||
Пошагово — [`deploy/pi/README.md`](deploy/pi/README.md), бэкапы — [`deploy/backup/README.md`](deploy/backup/README.md).
|
||||
|
||||
## Test — прод-клон в контейнере на ПК
|
||||
|
||||
Тот же `Dockerfile` и поведение, что у прода (FastAPI отдаёт SPA, БД на томе, вход игроков
|
||||
по логину/паролю или через Telegram), но образ собирается локально — для проверки прод-сборки
|
||||
до выката на Pi. Портов на хост **нет**: тест-клон виден только на `https://forbidden-stars.ru`
|
||||
через свой туннель-контейнер (ключ — файл `deploy/tunnel/id_tunnel`).
|
||||
|
||||
Проще всего — через лаунчер: поставить `APP_ENV=test` в `.env` и запустить `.\run.ps1`.
|
||||
Вручную (тот же эффект):
|
||||
```bash
|
||||
docker compose -f docker-compose.test.yml up -d --build
|
||||
# открыть https://forbidden-stars.ru (Swagger: /api/docs)
|
||||
docker compose -f docker-compose.test.yml logs -f app
|
||||
docker compose -f docker-compose.test.yml down -v # остановить и стереть тестовые данные
|
||||
```
|
||||
|
||||
- Читает **тот же `.env`**, что dev/prod (отдельного `.env.test` больше нет); внутри
|
||||
контейнера `APP_ENV` форсится в `test` (см. `docker-compose.test.yml`). Cookie — Secure
|
||||
(снаружи HTTPS).
|
||||
- От прода test отличается тем, что OpenAPI/Swagger открыт и **нет** fail-fast по дефолтным
|
||||
секретам, хотя контур публичный (задача #69). Не держите в `.env` дефолтные `SECRET_KEY` /
|
||||
`ADMIN_PASSWORD`, когда поднимаете test, — особенно после `restore-test` с прод-данными.
|
||||
- Данные — на отдельных томах `db-data-test` / `uploads-data-test` / `achievements-data-test`
|
||||
(и `backup-data-test` у контейнера бэкапов, он работает без расписания и без VPS);
|
||||
с dev и Pi не пересекаются.
|
||||
- Слот VPS 9001 общий с dev-туннелем (`LOCAL_PUBLIC=vps`) — поднимайте что-то одно.
|
||||
- Вход: **админ-панель** (`/admin/login`) работает сразу по логину/паролю; **игроки** — по
|
||||
логину/паролю сразу, через Telegram — при настроенном боте (`/setdomain` → `forbidden-stars.ru`).
|
||||
- Учебное восстановление прод-бэкапа в тест-клон — `.\scripts\fs-backup.ps1 restore-test`
|
||||
([`deploy/backup/README.md`, шаг 7](deploy/backup/README.md#шаг-7-учебное-восстановление-на-тест-клоне)).
|
||||
- **Не используйте `$` в секретах.** Единый `.env` читают и pydantic (dev — `$` дословно),
|
||||
и docker compose (test/prod — `$` = подстановка переменной). Чтобы значение совпадало
|
||||
и docker compose (prod — `$` = подстановка переменной). Чтобы значение совпадало
|
||||
везде, в `SECRET_KEY`/`ADMIN_PASSWORD` не должно быть `$`. Удобно генерировать так:
|
||||
`python -c "import secrets;print(secrets.token_urlsafe(48))"` (даёт только `[A-Za-z0-9_-]`).
|
||||
- **Временный прод на ПК** (вместо Pi): `docker compose -f docker-compose.temp.yml up -d --build` —
|
||||
поведение production, локальная сборка x86, ключ туннеля из файла `deploy/tunnel/id_tunnel`,
|
||||
тот же слот VPS 9000, что у Pi (одновременно не запускать).
|
||||
|
||||
## Аутентификация
|
||||
|
||||
Методы входа зависят от окружения (`APP_ENV`):
|
||||
|
||||
| | dev | test / prod |
|
||||
| | dev | prod |
|
||||
|---|---|---|
|
||||
| Логин (= ник) и пароль | ✓ | ✓ (основной) |
|
||||
| Telegram Login Widget | ✓ | ✓ |
|
||||
@@ -189,7 +163,7 @@ docker compose -f docker-compose.test.yml down -v # остановить и с
|
||||
`backend/app/routers/dev_auth.py` и `backend/app/routers/dev_admin.py` исключены из
|
||||
Docker-образа (`.dockerignore`), роутеры подключаются лишь при `APP_ENV=development`
|
||||
(`app/main.py`), а на фронте dev-блоки вырезаются из прод-сборки (`import.meta.env.DEV`).
|
||||
В test/prod аккаунт можно только отключить.
|
||||
В проде аккаунт можно только отключить.
|
||||
- **Telegram:** сервер проверяет подпись виджета (HMAC по `TELEGRAM_BOT_TOKEN`) и свежесть
|
||||
данных (не старше суток). Первый вход регистрирует игрока под Telegram-тегом; если такой ник
|
||||
занят или некорректен, фронт просит выбрать другой. `GET /api/auth/config` отдаёт доступные
|
||||
@@ -197,43 +171,42 @@ docker compose -f docker-compose.test.yml down -v # остановить и с
|
||||
|
||||
**Настройка Telegram (когда будете подключать реальный вход):**
|
||||
1. Создать бота у [@BotFather](https://t.me/BotFather) → получить **токен** и **username**.
|
||||
2. `/setdomain` у BotFather → оба домена: `forbiddenstars.ru` (prod) и `forbidden-stars.ru` (dev/test).
|
||||
2. `/setdomain` у BotFather → оба домена: `forbiddenstars.ru` (prod) и `forbidden-stars.ru` (dev).
|
||||
3. В `.env`: `TELEGRAM_BOT_TOKEN=...`, `TELEGRAM_BOT_USERNAME=...` (без `@`).
|
||||
4. Виджету нужен HTTPS-домен (см. «Домен и публикация») — по голому HTTP/localhost он не работает.
|
||||
|
||||
Админ-вход (секретная панель, логин+пароль) — отдельный механизм, доступен во всех
|
||||
окружениях. Страница — `/admin/login`; из интерфейса туда ведёт удержание кнопки «Меню» 10 секунд.
|
||||
|
||||
## Окружения (dev / test / prod)
|
||||
## Окружения (dev / prod)
|
||||
|
||||
Один и тот же код; контур задаёт `APP_ENV` в **едином** `.env` (его читает лаунчер):
|
||||
Один и тот же код; контур задаёт `APP_ENV` в **едином** `.env`. Допустимы только
|
||||
`development` и `production` — с любым другим значением бэкенд не стартует:
|
||||
|
||||
| | dev | test (прод-клон локально) | prod (Pi) |
|
||||
|---|---|---|---|
|
||||
| Запуск | `.\run.ps1` → `uvicorn --reload` + `vite` | `.\run.ps1` → `docker compose -f docker-compose.test.yml` | `docker compose up -d` |
|
||||
| `APP_ENV` | `development` | `test` (форсится в compose) | `production` (форсится в compose) |
|
||||
| Env-файл | единый `.env` | единый `.env` | единый `.env` (на Pi) |
|
||||
| Раздача SPA | Vite (HMR), `:5173` | FastAPI, только через `https://forbidden-stars.ru` | FastAPI, только через `https://forbiddenstars.ru` |
|
||||
| База данных | `backend/data/dev/…` | том `db-data-test` (`/data`) | том `db-data` (`/data`) |
|
||||
| Вход игроков | пароль + Telegram + ник (stub) | пароль + Telegram | пароль + Telegram |
|
||||
| Swagger (`/api/docs`) | ✓ | ✓ | ✗ |
|
||||
| Fail-fast по дефолтным секретам | ✗ | ✗ | ✓ |
|
||||
| | dev | prod (Pi) |
|
||||
|---|---|---|
|
||||
| Запуск | `.\run.ps1` → `uvicorn --reload` + `vite` | `docker compose up -d` |
|
||||
| `APP_ENV` | `development` | `production` (форсится в compose) |
|
||||
| Env-файл | единый `.env` | единый `.env` (на Pi) |
|
||||
| Раздача SPA | Vite (HMR), `:5173` | FastAPI, только через `https://forbiddenstars.ru` |
|
||||
| База данных | `backend/data/dev/…` | том `db-data` (`/data`) |
|
||||
| Вход игроков | пароль + Telegram + ник (stub) | пароль + Telegram |
|
||||
| Swagger (`/api/docs`) | ✓ | ✗ |
|
||||
| Fail-fast по дефолтным секретам | ✗ | ✓ |
|
||||
|
||||
- **Один `.env` на машину** в корне (рядом с `.env.example`). `APP_ENV` в нём решает, что
|
||||
запустит лаунчер (`development`/`test`); прод-контейнер это значение **игнорирует** и всегда
|
||||
`production`. Отдельного `.env.test` больше нет.
|
||||
- **Один `.env` на машину** в корне (рядом с `.env.example`). Прод-контейнер значение
|
||||
`APP_ENV` из него **игнорирует** и всегда `production`.
|
||||
- **Структура БД одна** (общие миграции Alembic), **файлы разные**: dev → `DEV_DATABASE_URL`
|
||||
(`backend/data/dev/`), test и prod → `PROD_DATABASE_URL` (том `/data`; у test и prod это
|
||||
РАЗНЫЕ тома). Так же раздельно лежат загрузки (`*_UPLOAD_DIR`) и ачивки (`*_ACHIEVEMENTS_DIR`).
|
||||
(`backend/data/dev/`), prod → `PROD_DATABASE_URL` (том `/data`). Так же раздельно лежат
|
||||
загрузки (`*_UPLOAD_DIR`) и ачивки (`*_ACHIEVEMENTS_DIR`).
|
||||
- **В Docker идёт только прод-код:** dev-вход (stub), dev-удаление аккаунтов и тесты физически
|
||||
исключены из образа (`.dockerignore`); `test` собирается из того же `Dockerfile`, что и прод,
|
||||
просто локально и с `APP_ENV=test`.
|
||||
исключены из образа (`.dockerignore`).
|
||||
- **Внимание:** данные дева (`backend/data/dev/`) сейчас **попадают** в образ — правило
|
||||
`data/` в `.dockerignore` исключает только корневую папку `data/` (задача #71).
|
||||
|
||||
## Git и деплой
|
||||
|
||||
- Ветка **`dev`** — рабочая: весь код, лаунчер, тесты. Повседневная разработка и `test` здесь.
|
||||
- Ветка **`dev`** — рабочая: весь код, лаунчер, тесты. Повседневная разработка и проверка здесь.
|
||||
- Ветка **`main`** — релиз прода: готовое промоутишь из `dev` через `merge dev→main`. Файлы во
|
||||
всех ветках одинаковы (окружение задаёт `.env`/compose, а не ветка) → merge безболезненный;
|
||||
чистоту прод-образа обеспечивает `.dockerignore`, а не разные наборы файлов.
|
||||
@@ -241,10 +214,9 @@ docker compose -f docker-compose.test.yml down -v # остановить и с
|
||||
образы app + tunnel + backup под arm64), на Pi — `docker compose up -d`. На Windows нужна
|
||||
именно PS-версия скрипта (`build-push.sh` из PowerShell уходит в WSL).
|
||||
- **Чистая выгрузка в папку без git** (опц., к деплою на Pi не относится):
|
||||
`scripts/export-prod.sh <dir> [ref]` / `scripts/export-test.sh <dir> [ref]` — через
|
||||
`git archive` + `export-ignore` из `.gitattributes` (без тестов, stub-входа, `pyproject.toml`,
|
||||
README-файлов; у прода ещё без лаунчера и тест-compose, у теста — без прод-compose). `dev_admin.py` в
|
||||
`export-ignore` пока не внесён (задача #70).
|
||||
`scripts/export-prod.sh <dir> [ref]` — через `git archive` + `export-ignore` из
|
||||
`.gitattributes` (без тестов, stub-входа, `pyproject.toml`, README-файлов и лаунчера).
|
||||
`dev_admin.py` в `export-ignore` пока не внесён (задача #70).
|
||||
|
||||
Секреты (`.env`) и данные (`data/`, `*.db`) в git не идут — см. `.gitignore`.
|
||||
|
||||
@@ -252,21 +224,21 @@ docker compose -f docker-compose.test.yml down -v # остановить и с
|
||||
|
||||
Публичные адреса отдаёт **VPS-привратник** (Caddy + HTTPS твоими сертификатами), а
|
||||
приложение само открывает к нему SSH reverse-туннель (дома белого IP нет — CGNAT).
|
||||
У **test/prod** туннель — **отдельный контейнер** в их `docker-compose`, и портов на хост
|
||||
они не публикуют (доступны только через домен):
|
||||
У **прода** туннель — **отдельный контейнер** в `docker-compose.yml`, и портов на хост он
|
||||
не публикует (доступен только через домен):
|
||||
|
||||
| | домен | как выставляется | слот VPS |
|
||||
|---|---|---|---|
|
||||
| prod | `forbiddenstars.ru` | туннель-контейнер (постоянно) → `app:8000` | 9000 |
|
||||
| test | `forbidden-stars.ru` | туннель-контейнер → `app:8000` | 9001 |
|
||||
| dev | `forbidden-stars.ru` | лаунчер (`run.ps1`/`run.sh`) при `LOCAL_PUBLIC=vps` → `localhost:5173` | 9001 |
|
||||
|
||||
- Прод (9000) и dev/test (9001) на **разных слотах/доменах** → прод и (dev|test) работают
|
||||
одновременно. Dev и test делят слот 9001 → по очереди. Временный прод на ПК
|
||||
(`docker-compose.temp.yml`) занимает слот 9000 — одновременно с продом на Pi не запускать.
|
||||
- Прод (9000) и dev (9001) на **разных слотах/доменах** → работают одновременно. Временный
|
||||
прод на ПК (`docker-compose.temp.yml`) занимает слот 9000 — одновременно с продом на Pi не запускать.
|
||||
- Dev по умолчанию только на localhost; `LOCAL_PUBLIC=vps` + лаунчер выставляет его на домен.
|
||||
В dev при этом открыты stub-вход по нику и Swagger — держите туннель поднятым только на
|
||||
время проверки (задача #69).
|
||||
- `COOKIE_SECURE` выводится автоматически (HTTPS-домен ⇒ Secure-cookie; dev+localhost ⇒ нет).
|
||||
- Ключ туннеля: test и временный прод берут файл `deploy/tunnel/id_tunnel`, прод на Pi —
|
||||
- Ключ туннеля: временный прод берёт файл `deploy/tunnel/id_tunnel`, прод на Pi —
|
||||
`TUNNEL_KEY_B64` (base64) в `.env`, dev-туннель — системный `ssh` с ключом по умолчанию
|
||||
(`~/.ssh`). Публичные части — в `authorized_keys` пользователя `tunnel` на VPS.
|
||||
- Пошаговая настройка — в [`deploy/`](deploy/README.md): `vps/` (Caddy, сертификаты, юзер `tunnel`),
|
||||
@@ -276,7 +248,7 @@ docker compose -f docker-compose.test.yml down -v # остановить и с
|
||||
|
||||
Контейнер `backup` (restic) в `docker-compose.yml` каждую ночь делает зашифрованный снимок
|
||||
БД, `uploads` и `achievements` — на Pi (том `backup-data`) и на VPS по SFTP. С ПК снимки
|
||||
скачиваются и проверяются учебным восстановлением в тест-клон (`scripts/fs-backup.ps1`).
|
||||
скачиваются со сверкой sha256 (`scripts/fs-backup.ps1 pull`).
|
||||
Настройка, восстановление и действия при гибели Pi — [`deploy/backup/README.md`](deploy/backup/README.md).
|
||||
|
||||
## Дополнения и фракции
|
||||
|
||||
Reference in New Issue
Block a user