Some checks failed
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
Docker Public / Build + push Public (push) Has been cancelled
Docker Public / Deploy Public on stage (push) Has been cancelled
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
78 lines
5 KiB
Markdown
78 lines
5 KiB
Markdown
# Спринт 6 — технический долг + 2FA
|
||
|
||
Автономная работа. После каждого пункта: `dotnet build` (SDK 8.0.126),
|
||
unit + integration тесты, коммит порцией, отметка `[x]`, коммит прогресса.
|
||
|
||
Не ломать auth. НЕ трогать global.json/POS/nginx/ОФД.
|
||
|
||
## Чек-лист
|
||
|
||
1. [x] **TD-6 Concurrency-токены на документах** — `RowVersion` (PostgreSQL
|
||
`xmin` через `IsRowVersion`) на Supply/Demand/RetailSale/Transfer/Inventory.
|
||
Миграция. EF concurrency check. 409 при конфликте. Тест: два параллельных
|
||
PUT → один 200, другой 409.
|
||
✅ Postgres `xmin` (system column, без миграции) через
|
||
`UseXminAsConcurrencyToken` для 5 документов + `IVersionedEntity`-marker.
|
||
SuppliesController PUT принимает `Xmin`, сверяет, 409 при mismatch.
|
||
Bonus: Supply.Update перешёл на ExecuteDelete+AddRange (тот же fix что
|
||
в RetailSale). 2 интеграционных теста.
|
||
2. [x] **TD-2 FluentValidation** — `FluentValidation.AspNetCore`, validator'ы
|
||
для SupplyInputDto/RetailSaleInputDto/ProductInputDto/CounterpartyInputDto/
|
||
EmployeeInputDto. Auto-register. Тесты на каждый.
|
||
✅ Не используем deprecated `FluentValidation.AspNetCore` — текущая
|
||
рекомендация: `AddValidatorsFromAssemblyContaining<Program>()` + кастомный
|
||
`ValidationFilter` (IAsyncActionFilter). На неуспех → 400 ValidationProblemDetails.
|
||
5 validator'ов, 16 unit-тестов, 70 integration зелёных без регрессий.
|
||
3. [x] **TD-4 Структурные log-fields в Serilog** — `LogContext.PushProperty`
|
||
в middleware: OrgId, UserId, CorrelationId. Бизнес-логи (Supply.Post,
|
||
Sale.Post) — структурно. `docs/logging.md`.
|
||
✅ `LogEnrichmentMiddleware` после Authentication. CorrelationId из заголовка
|
||
`X-Correlation-ID` или генерируется. Business-логи на Supply.Post /
|
||
RetailSale.Post с именованными плейсхолдерами. `docs/logging.md`
|
||
с паттерном + анти-паттернами (string interpolation, PII в логах).
|
||
4. [x] **TD-1 CQRS partial (MediatR)** — `CreateSupplyCommand`,
|
||
`PostRetailSaleCommand`, `GetSalesReportQuery`. Показать паттерн, не
|
||
полный рефакторинг. Тесты на handlers.
|
||
✅ MediatR подключён в `food-market.api` с авторегистрацией из
|
||
`food-market.application`. 3 handler-образца с абстракциями
|
||
(`ISupplyWriter`, `IRetailSalePoster`) — testable без EF/БД.
|
||
Контроллеры остались на прежнем flow (поэтапная миграция). 6 unit-тестов.
|
||
5. [x] **P2-4 2FA для админов (TOTP)** — `AuthenticatorTokenProvider`,
|
||
endpoints `/api/me/2fa/enroll`, `/api/me/2fa/verify`, `/api/me/2fa/disable`.
|
||
Опционально для Admin+SuperAdmin. При логине с включённым 2FA — два шага.
|
||
✅ Identity `AuthenticatorTokenProvider` (RFC 6238). Endpoints:
|
||
/api/me/2fa/{status, enroll, verify, disable} с QR-URI. Password-grant
|
||
на `/connect/token` принимает custom param `otp_code`; при включённом
|
||
2FA без него — `invalid_grant` с `error_description=2fa_required`.
|
||
4 интеграционных теста (тест сам генерит TOTP через RFC 6238).
|
||
|
||
## Итог
|
||
|
||
**Все 5 пунктов выполнены.** Спринт 6 завершён 2026-05-28.
|
||
|
||
Сводка:
|
||
- **TD-6 RowVersion** — Postgres `xmin` через `UseXminAsConcurrencyToken`
|
||
на 5 документах, 409 при conflict. Bonus: исправил Supply.Update.
|
||
- **TD-2 FluentValidation** — `ValidationFilter` + 5 validator'ов
|
||
(Supply, RetailSale, Product, Counterparty, Employee).
|
||
- **TD-4 Structured logging** — `LogEnrichmentMiddleware` (OrgId/UserId/
|
||
CorrelationId в LogContext), business-логи на Post-операциях.
|
||
- **TD-1 CQRS partial** — MediatR + 3 handler-образца с testable-абстракциями.
|
||
- **P2-4 TOTP 2FA** — endpoints + интеграция в password-grant.
|
||
|
||
**Сборка:** зелёная.
|
||
**Тесты:** 57 unit + 74 integration = **131 зелёных**.
|
||
|
||
### Что осталось вне scope автономной работы
|
||
- ОФД-оператор (`Транском`/`Касса24`),
|
||
- MoySklad webhook-токены прод,
|
||
- WPF/POS UI на Windows,
|
||
- Стейдж→прод-деплой,
|
||
- Реальный SMTP-провайдер прод (Mailgun/Sendgrid),
|
||
- Backup-коды для 2FA recovery (отдельная задача).
|
||
|
||
## Лог
|
||
|
||
- Каждый пункт: build + тесты + коммит порцией + отметка [x] + коммит прогресса.
|
||
- Все правки на `main` (origin Forgejo), без коммита `global.json`.
|