Перейти к основному содержимому

Развёртывание

Все приложения «Оптимы» работают в Coolify на VPS заказчика. PostgreSQL и Redis — управляемые сервисы Coolify. Приложения собираются в Docker-образы; доставка — через GitHub Actions и GHCR либо через GitHub App Coolify (для документации). Процессы проверок и секреты — CI/CD; локальный запуск — Локальная разработка.

Приложения и домены​

Приложение CoolifyКаталогДомен (prod)Источник и сборка
optima-backendbackend/api.optimawb.ruобраз ghcr.io/affiliatefabriq/optima-backend (Docker Image), CD через GitHub Actions + webhook
optima-frontendfrontend/app.optimawb.ruобраз ghcr.io/affiliatefabriq/optima-frontend (Next.js standalone), GitHub Actions + webhook
optima-landinglanding/optimawb.ruобраз ghcr.io/affiliatefabriq/optima-landing (статика за nginx), GitHub Actions + webhook
optima-docsdocs-site/docs.optimawb.ruauto-deploy из Git через GitHub App Coolify, без GHA, GHCR и webhook

TLS и домены выдаёт Coolify. Приложения не зависят друг от друга при деплое: фронтенд знает только URL API (NEXT_PUBLIC_API_URL вшивается на этапе сборки), лендинг — URL приложения и документации.

Окружения и теги образов​

Ветки сопоставлены окружениям:

ВеткаОкружениеТеги образа
mainprodlatest + sha-<short>
developstagedevelop + 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:

  1. build — npm ci, nest build; сборка падает, если нет dist/main.js или раннера миграций dist/core/database/run-migrations.js;
  2. prod-deps — npm ci --omit=dev;
  3. runtime — непривилегированный пользователь node, NODE_ENV=production, порт 3000, healthcheck по GET /health (период 30 с, start-period 60 с — на время миграций).

Миграции применяются при каждом старте контейнера. 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 /, Dockerfile docs-site/Dockerfile, Watch Paths docs-site/** и backend/** (образ встраивает Compodoc, поэтому изменения бэкенда тоже пересобирают доки). Ссылка на Swagger — build-переменная OPTIMA_SWAGGER_URL (в Coolify отметить Build Variable; по умолчанию https://api.optimawb.ru/api/docs), задаётся per-окружение.

Что разворачивается из репозитория, а что нет​

КомпонентГде живёт
PostgreSQL 16 + pgvector, RedisCoolify (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] запускаю приложение….