90 lines
7.6 KiB
Markdown
90 lines
7.6 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. [x] **P0-6 Авто-бэкап** — `deploy/food-market-backup.service` + `.timer`, скрипт
|
||
backup+ротация 30 дней, `docs/backup-restore.md`. Только артефакты в репо.
|
||
✅ `food-market-backup.sh` (pg_dump -Fc + tar uploads, ротация 30д, атомарная запись),
|
||
systemd timer ежедневно 03:00 (Persistent). Проверено: дамп PGDMP/248 TOC, pg_restore --list ок.
|
||
6. [x] **P0-8** — `deploy/.env.example` + `docs/secrets.md`.
|
||
✅ `.env.example` (все required+опц.), `secrets.md` (таблица/ротация/гигиена), проброс
|
||
`OpenIddict__Issuer`/`CertPassword` в compose. `compose config` валиден.
|
||
7. [x] **P0-9** — `docs/release-checklist.md`.
|
||
✅ Пред/во время/после выкатки + откат + прод; ссылки на secrets/backup/openiddict/stage-setup.
|
||
8. [x] **P1-20 Unit-тесты** — `tests/food-market.UnitTests`: `StockService.ApplyMovement`,
|
||
расчёт Cost в `SuppliesController.Post`, валидация платежа `RetailSalesController.Post`,
|
||
multi-tenant query filter.
|
||
✅ 23 теста зелёные. Чистая логика вынесена в Application (`MovingAverageCost`,
|
||
`RetailPaymentValidator`) и используется контроллерами. StockService + query-filter на
|
||
SQLite in-memory (EF8 поддерживает `ToJson`). `FakeTenantContext`, `SqliteDb` helper.
|
||
9. [x] **P1-21 Integration-тесты** — Testcontainers.PostgreSql + WebApplicationFactory:
|
||
signup-flow, supply post→unpost, retail overselling, tenant isolation A vs B, permission-проверки.
|
||
✅ `tests/food-market.IntegrationTests` — 10 тестов зелёные на реальном postgres:16-alpine
|
||
(Ryuk off, RateLimiting off через env). `ApiFactory`+`ApiActor`. Все 5 сценариев покрыты.
|
||
|
||
## Итог
|
||
|
||
**Все 9 пунктов выполнены.** Спринт 1 (стабилизация P0/P1-инфра) завершён 2026-05-27.
|
||
|
||
Сводка:
|
||
- **P0-3** rate-limit (5/мин+20/час на IP, конфигурируем) — `AuthRateLimiterExtensions`.
|
||
- **P0-4** health `/health/live` + `/health/ready` (БД+миграции), compose/Dockerfile healthcheck.
|
||
- **P0-5** permission-based authz (`[RequiresPermission]` + handler по флагам роли), 10 контроллеров.
|
||
- **P0-1** OpenIddict prod X509-ключи из конфига, persistent self-signed.
|
||
- **P0-6** авто-бэкап (systemd timer + скрипт + ротация 30д) + `backup-restore.md`.
|
||
- **P0-8** `deploy/.env.example` + `secrets.md`.
|
||
- **P0-9** `release-checklist.md`.
|
||
- **P1-20** unit-тесты (23) — `MovingAverageCost`, `RetailPaymentValidator`, StockService, query-filter.
|
||
- **P1-21** integration-тесты (10) — Testcontainers + WebApplicationFactory.
|
||
|
||
Сборка зелёная (`dotnet build src/food-market.api`); тесты: **23 unit + 10 integration = 33 зелёных**.
|
||
POS (net8.0-windows) на Linux не собирается — ожидаемо, вне scope.
|
||
|
||
Пропущено намеренно (по инструкции): P0-7 ОФД (нужен внешний оператор), gateway nginx HTTPS,
|
||
`global.json` (локальный даунгрейд не коммитим). Установка backup-таймера/сертификатов на
|
||
prod-vm — отдельный деплой-шаг (артефакты готовы).
|
||
|
||
### Эффект на код вне P0/P1
|
||
- Чистая логика вынесена в Application (`MovingAverageCost`, `RetailPaymentValidator`) — контроллеры используют её.
|
||
- `Program` стал `public partial` для WebApplicationFactory.
|
||
- e2e `roles` step08: gap → реальная проверка permission-enforcement (8/8 зелёный).
|
||
|
||
## Лог
|
||
|
||
- Каждый пункт: build + тесты + коммит порцией + отметка [x] + коммит прогресса.
|
||
- Все правки на ветке `main` (origin Forgejo), без коммита `global.json`.
|