food-market/docs/sprint1-progress.md
nns 744847661d docs(sprint1): P0-1 done
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 02:47:12 +05:00

52 lines
4.3 KiB
Markdown

# Спринт 1 — стабилизация (P0 код/инфра)
Автономная работа. После каждого пункта: `dotnet build` (SDK 8.0.126), релевантные тесты,
коммит порцией, отметка `[x]` здесь, коммит прогресса.
> Сборка: POS-проект (`food-market.pos`, net8.0-windows) на Linux не собирается — это
> ожидаемо (нужен Windows SDK). Эталон сборки — `dotnet build src/food-market.api/food-market.api.csproj`
> + solution-сборка тестовых проектов.
## Чек-лист
1. [x] **P0-3 Rate-limit**`Microsoft.AspNetCore.RateLimiting` (sliding window) на
`/connect/token` и `/api/auth/signup`. 5/мин/IP, 20/час/IP. Тест: 6-я попытка за минуту → 429.
`AuthRateLimiterExtensions` (global limiter + chained окна, gate по пути), отдельные
бакеты на эндпоинт. Проверено curl на :5091 — token 6→429, signup 6→429, бакеты независимы.
2. [x] **P0-4 Health checks**`/health/live` (alive) + `/health/ready` (DB ping + миграции
применены). docker-compose healthcheck → `/health/ready`.
`DatabaseReadyHealthCheck` (CanConnect + GetPendingMigrations), JSON-writer, tag `ready`.
Проверено: live→200 (checks:[]), ready→200 (database Healthy). Dockerfile + compose api
healthcheck на `/health/ready`, web ждёт api `service_healthy`. `/health` оставлен для
совместимости. Прим.: startup `Migrate()` — fail-fast при DB-down на буте (вне scope, compose
гейтит api на `postgres: service_healthy`).
3. [x] **P0-5 Permission-based authz**`PermissionHandler` + `[RequiresPermission("...")]`
читающий флаги `RolePermissions`. Заменить `[Authorize(Roles=...)]` в каталоге/документах.
E2E: кастомная роль без `ProductsEdit` → 403 на PUT товара.
`PermissionAuthorizationHandler` (live из БД: Employee→EmployeeRole→Permissions) +
`RequiresPermissionAttribute` + динамический `PermissionAuthorizationPolicyProvider`
(policy `perm:*`). SuperAdmin/Identity-Admin — full-access шорткат (custom-роли не маппятся
на Admin). Заменены role-гейты в 8 catalog + 2 document контроллерах (Currencies/Countries
оставлены SuperAdmin — глобальный справочник). Закрывает «роли — фикция» из аудита.
Проверка: curl на :5091 (403/200/400) + e2e `roles` step08 — зелёный 8/8.
Rate-limit стал конфигурируемым (`RateLimiting:*`) — иначе повторные логины тестов → 429.
4. [x] **P0-1 OpenIddict prod-ключи** — signing+encryption сертификаты из пути в конфиге,
persistent self-signed если файла нет. Dev-поведение не ломать. Документировать.
`OpenIddictKeyConfigurator`: dev RSA-XML (без изменений), prod X509 из
`OpenIddict:SigningCertPath`/`EncryptionCertPath`/`CertPassword`, self-signed (5 лет) в
App_Data при отсутствии. Проверено: prod 5-сегм. JWE, persist через рестарт (тот же
fingerprint, pre-restart токен валиден); dev 3-сегм. JWT. `docs/openiddict-keys.md`.
5. [ ] **P0-6 Авто-бэкап**`deploy/food-market-backup.service` + `.timer`, скрипт
backup+ротация 30 дней, `docs/backup-restore.md`. Только артефакты в репо.
6. [ ] **P0-8**`deploy/.env.example` + `docs/secrets.md`.
7. [ ] **P0-9**`docs/release-checklist.md`.
8. [ ] **P1-20 Unit-тесты**`tests/food-market.UnitTests`: `StockService.ApplyMovement`,
расчёт Cost в `SuppliesController.Post`, валидация платежа `RetailSalesController.Post`,
multi-tenant query filter.
9. [ ] **P1-21 Integration-тесты** — Testcontainers.PostgreSql + WebApplicationFactory:
signup-flow, supply post→unpost, retail overselling, tenant isolation A vs B, permission-проверки.
## Лог
(заполняется по ходу)