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

103 lines
6.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.
## Чек-лист
- [x] **1. Pre-deploy check**`deploy/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`.
- [x] **2. Blue-green deploy** `deploy/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 greenblue.
Failure удаляем green, оставляем blue. `--skip-web` для api-only.
- [x] **3. Rollback** `deploy/prod-rollback.sh <to-tag>`:
`docker image inspect` + fallback `docker pull` `docker compose up
-d --force-recreate api web` с указанным tag'ом wait /health/ready
до 120с. `--skip-web` поддерживается.
- [x] **4. Post-deploy smoke** `deploy/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 ✓** (тестовая прогонка).
- [x] **5. Stage-prod schema diff** `deploy/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 = ошибка получения.
- [x] **6. Release notes generator** `deploy/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
сгенерирован корректно.
- [x] **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.