Документация для следующего разработчика (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>
7.9 KiB
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.md —
ITenantEntity+ 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.yml—on 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.yml — on: 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'а (за пределами автономного режима):
- Реальный ОФД ApiKey (Webkassa предпочтительно) — Sprint 11-fiscal ждёт это для активации.
- Решение по прод-деплой (домен + cert + DNS).
- MoySklad webhook-токены для inline-импорта.
- Windows-машина (или CI runner) для POS WPF сборки.
- Казахский переводчик для UI (i18n уже подготовлен).
- Реальный SMTP-провайдер для платформы (Mailgun / Postmark / Yandex).
Plus P0-задача из baseline'а: исправить race в GenerateNumberAsync
для RetailSalesController и аналогичных контроллеров — это уже
автономно делается, но требует дизайн-решения (per-tenant sequence vs
counter table vs retry-loop).