first commit
This commit is contained in:
@@ -0,0 +1,163 @@
|
|||||||
|
# Forbidden Stars — учёт партий
|
||||||
|
|
||||||
|
Мобильное веб-приложение для учёта партий настольной игры **Forbidden Stars**:
|
||||||
|
профили игроков (вход через Telegram, пока — dev-заглушка), группы, создание партий
|
||||||
|
с рандомом фракций и фильтром по дополнениям группы, статистика и общий топ, админ-панель.
|
||||||
|
|
||||||
|
- **Бэкенд / ядро + API:** Python · FastAPI · SQLModel · SQLite
|
||||||
|
- **Фронтенд:** React · Vite · TypeScript (SPA, общается с ядром только по REST API)
|
||||||
|
- **Хостинг:** Raspberry Pi 4 (ARM64) в Docker
|
||||||
|
|
||||||
|
## Структура
|
||||||
|
|
||||||
|
```
|
||||||
|
backend/ FastAPI: ядро, REST API, БД, миграции, seed
|
||||||
|
frontend/ React + Vite SPA
|
||||||
|
Dockerfile multi-stage сборка (фронт собирается node, отдаётся FastAPI)
|
||||||
|
docker-compose.yml
|
||||||
|
.env.example
|
||||||
|
```
|
||||||
|
|
||||||
|
## Локальная разработка
|
||||||
|
|
||||||
|
Бэкенд и фронт запускаются раздельно; Vite проксирует `/api` на бэкенд.
|
||||||
|
|
||||||
|
### 1) Бэкенд
|
||||||
|
|
||||||
|
**Windows PowerShell** (команды по одной — в PowerShell 5.1 нет `&&`):
|
||||||
|
```powershell
|
||||||
|
cd backend
|
||||||
|
python -m venv .venv
|
||||||
|
.\.venv\Scripts\Activate.ps1 # если ругается на политику: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
|
||||||
|
pip install -e ".[dev]" # .[dev] — один аргумент (пакет + dev-зависимости)
|
||||||
|
Copy-Item ..\.env.example ..\.env # ЕДИНЫЙ .env лежит в КОРНЕ репозитория
|
||||||
|
alembic upgrade head # применит миграции и сидинг
|
||||||
|
python -m app.bootstrap # создаст/синхронизирует администратора из .env
|
||||||
|
uvicorn app.main:app --reload # http://localhost:8000 (Swagger: /api/docs)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Windows cmd.exe** (здесь `&&` поддерживается):
|
||||||
|
```bat
|
||||||
|
cd backend
|
||||||
|
python -m venv .venv
|
||||||
|
.venv\Scripts\activate.bat
|
||||||
|
pip install -e ".[dev]"
|
||||||
|
copy ..\.env.example ..\.env
|
||||||
|
alembic upgrade head
|
||||||
|
python -m app.bootstrap
|
||||||
|
uvicorn app.main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
**Linux / macOS / Git Bash:**
|
||||||
|
```bash
|
||||||
|
cd backend
|
||||||
|
python -m venv .venv && . .venv/Scripts/activate # на *nix: . .venv/bin/activate
|
||||||
|
pip install -e ".[dev]"
|
||||||
|
cp ../.env.example ../.env
|
||||||
|
alembic upgrade head
|
||||||
|
python -m app.bootstrap
|
||||||
|
uvicorn app.main:app --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Единый `.env` — в корне репозитория** (`ForbidenStarsApp/.env`), рядом с `.env.example`.
|
||||||
|
> Его читают и бэкенд (через абсолютный путь, независимо от рабочей папки), и `docker compose`.
|
||||||
|
> Файл — локальный, на каждой машине свой (dev/prod различаются строкой `APP_ENV`).
|
||||||
|
|
||||||
|
### 2) Фронт (в отдельном терминале)
|
||||||
|
```bash
|
||||||
|
cd frontend
|
||||||
|
npm install
|
||||||
|
npm run gen:api # сгенерирует типы из живого OpenAPI (бэкенд должен быть запущен)
|
||||||
|
npm run dev # http://127.0.0.1:5173 или http://localhost:5173 (оба стека)
|
||||||
|
```
|
||||||
|
|
||||||
|
Вход в dev-режиме — экран `/login`: в деве доступны оба метода (Telegram + вход по нику),
|
||||||
|
в проде — только Telegram (см. раздел «Аутентификация»).
|
||||||
|
|
||||||
|
## Production (Docker на Pi)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env # заполните SECRET_KEY, ADMIN_PASSWORD и пр.
|
||||||
|
docker compose build # на ARM64 собирается нативно
|
||||||
|
docker compose up -d # приложение на :8000, БД на томе
|
||||||
|
```
|
||||||
|
|
||||||
|
FastAPI отдаёт собранный SPA и API с одного origin. Миграции и бутстрап админа
|
||||||
|
выполняются автоматически при старте (`entrypoint.sh`).
|
||||||
|
|
||||||
|
## Test — локальный прод-клон в контейнере
|
||||||
|
|
||||||
|
Тот же образ и поведение, что и прод (FastAPI отдаёт SPA, БД на томе, вход игроков
|
||||||
|
только через Telegram), но на своей машине — для проверки прод-сборки до выката на Pi.
|
||||||
|
Изолированные тома и порт **8080** (не конфликтует с dev-uvicorn на :8000).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.test.example .env.test # заполнить при необходимости
|
||||||
|
docker compose --env-file .env.test -f docker-compose.test.yml up -d --build
|
||||||
|
# открыть http://localhost:8080 (Swagger: /api/docs)
|
||||||
|
docker compose -f docker-compose.test.yml down -v # остановить и стереть тестовые данные
|
||||||
|
```
|
||||||
|
|
||||||
|
- Окружение принудительно `production` (клон Pi), но `COOKIE_SECURE=false` (локально HTTP).
|
||||||
|
- Данные — на отдельных томах `db-data-test` / `uploads-data-test` (не пересекаются с dev и Pi).
|
||||||
|
- Вход: **админ-панель** (`/admin/login`) работает сразу по логину/паролю; вход **игроков** —
|
||||||
|
только через Telegram (нужен бот + публичный HTTPS/туннель на `localhost:8080`).
|
||||||
|
- Если пароль/секрет содержит `$`, для docker compose экранируйте его как `$$`
|
||||||
|
(для dev-uvicorn экранирование не нужно — pydantic читает `$` дословно).
|
||||||
|
|
||||||
|
## Аутентификация
|
||||||
|
|
||||||
|
Методы входа зависят от окружения (`APP_ENV`):
|
||||||
|
|
||||||
|
| | dev | prod |
|
||||||
|
|---|---|---|
|
||||||
|
| Telegram Login Widget | ✓ | ✓ (единственный) |
|
||||||
|
| Вход по нику (stub) | ✓ | ✗ (физически отсутствует) |
|
||||||
|
|
||||||
|
- **Stub-вход (по нику)** — только для разработки. Его код **физически не попадает в прод:**
|
||||||
|
файлы `backend/app/auth/dev_stub.py` и `backend/app/routers/dev_auth.py` исключены из
|
||||||
|
Docker-образа (`.dockerignore`), роутер подключается лишь при `APP_ENV != production`
|
||||||
|
(`app/main.py`), а на фронте dev-блок вырезается из прод-сборки (`import.meta.env.DEV`).
|
||||||
|
- **Telegram:** сервер проверяет подпись виджета (HMAC по `TELEGRAM_BOT_TOKEN`).
|
||||||
|
`GET /api/auth/config` отдаёт доступные методы и `telegram_bot_username` для виджета.
|
||||||
|
|
||||||
|
**Настройка Telegram (когда будете подключать реальный вход):**
|
||||||
|
1. Создать бота у [@BotFather](https://t.me/BotFather) → получить **токен** и **username**.
|
||||||
|
2. `/setdomain` у BotFather → ваш HTTPS-домен (где открывается приложение).
|
||||||
|
3. В `.env`: `TELEGRAM_BOT_TOKEN=...`, `TELEGRAM_BOT_USERNAME=...` (без `@`).
|
||||||
|
4. Домену нужен HTTPS (например, Cloudflare Tunnel) — виджет не работает по голому HTTP.
|
||||||
|
|
||||||
|
Админ-вход (секретная панель, логин+пароль) — отдельный механизм, доступен в обоих окружениях.
|
||||||
|
|
||||||
|
## Окружения (dev / test / prod)
|
||||||
|
|
||||||
|
Один и тот же код; контур выбирается тем, **чем и с каким `.env` запускаешь**:
|
||||||
|
|
||||||
|
| | dev | test (прод-клон локально) | prod (Pi) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Запуск | `uvicorn --reload` + `vite` | `docker compose -f docker-compose.test.yml` | `docker compose` |
|
||||||
|
| Env-файл | `.env` (корень) | `.env.test` (корень) | `.env` (корень, на Pi) |
|
||||||
|
| `APP_ENV` | `development` | `production` (форсится) | `production` (форсится) |
|
||||||
|
| Раздача SPA | Vite (HMR), :5173 | FastAPI, :8080 | FastAPI, :8000 |
|
||||||
|
| База данных | `backend/data/dev/…` | том `db-data-test` (`/data`) | том `db-data` (`/data`) |
|
||||||
|
| Вход игроков | Telegram + ник (stub) | только Telegram | только Telegram |
|
||||||
|
|
||||||
|
- **Структура БД одна** (общие миграции Alembic), **файлы разные** — путь выбирается по
|
||||||
|
`APP_ENV` (`DEV_DATABASE_URL` / `PROD_DATABASE_URL`). Данные дева — в `backend/data/dev/`
|
||||||
|
(в образ **не попадают**: `data/` в `.dockerignore`).
|
||||||
|
- **В Docker идёт только прод-код:** контейнер принудительно `APP_ENV=production`, dev-вход
|
||||||
|
(stub) физически исключён из образа. `test` — это тот же прод-образ, просто локально.
|
||||||
|
- **`.env` один на машину**, в корне (рядом с `.env.example`). `test` использует свой
|
||||||
|
`.env.test` (чтобы крутить прод-клон рядом с dev, не мешая ему). Реальные `.env`/`.env.test`
|
||||||
|
хранятся только локально; рядом лежат шаблоны `*.example`.
|
||||||
|
|
||||||
|
## Дополнения и фракции
|
||||||
|
|
||||||
|
| Дополнение | Фракции |
|
||||||
|
|---|---|
|
||||||
|
| База (всем) | Орки, Ультрамарины, Эльдары, Хаоситы |
|
||||||
|
| Forgotten Worlds | Имперская гвардия, Тау, Некроны, Тираниды |
|
||||||
|
| Forsaken Voids | Инквизиция, Сёстры битвы, Друкхари, Адептус Механикус |
|
||||||
|
|
||||||
|
Группа отмечает имеющиеся дополнения; при создании партии доступны только фракции
|
||||||
|
этих дополнений (база — всегда).
|
||||||
Reference in New Issue
Block a user