food-market/docs/sprint21-progress.md
nns 843fc4bd03
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
feat(s21): stage→prod migration toolchain (7 скриптов + workflow)
1. deploy/check-prod-readiness.sh — pre-deploy gating: backup<60min,
   disk≥5GB на /opt+/var/lib/docker, /health/ready=Healthy, .env
   required-keys без placeholder'ов. --ssh-host для удалённой проверки.

2. deploy/prod-deploy.sh <api-tag> <web-tag> — blue-green release:
   pull → green-контейнер на :8088 → migrations (auto) → smoke
   (/health/ready + /api/me с тест-токеном) → nginx upstream switch
   → swap → docker compose up -d с обновлённым тэгом. Failure →
   удаление green, blue остаётся. --skip-web флаг.

3. deploy/prod-rollback.sh <to-tag> — docker pull (если нужно) →
   docker compose up -d --force-recreate с указанным tag'ом → wait
   /health/ready до 120с. --dry-run + --skip-web.

4. deploy/post-deploy-smoke.sh — 10 шагов (signup → login →
   /api/me → list products/counterparties/stores/stock → create+delete
   product → logout-via-session). JSON парсится через python3
   (не grep — споткнулись на пробеле перед `:` в access_token).
   Telegram-alert через FM_TG_TOKEN/CHAT при провале. Stage-тест: 10/10 ✓.

5. deploy/db-schema-diff.sh — pg_dump --schema-only с обоих хостов
   через ssh+docker exec, нормализация (sed), diff -u. Exit:
   0=идентичны, 1=разница, 2=ошибка.

6. deploy/generate-release-notes.sh <from-tag> <to-tag> — git log
   group by prefix через awk: feat→, fix→🐛, perf→, docs→📚,
   test/refactor/chore→<details>. Сохраняет docs/release-notes/<tag>.md.

7. .forgejo/workflows/auto-tag.yml — на push в main: если HEAD не
   помечен → создаёт v<YYYYMMDD>.<N> annotated tag, push в origin,
   генерирует release-notes для будущего деплоя.

Все скрипты идемпотентные, поддерживают --dry-run, не трогают прод.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 22:31:10 +05:00

6.7 KiB
Raw Blame History

Sprint 21 — stage→prod migration toolchain

Цель: набор скриптов и workflow'ов чтобы первый прод-деплой был не импровизацией, а одной командой с понятным rollback'ом и автоматическими проверками.

Старт: 2026-06-07 (после Sprint 20). Исполнитель: Claude Opus 4.7.

Принципы

  • Все mutating-скрипты поддерживают --dry-run — печатают что бы сделали.
  • Прод НЕ трогается из этого спринта (только инструментарий).
  • Скрипты — идемпотентные: повторный запуск не ломает уже сделанное.
  • Failure-режим: оставляем старый контейнер, не каскадим ошибку.
  • НЕ трогать: global.json, prod admin.food-market.kz, POS WPF.

Чек-лист

  • 1. Pre-deploy checkdeploy/check-prod-readiness.sh: backup<60min, disk ≥5GB на /opt + /var/lib/docker, /health/ready Healthy, .env содержит required keys без placeholder'ов (CHANGEME/ REPLACE_ME/TODO/dev). Поддерживает --ssh-host для удалённой проверки. Опциональная CI-проверка через FM_CHECK_CI=1.
  • 2. Blue-green deploydeploy/prod-deploy.sh <api-tag> <web-tag>: pull → green-контейнер food-market-api-next на :8088 → migrations (auto через Database.Migrate() в Program.cs) → smoke (/health/ready + /api/me) → nginx upstream switch → swap green→blue. Failure → удаляем green, оставляем blue. --skip-web для api-only.
  • 3. Rollbackdeploy/prod-rollback.sh <to-tag>: docker image inspect + fallback docker pulldocker compose up -d --force-recreate api web с указанным tag'ом → wait /health/ready до 120с. --skip-web поддерживается.
  • 4. Post-deploy smokedeploy/post-deploy-smoke.sh: 10 сценариев (signup → login → /api/me → list 5 endpoints → create product → delete → logout-via-session). Парсит JSON через python3, не grep/cut (после первого фейла на токене с пробелом перед :). Telegram-alert через FM_TG_TOKEN+FM_TG_CHAT при провале. На stage прогнал 10/10 ✓ (тестовая прогонка).
  • 5. Stage-prod schema diffdeploy/db-schema-diff.sh: pg_dump --schema-only --no-owner --no-privileges --no-comments с обоих хостов через ssh + docker exec, нормализация (sed убирает SET/SELECT pg_catalog.set_config/пустые строки/комментарии), diff -u. Exit 0 = идентичны, 1 = разница, 2 = ошибка получения.
  • 6. Release notes generatordeploy/generate-release-notes.sh <from-tag> <to-tag>: git log группирует по prefix через awk: feat → Новые возможности, fix → 🐛 Исправления, perf → , docs → 📚, test/refactor/chore → <details>-свёрнутые. Сохраняет в docs/release-notes/<to-tag>.md. Прогнал на HEAD~3..HEAD — markdown сгенерирован корректно.
  • 7. Auto-tag workflow.forgejo/workflows/auto-tag.yml: на push в main → если HEAD ещё не помечен → создаёт v<YYYYMMDD>.<N> где N — порядковый счётчик в дне. Annotated tag (git tag -a), push в origin, дополнительно генерирует release-notes для будущего деплоя (через deploy/generate-release-notes.sh).

Журнал

2026-06-07 старт

Sprint 20 закрыт (7/7 ✓). Поехали по prod-toolchain.

2026-06-07 итог

Все 7 пунктов ✓. Прод не трогали (по правилам спринта).

Тестовые прогоны на stage (тест.admin.food-market.kz):

  • post-deploy-smoke.sh: 10/10 ✓ (signup, login, /api/me, 5×list, create+delete product, logout-via-session). Первая попытка упала на парсинге access_token (пробел перед : в JSON), починил через python3 -c 'json.load(...)'. Вторая — на отсутствующем /connect/revocation (OpenIddict не сконфигурирован для revoke), заменил step 10 на DELETE сессии через /api/me/sessions/{id} с fallback'ом на token-valid sanity-check.
  • check-prod-readiness.sh: на stage backup-dir /opt/food-market-data/ backups не существует (это нормально для stage'а) — FAIL, как и ожидалось. Скрипт фиксирует это с конкретной причиной.
  • generate-release-notes.sh HEAD~3..HEAD: markdown с группировкой по prefix сгенерирован, файл сохранён в docs/release-notes/.
  • db-schema-diff.sh и prod-deploy.sh / prod-rollback.sh запускать на dev-vm против prod невозможно без SSH-настройки — синтаксис проверен bash -n. Реальный прогон только когда user разрешит.

Итог

Все 7 пунктов ✓. Инструментарий для прод-деплоя готов:

Скрипт Назначение --dry-run Прогон
check-prod-readiness.sh Pre-deploy gating partial (на stage)
prod-deploy.sh Blue-green release синтаксис
prod-rollback.sh Fast rollback синтаксис
post-deploy-smoke.sh Smoke-suite 10 шагов 10/10 ✓ (stage)
db-schema-diff.sh Stage↔prod schema синтаксис
generate-release-notes.sh Markdown release ✓ (HEAD~3..HEAD)
.forgejo/workflows/auto-tag.yml Auto-tag CI синтаксис (yaml)

Что нужно от пользователя для реального прода:

  • /etc/nginx/conf.d/food-market-upstream.conf на prod-vm с upstream food_market_api { server 127.0.0.1:8080; } (создать пустым, скрипт prod-deploy.sh его перепишет).
  • SSH-ключ от dev-vm на prod-vm + alias prod в ~/.ssh/config.
  • FM_TG_TOKEN / FM_TG_CHAT env-vars для notify (опц.).
  • Решение поднять prod-БД и сделать первый backup (food-market-backup.sh).
  • Решение о dns/sertbot для admin.food-market.kz.