food-market/docs/prod-runbook.md
nns b49abfdbd7
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(prod): запуск admin.food-market.kz — бэкапы (hourly/daily/офсайт), restore-verify, мониторинг, deploy-prod
- prod-backup.sh (tier hourly 48ч / daily 30д + uploads), prod-backup-offsite-pull.sh (DR на dev-vm)
- prod-restore-verify.sh: restore во временную БД + сверка числа строк, дроп
- prod-monitor.sh: api/web/public/БД/диск/5xx → Telegram владельцу (+ --test)
- deploy-prod.sh: guard'ы (prod-postgres, .env chmod600, не dev-пароль, quick-login off,
  SEED_DEMO_DATA=false, issuer), бэкап ДО миграций, только --yes, НЕ в ночных
- systemd таймеры (backup-hourly/daily, monitor, offsite-pull); docs/prod-runbook.md

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 19:31:55 +05:00

65 lines
6 KiB
Markdown
Raw 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.

# Рунбук ПРОД admin.food-market.kz (ALL MARKET)
Боевой сервер магазина. Прод-vm **192.168.1.190**, compose **`~/food-market/deploy`**, своя БД
**`food-market-prod-postgres:5437`** (НЕ shared-postgres!). gateway nginx (на хосте, только читать)
проксирует admin.food-market.kz → :8081 (web). Публичный сайт food-market.kz — НЕ трогаем.
## Чек-лист готовности (выполнено 09.10.2026)
- [x] **Образы — релизные теги** (SHA main, не `test`/`latest`): `API_TAG`/`WEB_TAG` в `.env`.
- [x] **Секреты прода отдельны от стенда**, в `~/food-market/deploy/.env` **chmod 600**:
- `POSTGRES_PASSWORD` — сильный (НЕ dev-дефолт). БД своя (5437).
- `OPENIDDICT_ISSUER=https://admin.food-market.kz/`. OpenIddict PFX-ключи генерируются на
сервере в томе `food-market-api-data` (очищен перед стартом → свежие прод-ключи, отдельные
от стенда/dev). `OPENIDDICT_CERT_PASSWORD` пуст (ключи защищены правами ФС).
- `SEED_SUPERADMIN_PASSWORD` — временный, см. ниже.
- VAPID (web-push) — автогенерация в БД (PlatformSettings), секрет не нужен.
- SMTP — НЕ настроен (задаёт владелец; до настройки сброс пароля по email неактивен).
- [x] **Выключено на проде**: quick-login (`QUICK_LOGIN_ENABLED=false` + code safety-override по
issuer), стендовые подсказки, демо-сидеры и тест-орги (`SEED_DEMO_DATA=false` → нет «Demo Market»).
- [x] **SuperAdmin** `admin@food-market.local` — пароль из `SEED_SUPERADMIN_PASSWORD`; **копия
пароля: `~/.fm-watchdog/prod-superadmin-initial.txt` (chmod 600) на dev-vm**. ⚠ Владелец ОБЯЗАН
сменить пароль при первом входе (UI → профиль). Рекомендуется также завести персональный аккаунт.
- [x] Проверено: вход SuperAdmin через https://admin.food-market.kz = HTTP 200; БД пуста
(orgs=0, products=0, users=1=SuperAdmin, roles=4 системных); web SPA = 200; quick-login = 404.
## Деплой прода (ТОЛЬКО вручную)
```
~/deploy-prod.sh --yes # взять теги из прод .env, backup → up
~/deploy-prod.sh <api> <web> --yes --build # пересобрать+push+деплой с новыми тегами
```
- Скрипт с guard'ами: проверяет что compose = food-market-prod-postgres (не shared-postgres),
`.env` chmod 600, НЕ dev-пароль БД, quick-login off, SEED_DEMO_DATA=false, issuer прод.
- Делает **бэкап БД ДО** pull/миграций. Миграции применяются автоматически при старте api
(`AppDbContext.Database.Migrate()` → `/health/ready` = Healthy только после миграций).
- Поднимает `postgres api web` (public НЕ трогает). НЕ в ночных задачах.
## Бэкапы и восстановление
- **Ежечасно** (хранение 48 ч): `food-market-backup-hourly.timer` → `/opt/food-market-data/backups/hourly`.
- **Ежедневно 03:30** (хранение 30 дн + uploads): `food-market-backup-daily.timer` →
`…/backups/daily`; `ExecStartPost` — автопроверка восстановления.
- **Офсайт (другая VM)**: dev-vm таймер `food-market-offsite-pull.timer` (04:00) тянет последний
daily-дамп на dev-vm `~/fm-prod-backups` (хранение 30 дн).
- Формат — `pg_dump -Fc` (pg_restore с параллелизмом/выборочно).
- **Проверка восстановления** (вручную): `~/food-market/deploy/prod-restore-verify.sh` — restore
последнего дампа во временную БД `food_market_restore_test` + сверка числа строк с боевой +
дроп временной. Боевую БД не трогает. Проверено 09.10: все ключевые таблицы совпали.
## Мониторинг
- `food-market-prod-monitor.timer` (каждые 5 мин): api `/health/ready`, web, публичный вход, БД
(`pg_isready`), место на диске (порог 85%), 5xx в логах api за 5 мин. При проблеме — Telegram
владельцу (бот: `~/.fm-watchdog/telegram-{token,chat}` на prod-vm). Лог: `~/.fm-watchdog/prod-monitor.log`.
- Тест уведомления: `~/food-market/deploy/prod-monitor.sh --test` (отправлено 09.10 ✓).
## Откат (rollback)
1. Предыдущий образ: в registry по прошлому SHA. `~/deploy-prod.sh <prev-api> <prev-web> --yes`
(без `--build`) — вернёт прежние теги (бэкап снимется автоматически до переключения).
2. Данные: восстановить из дампа —
`docker exec -i food-market-prod-postgres pg_restore -U food_market -d food_market --clean --if-exists < <дамп>`
(на пустую/битую БД; при живой — сначала остановить api). Дампы: `/opt/food-market-data/backups/{hourly,daily}` или офсайт dev-vm `~/fm-prod-backups`.
3. Проверить `/health/ready` и вход. Если проблема в миграции — откат образа на прошлый SHA
(миграции в этом проекте аддитивные; down-миграции не применяем на проде).
## НЕ трогать
shared-postgres (5434) и его базы (sklad/purchase/calcman/makesales); gateway nginx (только чтение);
стенд (test.admin.food-market.kz); публичный сайт food-market.kz (контейнер public, PUBLIC_TAG=test).