Развёртывание
Все приложения «Оптимы» работают в Coolify на VPS заказчика. PostgreSQL и Redis — управляемые сервисы Coolify. Приложения собираются в Docker-образы; доставка — через GitHub Actions и GHCR либо через GitHub App Coolify (для документации). Процессы проверок и секреты — CI/CD; локальный запуск — Локальная разработка.
Приложения и домены
| Приложение Coolify | Каталог | Домен (prod) | Источник и сборка |
|---|---|---|---|
optima-backend | backend/ | api.optimawb.ru | образ ghcr.io/affiliatefabriq/optima-backend (Docker Image), CD через GitHub Actions + webhook |
optima-frontend | frontend/ | app.optimawb.ru | образ ghcr.io/affiliatefabriq/optima-frontend (Next.js standalone), GitHub Actions + webhook |
optima-landing | landing/ | optimawb.ru | образ ghcr.io/affiliatefabriq/optima-landing (статика за nginx), GitHub Actions + webhook |
optima-docs | docs-site/ | docs.optimawb.ru | auto-deploy из Git через GitHub App Coolify, без GHA, GHCR и webhook |
TLS и домены выдаёт Coolify. Приложения не зависят друг от друга при деплое: фронтенд знает только URL
API (NEXT_PUBLIC_API_URL вшивается на этапе сборки), лендинг — URL приложения и документации.
Окружения и теги образов
Ветки сопоставлены окружениям:
| Ветка | Окружение | Теги образа |
|---|---|---|
main | prod | latest + sha-<short> |
develop | stage | develop + sha-<short> |
Приложение в Coolify настроено как источник «Docker Image» на соответствующий тег; публикацию образа
завершает вызов deploy-webhook (отдельный секрет на каждое приложение и окружение). Параллельные
деплои одной ветки отменяются (concurrency), так что в работе всегда последний коммит.
Конфигурация окружений — переменные Coolify per-окружение, а не файлы в репозитории: секреты
(JWT_*, ENCRYPTION_KEYS, LLM_API_KEY, доступы к Bull Board и /metrics), DATABASE_URL,
REDIS_URL, CORS_ORIGINS, QUEUE_PREFIX (prod — optima, stage — optima-stage, чтобы очереди не
пересекались в общем Redis). В production приложение отказывается стартовать с заглушками вместо
секретов (Безопасность). Полный перечень — Переменные окружения.
Образ бэкенда и миграции
backend/Dockerfile — многоступенчатая сборка на node:22-alpine:
- build —
npm ci,nest build; сборка падает, если нетdist/main.jsили раннера миграцийdist/core/database/run-migrations.js; - prod-deps —
npm ci --omit=dev; - runtime — непривилегированный пользователь
node,NODE_ENV=production, порт 3000, healthcheck поGET /health(период 30 с,start-period60 с — на время миграций).
Миграции применяются при каждом старте контейнера. Coolify запускает образ как есть и шагов «до
старта» не выполняет, поэтому CMD — скрипт docker-entrypoint.sh:
node dist/core/database/run-migrations.js # миграции (set -e: сбой → контейнер падает)
exec node dist/main # приложение (SIGTERM доходит до Node)
- Раннер не использует ts-node и исходники — только
dist/; источник данных миграций не требует остального env (в нём нет сущностей), поэтому для миграций достаточноDATABASE_URL. - Перед прогоном берётся advisory-lock PostgreSQL: реплики, стартующие одновременно, не применяют миграцию дважды.
- Если миграция упала, новая версия не поднимется, а Coolify оставит работать предыдущую и покажет причину в логе деплоя.
- Предусловие для базы: расширение
vector(pgvector) должно быть доступно в managed PostgreSQL (Данные).
Проверка «применить → откатить → применить» входит в CI (npm run test:e2e, migrations.e2e-spec.ts).
Образы фронтенда, лендинга и документации
- Frontend — Next.js
output: "standalone", запускnode server.jsна порту 3000;NEXT_PUBLIC_API_URLпередаётся build-arg (в CI —https://api.optimawb.ru). - Landing — Vite-сборка, раздача nginx на порту 80; build-arg
VITE_APP_ORIGIN,VITE_DOCS_URL. - Docs-site —
docs-site/Dockerfileсобирается из корня монорепо (нужныdocs-site/иbackend/): первая стадия строит Compodoc бэкенда (npm run docs), вторая — Docusaurus; nginx отдаёт портал и/compodoc. Coolify: Base Directory/, Dockerfiledocs-site/Dockerfile, Watch Pathsdocs-site/**иbackend/**(образ встраивает Compodoc, поэтому изменения бэкенда тоже пересобирают доки). Ссылка на Swagger — build-переменнаяOPTIMA_SWAGGER_URL(в Coolify отметить Build Variable; по умолчаниюhttps://api.optimawb.ru/api/docs), задаётся per-окружение.
Что разворачивается из репозитория, а что нет
| Компонент | Где живёт |
|---|---|
| PostgreSQL 16 + pgvector, Redis | Coolify (managed), бэкапы и доступ — на стороне заказчика |
| Секреты | Coolify per-окружение и GitHub Secrets (только для CD) |
docker-compose.yml | только локальная разработка, в проде не используется |
Эксплуатационные проверки после деплоя
GET https://api.optimawb.ru/health—ok(PostgreSQL и Redis доступны; в production тело краткое);GET /version— версия приложения.- Bull Board
/admin/queuesи/metrics— состояние очередей и метрик (Наблюдаемость). - В логе контейнера строки
[entrypoint] применяю миграции БД…и[entrypoint] запускаю приложение….