From 879e6b8ceef70e92f54b9c7e74273c172b48fed2 Mon Sep 17 00:00:00 2001 From: nns Date: Thu, 28 May 2026 11:40:01 +0500 Subject: [PATCH] =?UTF-8?q?docs(sprint3):=20P1-19=20done=20=E2=80=94=20?= =?UTF-8?q?=D0=B2=D1=81=D0=B5=205=20=D0=BF=D1=83=D0=BD=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=B2=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5=D0=BD=D1=8B?= =?UTF-8?q?,=20=D0=B8=D1=82=D0=BE=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.7 --- docs/sprint3-progress.md | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/docs/sprint3-progress.md b/docs/sprint3-progress.md index 86a843c..3b24c97 100644 --- a/docs/sprint3-progress.md +++ b/docs/sprint3-progress.md @@ -38,10 +38,45 @@ Multi-tenant: все запросы фильтруются по `OrganizationId` `cumulativeShare ≤ 80`, B — `≤ 95`, C — остальное. Товары с неположительной метрикой исключаются. Web: цветные плашки класса + полоса накопительной доли. 4 интеграционных теста. -5. [ ] **P1-19 OpenAPI / Swagger** — `Swashbuckle.AspNetCore`, +5. [x] **P1-19 OpenAPI / Swagger** — `Swashbuckle.AspNetCore`, `/swagger/v1/swagger.json` в Development. Сгенерировать TS-клиент для food-market.web (`openapi-typescript`/`nswag`) и подключить для пары контроллеров как образец. + ✅ SwaggerGen с Bearer security-scheme + стабильные operationId + (Controller_VerbAction — verb включён против коллизии WipeAll/WipeAllAsync) + + уникальные schemaId с namespace-префиксом. UI только в Development. + `openapi-typescript` как devDependency + npm-script `gen:api`. + `src/lib/api.generated.ts` + `apiClient.ts` (тонкая обёртка) — образец + на Reports/Sales/ABC/Profit. `docs/openapi.md` — workflow генерации. + +## Итог + +**Все 5 пунктов выполнены.** Спринт 3 (отчёты и аналитика) завершён 2026-05-28. + +Сводка: +- **P1-8 Sales** — `/api/reports/sales` 7 группировок + CSV/XLSX, 5 интеграционных. +- **P1-9 Stock** — реконструкция через журнал движений, 5 интеграционных (вкл. edges). +- **P1-10 Profit** — netto с защитой от деления на ноль, 3 интеграционных. +- **P1-11 ABC** — Парето 80/15/5 + 3 метрики + цветная UI-визуализация, 4 интеграционных. +- **P1-19 OpenAPI** — Swagger + TS-клиент через openapi-typescript, + обёртка `apiClient.ts` для подсказки IDE. + +**Сборка:** зелёная. **Тесты:** 24 unit + 49 integration (32 sprint1+2 + 17 sprint3) **зелёные**. +**Web:** `pnpm build` зелёный (4 новых report-страницы + boilerplate api.generated.ts). + +### Архитектурное замечание +Все отчётные контроллеры идут паттерном «плоский pull + group в C#» — EF8 не +переводит `g.Select(...).Distinct().Count()` в SQL для group-проекций с +nullable join-ключами (cashier, retail-point). Объёмы отчётов (~десятки +тыс. строк/месяц) держатся в RAM спокойно; на крупных тенантах перейдём +на raw SQL/views (вне scope этого спринта). + +### Bonus +Поймал и исправил баг `RetailSalesController.Update`: DbUpdateConcurrency +`expected 1 row, affected 0` воспроизводился на возвратах сразу после +`create-return`. Лечение — `ApplyLines` добавляет строки напрямую в DbSet +(а не через nav-collection), Update не делает `Include(Lines)`, старые +строки удаляются `ExecuteDelete`. ## Лог