food-market/docs/sprint12-progress.md
nns 97e26a65d5 docs(s12): ARCHITECTURE/MULTI-TENANCY/RUNBOOK/DEVELOPER-GUIDE + k6 baseline + stage-verify CI
Документация для следующего разработчика (4 файла, ~1500 строк по
существу), реальный нагрузочный baseline на stage, и автоматический
smoke на каждый push.

Доки:
- docs/ARCHITECTURE.md — карта слоёв, модулей, Program.cs composition
  root, полный поток signup→post с трассировщиком ASP.NET pipeline.
- docs/MULTI-TENANCY.md — ITenantEntity + reflection query-filter,
  stamping в SaveChanges, SuperAdmin override (read-only + edit-mode
  с reason), 8 подводных камней, чеклист «как добавить tenant-сущность».
- docs/RUNBOOK.md — health-чеки, backup/restore с примером, смена SDK,
  disaster-recovery на новый сервер, 6 описанных инцидентов
  (включая docker-compose project name), БД-troubleshooting.
- docs/DEVELOPER-GUIDE.md — локальный setup, гочи integration-тестов,
  полные паттерны (controller с permission + tenant-сущность с
  RowVersion + 5 шагов миграции), валидация, structured-логирование,
  «НЕ делать» список.

k6 baseline:
- tests/load/ — 3 скрипта (signup-burst, retail-sales-parallel,
  sales-report-heavy) + README с инструкциями.
- docs/performance-baseline.md — реальные цифры на stage:
  * signup p95 446ms @ 50 RPM (IP-лимит 60/мин держит);
  * retail-sale sequential — 17/sec, p95 71ms;
  * retail-sale @ VU>1 — 53% failure из-за race в
    GenerateNumberAsync (unique-violation 23505 не ловится в
    SaveOrFkErrorAsync) — P0 для следующего рефакторинга;
  * reports на 1500 чеков — p95 50-114ms до VU=5.

CI:
- .forgejo/workflows/stage-verify.yml — on workflow_run после Docker
  API/Web, wait-for-ready → tests/stage-smoke.sh → Telegram пинг.
- tests/stage-smoke.sh — 7-секундный bash-смок (curl+jq+python3),
  5 этапов: health, signup, token, multi-tenant изоляция (B → 404
  на product A, B → пустой список), полный документ-цикл
  (supplier+supply.post → stock=100 → sale.post → stock=99).
  Локальный прогон против stage — все этапы зелёные.

Build чистый, локальный прогон smoke зелёный. Sprint 12 закрывает
автономно-безопасный цикл — дальше нужен вход от user'а.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-07 03:19:25 +05:00

7.9 KiB
Raw Blame History

Sprint 12 — документация, runbook, нагрузочное тестирование

Цель: переложить «то что знаю только я и комментарии в коде» в читаемые документы для следующего разработчика, замерить реальную производительность под нагрузкой, и закрыть автоматическую верификацию stage-стэйджа на каждый push.

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

Это последний автономно-безопасный спринт. Дальше нужны входы от user'а: реальные ОФД-ApiKey, MoySklad webhook-token'ы, Windows-машина для POS WPF, прод-деплой план, казахские переводы, реальный SMTP-провайдер.

Принципы

  • Документация — для человека, не «AI-портянка». Конкретные пути, имена типов, причины решений. Без воды и эмоций.
  • k6 — реальные числа. Если p95 высокий — пишем как есть.
  • НЕ трогать: global.json, прод-стек, POS WPF.

Чек-лист

  • 1. docs/ARCHITECTURE.md — карта слоёв, модулей, потоков signup→bootstrap→операции. Реальные имена типов и путей, не маркетинг.
  • 2. docs/MULTI-TENANCY.mdITenantEntity + reflection query-filter, stamping в SaveChanges, SuperAdmin override (read-only + edit-mode с reason), 8 подводных камней (IgnoreQueryFilters, фоновые jobs без HttpContext, raw SQL, и т.д.).
  • 3. docs/RUNBOOK.md — health-чеки, backup/restore (включая disaster-recovery), смена SDK, перенос на новый сервер, 6 описанных инцидентов (включая docker-compose project name из ТЗ), troubleshooting БД (stock-агрегат расхождения, audit-log размер, EFMigrationsHistory).
  • 4. docs/DEVELOPER-GUIDE.md — локальный setup, запуск тестов, гочи integration-тестов (Ryuk, rate-limiter eager-config, один ApiFactory), полные паттерны: добавить controller с permission + добавить tenant-сущность с RowVersion + 5 шагов миграции, валидация (DataAnnotations / FluentValidation / бизнес), structured-логирование.
  • 5. k6 нагрузочный тестtests/load/ + 3 скрипта (signup-burst, retail-sales-parallel, sales-report-heavy) + docs/performance-baseline.md с реальными цифрами на stage'е. Главное найденное: race в GenerateNumberAsync при VU > 1 на одном tenant'е (unique-violation 23505 не ловится → 500). Прогон зарегистрирован как P0 для следующего рефакторинга.
  • 6. CI workflow .forgejo/workflows/stage-verify.ymlon workflow_run после Docker API/Docker Web, ждёт /health/ready и запускает tests/stage-smoke.sh (~7с, full-cycle smoke: signup → multi-tenant isolation → supply.post → retail-sale.post → stock check). Telegram-нотификация по успеху/падению.

Журнал

2026-06-07 старт

Sprint 11 закрыт (7/7 ✓). Поехали по docs-чек-листу.

2026-06-07 п.1–п.4 (документация)

Прочитал реальный код: Program.cs composition root, AppDbContext reflection-фильтры, HttpContextTenantContext с AsyncLocal-override, SuperAdminOverrideClaimsTransformer + ReadonlyOverrideMiddleware, RequiresPermissionAttribute + policy-handler, HangfireJobsConfigurator recurring jobs, deploy/Dockerfile + docker-compose, backup-скрипт + systemd-timer.

Написал 4 документа на основе этого:

  • ARCHITECTURE.md (372 строки) — слои + модули + composition root + поток signup→post с детальным трассировщиком ASP.NET pipeline.
  • MULTI-TENANCY.md (256 строк) — query-filter, stamping, SuperAdmin override, 8 подводных камней + чеклист «как добавить tenant-сущность».
  • RUNBOOK.md (337 строк) — health-чеки, backup/restore с примером, смена SDK, disaster-recovery, 6 инцидентов, БД-troubleshooting.
  • DEVELOPER-GUIDE.md (332 строки) — локальный setup, тесты, паттерны (controller + entity + валидация + логирование), "НЕ делать" список.

2026-06-07 п.5 (k6 baseline)

k6 v0.55.0 standalone в ~/bin/k6. 3 скрипта в tests/load/:

  • signup-burst.js: 50 RPM → p95 446ms, 0% errors. 100 RPM → 39% 429 (IP-лимит работает, by design).
  • retail-sales-parallel.js: VU=1 — 17 sales/sec, p95 71ms, 0% failures. VU=5 — 53% failure из-за race в GenerateNumberAsync (unique violation на RetailSale.Number). Это реальная находка, P0 для следующего спринта.
  • sales-report-heavy.js: на tenant'е с 1500 чеков, VU=1 — p95 54ms, VU=4 — p95 81ms, VU=5 — p95 114ms (один аномальный прогон показал 3.8с — autovacuum suspect).

Все цифры в docs/performance-baseline.md с воспроизведением.

2026-06-07 п.6 (CI workflow)

.forgejo/workflows/stage-verify.ymlon: workflow_run после Docker API и Docker Web, не запускается на failed parent (нет смысла верифировать незадеплоенное). Шаги: wait-for-ready (60с retry loop) → запустить tests/stage-smoke.sh → Telegram пинг.

tests/stage-smoke.sh — bash-скрипт без зависимостей кроме curl+jq+python3. 5 этапов: health, signup A, token A, multi-tenant isolation (A создаёт продукт, B получает 404 + список без продукта A), полный документ-цикл (supplier+supply.post → проверка stock=100 → sale.post → проверка stock=99). Локальный прогон против stage — 7 секунд, всё зелёное.

Итог

Все 6 пунктов ✓. Документация:

  • 4 новых файла в docs/ (~1300 строк суммарно).
  • docs/performance-baseline.md — реальные цифры + 1 находка P0.

Тестирование:

  • 3 k6 скрипта в tests/load/.
  • tests/stage-smoke.sh — 7-секундный smoke против stage.

CI:

  • .forgejo/workflows/stage-verify.yml — auto-verify на каждый successful deploy.

Следующие шаги, требующие user'а (за пределами автономного режима):

  1. Реальный ОФД ApiKey (Webkassa предпочтительно) — Sprint 11-fiscal ждёт это для активации.
  2. Решение по прод-деплой (домен + cert + DNS).
  3. MoySklad webhook-токены для inline-импорта.
  4. Windows-машина (или CI runner) для POS WPF сборки.
  5. Казахский переводчик для UI (i18n уже подготовлен).
  6. Реальный SMTP-провайдер для платформы (Mailgun / Postmark / Yandex).

Plus P0-задача из baseline'а: исправить race в GenerateNumberAsync для RetailSalesController и аналогичных контроллеров — это уже автономно делается, но требует дизайн-решения (per-tenant sequence vs counter table vs retry-loop).