Устаревшие комментарии и подсказки в коде, export-скрипты; мусорный файл в репозитории (#70) #99

Merged
NotBigGhost merged 1 commits from issue-70-stale-comments into dev 2026-09-30 13:05:53 +03:00
18 changed files with 25 additions and 111 deletions
Showing only changes of commit ec1e94119c - Show all commits
+4 -4
View File
@@ -6,7 +6,7 @@
# ─── ГЛАВНЫЙ ПЕРЕКЛЮЧАТЕЛЬ ──────────────────────────────────────────────────── # ─── ГЛАВНЫЙ ПЕРЕКЛЮЧАТЕЛЬ ────────────────────────────────────────────────────
# Этот параметр читает ЛАУНЧЕР (run.ps1 / run.sh) и решает, что запускать: # Этот параметр читает ЛАУНЧЕР (run.ps1 / run.sh) и решает, что запускать:
# development — нативно: uvicorn --reload + vite, БД в ./data/dev/, вход TG+ник # development — нативно: uvicorn --reload + vite, БД в ./data/dev/, есть вход по нику (stub)
# production — НЕ запускается лаунчером; деплой на Pi отдельно (docker compose up -d). # production — НЕ запускается лаунчером; деплой на Pi отдельно (docker compose up -d).
# Прод-контейнер ИГНОРИРУЕТ это значение и всегда production. # Прод-контейнер ИГНОРИРУЕТ это значение и всегда production.
APP_ENV=development APP_ENV=development
@@ -44,8 +44,8 @@ ADMIN_NICKNAME=Администратор
ADMIN_BOOTSTRAP_ENABLED=true ADMIN_BOOTSTRAP_ENABLED=true
# ─── АУТЕНТИФИКАЦИЯ ИГРОКОВ ─────────────────────────────────────────────────── # ─── АУТЕНТИФИКАЦИЯ ИГРОКОВ ───────────────────────────────────────────────────
# Методы входа задаёт APP_ENV: dev → Telegram + stub (вход по нику), prod → только # Вход везде — логин/пароль и Telegram; в development ещё stub (по нику без пароля).
# Telegram. Для Telegram нужны токен и юзернейм бота (@BotFather). /setdomain у # Для Telegram нужны токен и юзернейм бота (@BotFather). /setdomain у
# BotFather укажи на ОБА домена, где открывается виджет: forbiddenstars.ru (prod) # BotFather укажи на ОБА домена, где открывается виджет: forbiddenstars.ru (prod)
# и forbidden-stars.ru (dev). # и forbidden-stars.ru (dev).
TELEGRAM_BOT_TOKEN= TELEGRAM_BOT_TOKEN=
@@ -81,7 +81,7 @@ DEV_ACHIEVEMENTS_DIR=./data/dev/achievements
PROD_ACHIEVEMENTS_DIR=/data/achievements PROD_ACHIEVEMENTS_DIR=/data/achievements
# ─── ОБРАЗЫ ПРОДА (реестр для docker compose pull на Pi) ────────────────────── # ─── ОБРАЗЫ ПРОДА (реестр для docker compose pull на Pi) ──────────────────────
# Образы собираются под arm64 на ПК (scripts/build-push.sh) и пушатся в Gitea-реестр, # Образы собираются под arm64 на ПК (scripts/build-push.ps1; в Linux — .sh) и пушатся в Gitea-реестр,
# а Pi их тянет (docker compose pull). Owner в пути — строчными. Тег можно версионировать. # а Pi их тянет (docker compose pull). Owner в пути — строчными. Тег можно версионировать.
# Перед пушем/пуллом: docker login gitea.arseniev.info # Перед пушем/пуллом: docker login gitea.arseniev.info
IMAGE_REGISTRY=gitea.arseniev.info/notbigghost IMAGE_REGISTRY=gitea.arseniev.info/notbigghost
-13
View File
@@ -3,16 +3,3 @@
# Скрипты образов (entrypoint.sh, deploy/*/…) контейнер дополнительно чинит sed-ом при сборке. # Скрипты образов (entrypoint.sh, deploy/*/…) контейнер дополнительно чинит sed-ом при сборке.
*.sh text eol=lf *.sh text eol=lf
backend/entrypoint.sh text eol=lf backend/entrypoint.sh text eol=lf
# ── export-ignore: НЕ попадает в `git archive` (чистая выгрузка прода) ─────────
# В git эти файлы есть и доступны на всех ветках (нужны для разработки),
# но в архив деплоя (scripts/export-prod.sh) не идут. На Docker-сборку НЕ влияет —
# там чистоту образа обеспечивает .dockerignore.
backend/tests/ export-ignore
backend/app/auth/dev_stub.py export-ignore
backend/app/routers/dev_auth.py export-ignore
backend/pyproject.toml export-ignore
README.md export-ignore
.gitignore export-ignore
.gitattributes export-ignore
.dockerignore export-ignore
+1 -5
View File
@@ -16,7 +16,7 @@
backend/ FastAPI: ядро, REST API, БД, миграции Alembic, seed, тесты backend/ FastAPI: ядро, REST API, БД, миграции Alembic, seed, тесты
frontend/ React + Vite SPA frontend/ React + Vite SPA
deploy/ публикация и эксплуатация: vps/ (Caddy), pi/ (прод), tunnel/ и backup/ (образы) deploy/ публикация и эксплуатация: vps/ (Caddy), pi/ (прод), tunnel/ и backup/ (образы)
scripts/ build-push.* (сборка и пуш образов), fs-backup.* (бэкапы с ПК), export-prod.sh scripts/ build-push.* (сборка и пуш образов), fs-backup.* (бэкапы с ПК)
Dockerfile multi-stage сборка (фронт собирается node, отдаётся FastAPI) Dockerfile multi-stage сборка (фронт собирается node, отдаётся FastAPI)
docker-compose.yml прод на Pi: app + tunnel + backup docker-compose.yml прод на Pi: app + tunnel + backup
docker-compose.temp.yml временный прод на ПК вместо Pi: app + tunnel docker-compose.temp.yml временный прод на ПК вместо Pi: app + tunnel
@@ -214,10 +214,6 @@ docker compose up -d # pull_policy: always — тянет свежие
- **Деплой на Pi:** на ПК с ветки `main` — `.\scripts\build-push.ps1` (собирает и пушит - **Деплой на Pi:** на ПК с ветки `main` — `.\scripts\build-push.ps1` (собирает и пушит
образы app + tunnel + backup под arm64), на Pi — `docker compose up -d`. На Windows нужна образы app + tunnel + backup под arm64), на Pi — `docker compose up -d`. На Windows нужна
именно PS-версия скрипта (`build-push.sh` из PowerShell уходит в WSL). именно PS-версия скрипта (`build-push.sh` из PowerShell уходит в WSL).
- **Чистая выгрузка в папку без git** (опц., к деплою на Pi не относится):
`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`. Секреты (`.env`) и данные (`data/`, `*.db`) в git не идут — см. `.gitignore`.
+3 -2
View File
@@ -2,8 +2,9 @@
Тонкий слой поверх `admin_service.authenticate_admin`: throttle по IP, по паре «IP + логин» Тонкий слой поверх `admin_service.authenticate_admin`: throttle по IP, по паре «IP + логин»
и по самому аккаунту через тот же `LoginThrottle`, что и вход игрока (`core/ratelimit`). и по самому аккаунту через тот же `LoginThrottle`, что и вход игрока (`core/ratelimit`).
Сервис остаётся чистым от инфраструктуры лимитов. Пароль администратора — единственный Сервис остаётся чистым от инфраструктуры лимитов. Лимиты те же, что у игрока (5 на пару,
барьер к полному контролю приложения, поэтому перебор здесь ограничиваем строже игроцкого. 20 на IP, 50 на аккаунт за 15 минут); отличие — при успешном входе снимаются все счётчики,
включая IP.
""" """
from __future__ import annotations from __future__ import annotations
+1 -1
View File
@@ -1,4 +1,4 @@
"""Dev-провайдер: вход без секрета по нику/идентификатору (только не-production).""" """Dev-провайдер: вход без секрета по нику/идентификатору (только development)."""
from __future__ import annotations from __future__ import annotations
from typing import Any from typing import Any
+2 -2
View File
@@ -1,7 +1,7 @@
"""Общий вход: внешняя личность → пользователь → сессия. """Общий вход: внешняя личность → пользователь → сессия.
Прод-безопасный модуль (без импортов dev-провайдера). Используется и Telegram-входом, Прод-безопасный модуль (без импортов dev-провайдера). establish_session зовут вход через
и dev-входом. Telegram, /auth/login, /auth/register и dev-вход.
""" """
from __future__ import annotations from __future__ import annotations
+1 -1
View File
@@ -2,7 +2,7 @@
Проверяет подпись данных виджета (HMAC-SHA256 ключом SHA256(BOT_TOKEN)) и свежесть Проверяет подпись данных виджета (HMAC-SHA256 ключом SHA256(BOT_TOKEN)) и свежесть
auth_date. Нужны TELEGRAM_BOT_TOKEN (+ TELEGRAM_BOT_USERNAME для виджета на фронте). auth_date. Нужны TELEGRAM_BOT_TOKEN (+ TELEGRAM_BOT_USERNAME для виджета на фронте).
Доступен и в dev, и в prod (в prod — единственный метод входа). Доступен во всех окружениях — наряду со входом по логину и паролю.
""" """
from __future__ import annotations from __future__ import annotations
+3 -3
View File
@@ -31,7 +31,7 @@ class Settings(BaseSettings):
) )
# ── Главный переключатель окружения: development | production ───────────── # ── Главный переключатель окружения: development | production ─────────────
# development — нативный dev (uvicorn + vite), БД в ./data/dev/, вход Telegram+ник. # development — нативный dev (uvicorn + vite), БД в ./data/dev/, есть stub-вход по нику.
# production — Docker на Pi; контейнер форсит это значение, игнорируя .env. # production — Docker на Pi; контейнер форсит это значение, игнорируя .env.
app_env: str = "development" app_env: str = "development"
log_level: str = "INFO" log_level: str = "INFO"
@@ -67,8 +67,8 @@ class Settings(BaseSettings):
# cookie_secure НЕ задаётся вручную — выводится из окружения (см. property ниже). # cookie_secure НЕ задаётся вручную — выводится из окружения (см. property ниже).
cookie_domain: str | None = None cookie_domain: str | None = None
# Аутентификация. Методы входа определяются окружением (dev: telegram+stub, # Аутентификация. Методы входа определяются окружением (auth/registry.py): везде
# prod: только telegram) — отдельного переключателя провайдера нет. # логин/пароль + Telegram, в development ещё stub — отдельного переключателя нет.
telegram_bot_token: str | None = None telegram_bot_token: str | None = None
telegram_bot_username: str | None = None telegram_bot_username: str | None = None
public_base_url: str | None = None public_base_url: str | None = None
+1 -1
View File
@@ -6,7 +6,7 @@
* рестарт (в т.ч. деплой) сбрасывает окно — злоумышленник получает новую квоту после * рестарт (в т.ч. деплой) сбрасывает окно — злоумышленник получает новую квоту после
перезапуска, но окно короткое, а рестарты редки; перезапуска, но окно короткое, а рестарты редки;
* при уходе от одного воркера лимит делится между процессами (каждый считает своё) — * при уходе от одного воркера лимит делится между процессами (каждый считает своё) —
тогда счётчики нужно вынести во внешний стор (Redis pub/sub, как отмечено в CLAUDE.md тогда счётчики нужно вынести во внешний стор (Redis pub/sub, как отмечено в core/events.py
про SSE-шину), общий для всех воркеров. про SSE-шину), общий для всех воркеров.
Помимо пары «IP + логин» и лимита по IP есть IP-независимый лимит на аккаунт Помимо пары «IP + логин» и лимита по IP есть IP-независимый лимит на аккаунт
(`login-user:*` / `admin-login-user:*`), чтобы ротация X-Forwarded-For / многих адресов (`login-user:*` / `admin-login-user:*`), чтобы ротация X-Forwarded-For / многих адресов
+2 -2
View File
@@ -175,6 +175,6 @@ def is_session_revoked(payload: dict) -> bool:
def client_ip(request: Request) -> str | None: def client_ip(request: Request) -> str | None:
"""IP клиента для журнала аудита. """IP клиента для журнала аудита.
Одна точка на всё приложение: за VPS-привратником адрес придётся брать из Одна точка на всё приложение. Реальный адрес за VPS-привратником уже подставляет
X-Forwarded-For, и менять это в двух десятках роутеров — не вариант.""" uvicorn (--proxy-headers + --forwarded-allow-ips в entrypoint.sh) — отсюда он и берётся."""
return request.client.host if request.client else None return request.client.host if request.client else None
-21
View File
@@ -1,21 +0,0 @@
"""Инициализация схемы и справочников (для тестов и локального быстрого старта).
В production схема создаётся миграциями Alembic; этот модуль удобен для тестов,
где БД поднимается из чистого состояния.
"""
from __future__ import annotations
from sqlmodel import SQLModel
from app.db.session import engine
from app.seed.reference_data import seed_reference_data
from sqlmodel import Session
# Импорт моделей обязателен, чтобы они зарегистрировались в SQLModel.metadata.
import app.models # noqa: F401
def create_db_and_seed() -> None:
SQLModel.metadata.create_all(engine)
with Session(engine) as session:
seed_reference_data(session)
+2 -2
View File
@@ -1,8 +1,8 @@
"""DEV-ТОЛЬКО роутер: вход по нику (stub) + тестовые пользователи. """DEV-ТОЛЬКО роутер: вход по нику (stub) + тестовые пользователи.
Этот файл и app/auth/dev_stub.py ФИЗИЧЕСКИ исключены из прод-образа (.dockerignore), Этот файл и app/auth/dev_stub.py ФИЗИЧЕСКИ исключены из прод-образа (.dockerignore),
а подключается роутер лишь когда APP_ENV != production (см. app/main.py). Так код а подключается роутер лишь при APP_ENV=development (см. app/main.py). Так вход
входа по логину остаётся только на деве. без пароля остаётся только на деве (по логину и паролю входят везде).
""" """
from __future__ import annotations from __future__ import annotations
+1 -1
View File
@@ -1,7 +1,7 @@
# Caddy на VPS (186.246.51.17) — единственная публичная точка входа. # Caddy на VPS (186.246.51.17) — единственная публичная точка входа.
# Два домена, ОБА с твоими сертификатами; проксируют в SSH-туннели: # Два домена, ОБА с твоими сертификатами; проксируют в SSH-туннели:
# #
# forbiddenstars.ru → 127.0.0.1:9000 ← Pi (autossh, постоянно) PROD # forbiddenstars.ru → 127.0.0.1:9000 ← Pi (туннель-контейнер, ssh + restart) PROD
# forbidden-stars.ru → 127.0.0.1:9001 ← ПК (по требованию) DEV # forbidden-stars.ru → 127.0.0.1:9001 ← ПК (по требованию) DEV
# #
# Caddy сам терминирует TLS (он и есть edge: видит реального клиента), а вниз к # Caddy сам терминирует TLS (он и есть edge: видит реального клиента), а вниз к
+2 -2
View File
@@ -21,8 +21,8 @@
services: services:
app: app:
build: . build: .
# Образ из реестра (Gitea): собирается под arm64 на ПК (scripts/build-push.sh) и тянется # Образ из реестра (Gitea): собирается под arm64 на ПК (scripts/build-push.ps1, в Linux —
# на Pi через `docker compose pull`. build: оставлен как локальный фолбэк (сборка на Pi). # .sh) и тянется на Pi. build: нужен только этой сборке на ПК — на Pi не используется.
image: ${IMAGE_REGISTRY:-gitea.arseniev.info/notbigghost}/forbidden-stars:${IMAGE_TAG:-latest} image: ${IMAGE_REGISTRY:-gitea.arseniev.info/notbigghost}/forbidden-stars:${IMAGE_TAG:-latest}
pull_policy: always # на Pi всегда тянем образ из реестра (без сборки) pull_policy: always # на Pi всегда тянем образ из реестра (без сборки)
restart: unless-stopped restart: unless-stopped
-29
View File
@@ -1,29 +0,0 @@
commit 65bebf8b85fcbf921cbbc4f2599953a9fa3ca9c6 (HEAD -> dev)
Author: NotBigGhost <ivan@arseniev.info>
Date: Wed Jun 17 04:45:33 2026 +0300
Добавление ssh-ключа к контейнеру tunnel
commit 7e8b748caf5d9f4ab3d2d7f76d6a4b850b9b1366
Author: NotBigGhost <ivan@arseniev.info>
Date: Wed Jun 17 04:27:11 2026 +0300
Правки локального размещения дева, перенос тунеля в контейнер
commit b04fbb2e171a7fe3376f3633dfee9e29e4e4bb90
Author: NotBigGhost <ivan@arseniev.info>
Date: Tue Jun 16 19:15:54 2026 +0300
Завершена настройка домена для дева, теста и прода. Соединение через ssh-туннель
commit 56b5d09a4dc5e6f5d06e32c2635c84a66597e71f (origin/main, main)
Author: NotBigGhost <ivan@arseniev.info>
Date: Tue Jun 16 17:41:06 2026 +0300
v0.1 - макет интерфейса, аутентификация через логин, аккаунт админа, создание партии в 2 этапа, базовые настройки профиля и группы, переключение между группами, статистика
commit 6ab74f01aaf1ac042a269c7660b3e564b93350c7
Author: NotBigGhost <ivan@arseniev.info>
Date: Tue Jun 16 16:53:41 2026 +0300
first commit
+1 -1
View File
@@ -135,7 +135,7 @@ switch ($appEnv) {
} }
"production" { "production" {
Write-Host "production is not started by the launcher - prod is separate." -ForegroundColor Yellow Write-Host "production is not started by the launcher - prod is separate." -ForegroundColor Yellow
Write-Host "Deploy on Pi (from main branch): docker compose up -d --build" Write-Host "Deploy: PC (main branch) scripts\build-push.ps1, then on Pi: docker compose up -d"
exit 1 exit 1
} }
default { default {
+1 -1
View File
@@ -85,7 +85,7 @@ case "$app_env" in
;; ;;
production) production)
echo "production лаунчером не запускается — прод обособлен." echo "production лаунчером не запускается — прод обособлен."
echo "Деплой на Pi (из ветки main): docker compose up -d --build" echo "Деплой: на ПК (ветка main) scripts/build-push.sh, затем на Pi: docker compose up -d"
exit 1 exit 1
;; ;;
*) *)
-20
View File
@@ -1,20 +0,0 @@
#!/usr/bin/env bash
# Выгрузка ПРОДА: в целевую папку попадают только файлы, нужные для запуска
# прод-контейнера (без тестов, dev-входа и dev-лаунчера).
#
# Использование: scripts/export-prod.sh <целевая-папка> [git-ref]
# git-ref по умолчанию HEAD; для прод-ветки: scripts/export-prod.sh /srv/fs prod
set -euo pipefail
DEST="${1:?Укажите целевую папку: scripts/export-prod.sh <dir> [ref]}"
REF="${2:-HEAD}"
mkdir -p "$DEST"
# git archive уважает export-ignore из .gitattributes (тесты, dev-вход и т.п. отсеяны)
git archive --format=tar "$REF" | tar -x -C "$DEST"
# dev-специфика в проде не нужна (лаунчер)
rm -f "$DEST/run.ps1" "$DEST/run.sh"
echo "[export-prod] Прод выгружен в: $DEST"
echo " дальше: cp .env.example .env && docker compose up -d --build"