Единственный оформленный способ деплоя в репозитории — Docker-образ по
корневому Dockerfile, без Docker Compose и без CI-пайплайна
(.gitlab-ci.yml/.github/workflows в репозитории нет — сборка и
раскладка по продакшену делаются вручную/через Coolify).
Multi-stage сборка:
- Слой
claude-cli(node:22-bookworm-slim) — ставит@anthropic-ai/claude-codeглобально черезnpm. - Основной слой (
python:3.12-slim) — копируетnode,claudeи его модули из первого слоя, ставит проект черезpip install .(без dev-зависимостей), создаёт непривилегированного пользователяappи каталог/data/running-portalдля рантайм-данных.
Ключевые ENV, зашитые прямо в Dockerfile (переопределяются реальными
переменными окружения контейнера при деплое):
PORT=8000
DB_PATH=/data/running-portal/portal.db
MI_FITNESS_STATE_PATH=/data/running-portal/auth.json
MI_FITNESS_CACHE_DIR=/data/running-portal/fds_cache
HOME=/data/running-portal
CLAUDE_CLI_PATH=/usr/local/bin/claudeHOME=/data/running-portal — не случайность: Claude CLI ищет файл
авторизации в $HOME/.claude, и это значение выравнивает его с тем же
персистентным томом, где лежат portal.db/auth.json, чтобы
Claude-сессия тоже переживала пересоздание контейнера.
Здоровье контейнера проверяется встроенным HEALTHCHECK —
HTTP GET на / (сам портал не имеет отдельного /health-эндпоинта:
portal/routers/health.py — это CRUD журнала состояния, а не
healthcheck; для этой роли используется главная страница).
Всё состояние, которое должно пережить пересоздание контейнера, лежит
под одним каталогом — /data/running-portal (см. ENV выше):
portal.db— SQLite;auth.json— состояние сессии Mi Fitness;fds_cache/— кэш скачанных бинарных файлов Mi Fitness;.claude/(косвенно, черезHOME) — авторизация Claude CLI.
Ни одно из этого не должно попадать в образ или в репозиторий — все
четыре пути либо в .gitignore, либо (для .claude/) вне рабочей
директории проекта в принципе.
docker build -t running-portal .
docker run -p 8000:8000 \
-v running-portal-data:/data/running-portal \
-e MI_FITNESS_COUNTRY_CODE=RU \
running-portalПолный список переменных окружения — в README
(раздел «Конфигурация») и в
.env.production.example.
Портал развёрнут через Coolify на внутреннем dev-сервере — конкретные
параметры (URL, точка монтирования тома, UUID приложения, файл
API-токена, история миграции данных) зафиксированы отдельно в
docs/coolify-deploy.md и не дублируются здесь,
так как это runbook по конкретному инстансу, а не общий рецепт деплоя.
Корневой PRODUCTION_READINESS.md
фиксирует разрыв между текущим состоянием (личный проект, один
пользователь, SQLite, in-process планировщик, прямой subprocess до
Claude CLI) и тем, что нужно для более широкого использования:
шифрование состояния Mi Fitness, аутентификация самого портала,
вынесение синхронизации из HTTP-пути запроса, PostgreSQL + миграции,
внешний воркер вместо APScheduler, наблюдаемость. Ничего из этого в
коде пока не реализовано — считать частью текущей архитектуры нельзя.