CI/CD
Качество кода защищено тремя слоями (defense in depth): Gate 1 — проверки перед коммитом и PR в цикле разработки, Gate 2 — pre-commit хук, Gate 3 — CI в GitHub Actions. Доставка — GitHub Actions → GHCR → Coolify (для документации — auto-deploy из Git). Устройство окружений — Развёртывание.
Гейты качества
| Гейт | Где | Что проверяет |
|---|---|---|
| Gate 1 | фаза SHIP цикла /op + консультативный Stop-хук | backend: lint, тесты, сборка, покрытие документации (docs:coverage); frontend: lint, typecheck, unit-тесты, сборка, e2e |
| Gate 2 | pre-commit (husky + lint-staged, backend/) | по staged backend/src/**/*.ts: eslint --fix и tsc -p tsconfig.build.json --noEmit; коммит блокируется при неисправимой ошибке |
| Gate 3 | CI (GitHub Actions) | полный набор проверок ниже на каждый PR и push |
Ветки и коммиты: feat/OP-XX-<slug> от develop, сообщения <type>(scope): описание (OP-XX).
Merge PR — чекпоинт человека; develop деплоится на stage, main — на prod.
Workflow'ы
Каждый workflow запускается при изменении своего каталога (paths), на push в main/develop, на
pull_request и вручную (workflow_dispatch, без деплоя). Деплой-job выполняется только на push.
backend-ci.yml (backend/**)
Job build-and-check поднимает сервисы pgvector/pgvector:pg16 и redis:7-alpine, Node 22:
| Шаг | Команда |
|---|---|
| Установка | npm ci |
| Аудит зависимостей | npm audit --omit=dev --audit-level=high (не блокирует) |
| Lint | npm run lint |
| Юнит-тесты | npm test |
| Миграции — применить | npm run migration:run |
| e2e + цикл миграций | npm run test:e2e (применить → откатить → применить) |
| Сборка | npm run build |
| Покрытие документации | npm run docs:coverage (порог 80 %) |
| Контракт OpenAPI | npm run docs:openapi, артефакт openapi.json |
frontend-ci.yml (frontend/**)
npm ci → npm run lint → npm run typecheck → npm run test:unit → npm run build
(NEXT_PUBLIC_API_URL=https://api.optimawb.ru) → установка Chromium → npm run e2e (Playwright;
при падении отчёт сохраняется артефактом на 7 дней).
landing-ci.yml (landing/**)
npm ci → npm run lint → npm run typecheck → npm run build (VITE_APP_ORIGIN, VITE_DOCS_URL).
Портал документации
Отдельного workflow нет: проверка и сборка выполняются Docker-сборкой в Coolify (npm run build внутри
docs-site/Dockerfile). Битые ссылки в документации ломают сборку, поэтому перед пушем запускайте
npm run build в docs-site/ (Локальная разработка).
Доставка (CD)
После успешных проверок на push job deploy собирает образ и публикует его в GHCR, затем дёргает
deploy-webhook Coolify (curl --fail, заголовок Authorization: Bearer ${{ secrets.COOLIFY_TOKEN }}).
| Приложение | Образ GHCR | prod (main) | stage (develop) |
|---|---|---|---|
| Backend | ghcr.io/affiliatefabriq/optima-backend | api.optimawb.ru | webhook stage |
| Frontend | ghcr.io/affiliatefabriq/optima-frontend | app.optimawb.ru | webhook stage |
| Landing | ghcr.io/affiliatefabriq/optima-landing | optimawb.ru | webhook stage |
| Docs-site | — (сборка в Coolify) | docs.optimawb.ru | auto-deploy из Git |
- Теги образа:
latest(изmain) илиdevelop(изdevelop) +sha-<short>. - Сборка
linux/amd64с кэшем GitHub Actions;concurrencyотменяет устаревшие деплои той же ветки. - Публикация в GHCR — встроенным
GITHUB_TOKEN(праваpackages: write). - Backend: образ при старте сам применяет миграции (см. Развёртывание).
- Docs-site деплоится через GitHub App Coolify:
main→ prod,develop→ stage; Watch Paths —docs-site/**иbackend/**.
Секреты GitHub
Settings → Secrets and variables → Actions:
| Секрет | Назначение |
|---|---|
COOLIFY_TOKEN | API-токен Coolify с правом Deploy |
COOLIFY_WEBHOOK_BACKEND_PROD / COOLIFY_WEBHOOK_BACKEND_STAGE | deploy-webhook бэкенда |
COOLIFY_WEBHOOK_FRONTEND_PROD / COOLIFY_WEBHOOK_FRONTEND_STAGE | deploy-webhook фронтенда |
COOLIFY_WEBHOOK_LANDING_PROD / COOLIFY_WEBHOOK_LANDING_STAGE | deploy-webhook лендинга |
URL webhook берётся из карточки приложения в Coolify. Для docs-site секреты не нужны. Секреты приложений (JWT, ключи шифрования, LLM и т. д.) хранятся в Coolify, а не в GitHub; в CI используются только заглушки для тестов.
Когда проверка падает
- Lint/typecheck — исправьте локально той же командой; хук Gate 2 ловит большинство случаев до коммита.
docs:coverage— публичному коду не хватает TSDoc: документируйте классы, методы и DTO вместе с кодом.- Контракт OpenAPI — изменился набор эндпоинтов: обновите ожидаемый список в
backend/test/openapi.e2e-spec.tsи перегенерируйте клиент фронтенда (npm run api:generate). - Миграции — проверьте, что
down()корректно откатываетup(): e2e гоняет полный цикл.