171 lines
8.5 KiB
Markdown
171 lines
8.5 KiB
Markdown
# Sprint 28 — docs sync + test coverage gap-fill (overnight)
|
||
|
||
Цель: воспользоваться overnight-окном для накопления реального soak-
|
||
теста (4 часа), параллельно — мелкие реальные улучшения: точность
|
||
auto-generated api-reference, новые integration-тесты, CI-integration.
|
||
|
||
Старт: 2026-06-09 03:15. Исполнитель: Claude Opus 4.7 (autonomous).
|
||
Продолжение [[sprint27_done]].
|
||
|
||
## Что сделано
|
||
|
||
### 1. api-reference.md теперь имеет 240 endpoint'ов (было 195)
|
||
|
||
`ApiReferenceDocsJob` regex для return-type'a слишком строгий — матчил
|
||
только 1-level generic. Не ловил `Task<ActionResult<PagedResult<EmployeeDto>>>`
|
||
(double-nested), поэтому пропускал ~45 endpoint'ов.
|
||
|
||
**Фикс:** новый regex `[^(=;{}\n]+?` для return-type (любой identifier
|
||
с любой глубиной генериков) в:
|
||
- `src/food-market.api/Background/ApiReferenceDocsJob.cs` (runtime job
|
||
для weekly auto-gen в /content-root/api-reference-generated.md)
|
||
- `scripts/gen-api-reference.py` (Python-эквивалент для коммита в репо)
|
||
|
||
Результат: **240 endpoints, 58 controllers** (было 195/57). Пример
|
||
пропуска: `EmployeesController` имел 4 из 5 endpoint'ов; теперь все 5
|
||
(GET /api/organization/employees был пропущен — это list endpoint с
|
||
return типом `Task<ActionResult<PagedResult<EmployeeDto>>>`).
|
||
|
||
### 2. observability.md дополнен (Sprint 20+ + Sprint 26)
|
||
|
||
- Добавлен ряд про `food_market_disk_free_bytes` (Sprint 20 `DiskMonitoringJob`).
|
||
- Новый раздел «quality-watchdog метрики» — 5 метрик textfile exporter'a
|
||
(`quality_watchdog_run_total`, `step_failure_total`, `endpoint_p95_ms`,
|
||
`last_run_status`, `incidents_total`).
|
||
- Раздел «Готовые dashboards» теперь упоминает оба JSON (food-market.json
|
||
+ quality-watchdog.json) с UID/назначением.
|
||
|
||
### 3. Integration spec #7: 1C-CSV import + GDPR org-export
|
||
|
||
`tests/integration/07-import-export-flows.spec.ts`:
|
||
- POST `/api/catalog/products/import/1c-csv` с 1С-форматом
|
||
(Наименование;Штрихкод;Цена;Единица;Группа в semicolon-CSV) →
|
||
возвращает `{created, skipped, errors[], ids[]}`.
|
||
- POST `/api/org/export` (НЕ `/api/admin/org-export`, как я было
|
||
предположил — был баг в моих оригинальных предположениях) →
|
||
возвращает `{id, status, ...}`.
|
||
- orgB не видит export orgA — multi-tenant clean.
|
||
|
||
Прогон 8.2s. Pass.
|
||
|
||
### 4. PruneQualityTestOrgsAsync unit test
|
||
|
||
`tests/food-market.IntegrationTests/PruneQualityTestOrgsTests.cs` — два
|
||
[Fact]'a:
|
||
- `Deletes_only_quality_orgs_older_than_threshold` — 4 org'и (старая
|
||
quality, свежая quality, реальная org, edge-старше-threshold). Threshold
|
||
24h. Удаляет 2 (старую quality + edge). Свежая quality и реальная
|
||
остаются.
|
||
- `Returns_zero_when_no_candidates_match` — только свежая quality →
|
||
deleted=0, org остаётся.
|
||
|
||
Тест требует Testcontainers (PostgreSQL для information_schema +
|
||
DO $$ блоков) — не SQLite. Прогоняется в CI на dev-vm; локально нет
|
||
.NET 8.0.417 SDK (global.json pin).
|
||
|
||
### 5. Forgejo CI workflow: integration suite
|
||
|
||
`.forgejo/workflows/regression.yml` добавлен шаг "Run integration
|
||
cross-feature suite" после regression flows+visual. На failure артефакты
|
||
из tests/integration/reports/ тоже загружаются. Telegram-уведомление
|
||
обновлено: `35 flows + 60 visual + 8 integration`.
|
||
|
||
### 6. 4-часовой soak test запущен в фоне
|
||
|
||
`setsid nohup k6 run ... &` — детачнутая сессия. Параметры:
|
||
- DURATION=4h, RPS=50
|
||
- E2E_ADMIN_URL=stage
|
||
- Output: `/tmp/soak-real/k6.log`, `/tmp/soak-real/summary.json`
|
||
- Monitor: 5-минутный snapshot в `/tmp/soak-real/metrics.csv`
|
||
|
||
ETA финиша: ~07:15. Финальные числа добавлю в этот файл после
|
||
завершения.
|
||
|
||
## Soak: интерим-результаты (на момент 03:46, 31 мин run)
|
||
|
||
| Метрика | Значение | Замечание |
|
||
|---|---|---|
|
||
| iterations | 91371 | 0 interrupted |
|
||
| iter/sec | 49.2 | target 50 (constant-arrival-rate) |
|
||
| api_mem_mb (range) | 250-465 | spike 465 — это redeploy для HSTS, нормальное |
|
||
| api_cpu_pct (steady) | 54-83% | под нагрузкой |
|
||
| pg_connections | 19-56 | spike 56 во время restart, обратно к 19 |
|
||
| disk_free_gb | 30 | без изменений |
|
||
| products p95 | 32-256ms | 256ms был во время старта (warmup) |
|
||
|
||
Зафиксированы 0 failures (`http_req_failed.rate=0.0`). Memory не растёт
|
||
линейно — bounces around 250-300 MiB после warmup.
|
||
|
||
Soak продолжается до ~07:15. Финальные числа в этом разделе после
|
||
завершения.
|
||
|
||
## Дополнительная работа (overnight)
|
||
|
||
После основных 6 пунктов чек-листа также сделано:
|
||
|
||
### 7. fix: ApiReferenceDocsJob handle `~/path` ASP.NET convention
|
||
|
||
`HttpPost("~/connect/token")` — ASP.NET Core конвенция «absolute from
|
||
root, ignore class [Route]». До фикса генератор клеил с base-route'ом →
|
||
`/~/connect/token` (невалидный). Теперь tilde корректно срезается.
|
||
|
||
Виден `/connect/token` в api-reference.md.
|
||
|
||
### 8. fix(security): HSTS header on stage
|
||
|
||
Найдено: stage отдавал security-headers (CSP, X-Frame-Options, etc.) но
|
||
БЕЗ Strict-Transport-Security. Причина: `UseHsts()` в ASP.NET Core не
|
||
срабатывает за nginx-прокси (api видит HTTP, не HTTPS — нет
|
||
ForwardedHeaders middleware'a).
|
||
|
||
Фикс: добавлен `add_header Strict-Transport-Security` в
|
||
`deploy/nginx.conf`. max-age=2592000 (30 дней), без includeSubDomains
|
||
и без preload — pre-emptive consent, можно безопасно убрать.
|
||
|
||
Verified: `curl -I https://test.admin.food-market.kz/` → `strict-transport-security: max-age=2592000`.
|
||
|
||
Integration test `tests/integration/08-security-headers.spec.ts` (2
|
||
[Fact]) проверяет 7 security-заголовков на главной + на 404.
|
||
|
||
### 9. test: ApiReferenceDocsJob regex lock-down
|
||
|
||
`tests/food-market.UnitTests/ApiReferenceDocsJobTests.cs` — создаёт
|
||
временный controller-файл с double-nested generic
|
||
(`Task<ActionResult<PagedResult<Dto>>>`), прогоняет GenerateAsync,
|
||
проверяет count=3 и наличие всех routes в output.
|
||
|
||
Защищает от регрессии Sprint 28 fix'a.
|
||
|
||
### 10. perf: integration suite workers=2 (46% speedup)
|
||
|
||
Раньше `tests/integration/playwright.config.ts` имел `workers: 1`
|
||
из-за signup rate-limit. После Sprint 26 повышения stage до
|
||
5000/min — больше не упирается. Включил `workers: 2` → прогон 66s → 36s.
|
||
|
||
### 11. README + ONBOARDING update до Sprint 28
|
||
|
||
Sprint history дополнен 25-28. Endpoint count обновлён до 240. Sprint
|
||
counter unified.
|
||
|
||
## Метрики
|
||
|
||
| | До Sprint 28 | После | Δ |
|
||
|---|---|---|---|
|
||
| API endpoints в docs/api-reference.md | 195 (из 240) | 240 | +45 |
|
||
| Controllers в reference | 57 | 58 | +1 |
|
||
| Integration specs | 6 | 7 | +1 |
|
||
| CI integration step | (нет) | Sprint 27/28 step | new |
|
||
| PruneQualityTestOrgs unit test | (нет) | 2 [Fact]'a | new |
|
||
| Observability metrics doc | 6 кастомных | 11 кастомных (+ disk + 5 watchdog) | +5 |
|
||
|
||
## Артефакты этой ночи
|
||
|
||
- `scripts/gen-api-reference.py` — Python-генератор (соответствует
|
||
обновлённому `ApiReferenceDocsJob.cs`)
|
||
- `docs/api-reference.md` — пересгенерирован, 240 endpoints
|
||
- `docs/observability.md` — дополнен
|
||
- `tests/integration/07-import-export-flows.spec.ts` — новый spec
|
||
- `tests/food-market.IntegrationTests/PruneQualityTestOrgsTests.cs` — новый C# test
|
||
- `.forgejo/workflows/regression.yml` — added integration step
|
||
- `/tmp/soak-real/k6.log`, `/tmp/soak-real/metrics.csv` — soak в процессе
|