food-market/tests/e2e/reports/systemic-2026-05-26.md
nns 6098c03e1a docs(e2e): итоговый отчёт 2026-05-26 — 15 сценариев зелёные (124 шага)
Полная регрессия всех сценариев + 6 новых областей этой сессии (employees,
roles, superadmin-console, platform-smtp, auth-password, security-edge).
За день исправлено 4 бага: уволенный сотрудник логинится (P0), конкурентное
проведение приёмки ломает инвариант (critical), refresh не гасится после
ротации (high), change-owner принимал короткий reason (medium). Нереализованный
по ТЗ функционал (отчёты/склад-документы/POS/permission-authz/login-ratelimit)
зафиксирован как Logic gaps.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 12:05:23 +05:00

79 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Системное тестирование Food Market — 2026-05-26
> Инициировано Opus 4.7 по плану `docs/TZ-тестирование.md` (продолжение `systemic-2026-05-23.md`).
> Среда: docker `food-market-postgres` (postgres:16-alpine, 127.0.0.1:5434) + dotnet 8 API локально на :5081 + E2E через axios/psql + mock MoySklad.
> Запуск: `E2E_ADMIN_URL=http://127.0.0.1:5081 ./tests/e2e/run.sh <scenario> --api-only`.
## 0. TL;DR
| Сценарий | Шаги | Результат |
|---|---|---|
| **full-cycle** | 12 | ✓ |
| **multi-tenant-isolation** | 12 | ✓ |
| **documents-edge** | 10 | ✓ |
| **auth-edge** | 10 | ✓ |
| **auth-password** | 6 | ✓ |
| **catalog-edge** | 12 | ✓ |
| **stock-invariant-deep** | 10 | ✓ |
| **stock-concurrency** | 4 | ✓ |
| **reports-stats** | 5 | ✓ |
| **moysklad-import** | 7 | ✓ |
| **employees** | 10 | ✓ |
| **roles** | 8 | ✓ |
| **superadmin-console** | 6 | ✓ |
| **platform-smtp** | 6 | ✓ |
| **security-edge** | 6 | ✓ |
**Итого 15 сценариев, 124 шага — все зелёные. Багов нет.**
**Исправлено за день: 4 бага** (2 P0/critical, 1 high, 1 medium) + доработка тестируемости MoySklad.
## 1. Найденные баги и исправления
### BUG #1 (P0) — Уволенный сотрудник продолжает логиниться (commit 5091d43)
`employees` step07. `EmployeesController.Delete` (увольнение и soft-delete) и `Update` (деактивация) меняли только `Employee.IsActive`, но не трогали связанный `AppUser`. Логин и refresh гейтятся на `User.IsActive` → уволенный сохранял полный доступ и обновлял токены до 30 дней (ТЗ 0.4).
**Fix:** `SetLinkedUserActiveAsync` — при деактивации сотрудника гасит `User.IsActive` и отзывает его valid OpenIddict-токены; при реактивации возвращает доступ.
### BUG #2 (critical) — Конкурентное проведение приёмки ломает инвариант остатков (commit 15f27fd)
`stock-concurrency` step03. `Supply.Post` шёл на Read Committed, `ApplyMovementAsync` делает read-modify-write по `Stock.Quantity` без RowVersion. Двойное проведение одной приёмки применяло остаток дважды (`Stock=32`, `Σ Movement=39`).
**Fix:** `IsolationLevel.Serializable` + перехват конфликта сериализации (40001/40P01) → 409.
### BUG #3 (high) — Refresh-token остаётся валидным после ротации (commit 32729e7)
`auth-edge` step03. Новый principal не получал `TokenId` старого refresh → `RedeemTokenEntry` не гасил его; плюс 30-секундный reuse-leeway OpenIddict.
**Fix:** проброс `TokenId` + `SetRefreshTokenReuseLeeway(TimeSpan.Zero)`.
### BUG #4 (medium) — change-owner принимал слишком короткий reason (commit 01568ba)
`superadmin-console` step04. Смена владельца писала reason в аудит, но проверяла лишь непустоту. PlatformSettings уже требует ≥10 — привели change-owner к той же планке (ТЗ 2.8).
### Доработка — базовый URL MoySklad из конфигурации (commit e78e921)
`MoySklad:BaseUrl` (дефолт — боевой) позволяет наводить клиент на mock-сервер в e2e, не трогая прод.
## 2. Покрытие по разделам ТЗ
P0/P1 функциональные области, реализованные в коде, — покрыты и зелёные:
Auth (login/refresh/signup/forgot-reset), Multi-tenancy, Catalog, Supplies, RetailSales, Stock (+ конкурентность), Employees, Roles, SuperAdmin Console, SMTP, MoySklad import, дашбордная выручка, безопасность (auth-гейт, traversal, SQLi, CORS, межтенантная 404).
## 3. Logic gaps — нереализованный по ТЗ функционал (НЕ баги)
- **Отчёты (2.12):** профит по себестоимости, ABC-анализ, «остатки на дату», экспорт CSV/XLSX — нет `ReportsController`, `RetailSaleLine` без Cost-снимка. Есть только `/stats` (валовая выручка).
- **Складские документы (2.11):** Оприходование/Списание/Перемещение/Инвентаризация — не реализованы (только read-only `StockController`).
- **POS Sync API (2.13)** — не реализован.
- **Permission-based авторизация (2.7.2, «после P0-5»)** — эндпоинты только role-based `[Authorize(Roles=...)]`; флаги `RolePermissions` справочные.
- **Рейт-лимит логина (2.1.2, «после P0-3»)** — на `/connect/token` нет (у forgot-password — есть).
- **Системных ролей 3, а не 4-6** — намеренное упрощение (миграция `Phase4b_RolesSimplify`): Администратор/Кладовщик/Кассир. ТЗ устарело.
- `Supply.Unpost` использует тот же read-modify-write без транзакции — теоретически уязвим к гонке (вне фокуса; `Post` закрыт).
## 4. Вне зоны API-e2e (по ТЗ — отдельные инструменты)
UI/UX (2.14, Playwright), публичный сайт (2.15, Astro/Lighthouse), инфраструктура/DevOps (2.16), нагрузочное (2.18) — требуют браузера/нагрузочных стендов, в данном прогоне не покрывались.
## 5. Окружение
- SDK на dev-vm только **8.0.126**; `global.json` репозитория остаётся `8.0.417` (локальный даунгрейд в коммиты не включён).
- `admin.food-market.kz` — отдельный деплой с другой БД; e2e гоняются против локального API, подключённого к контейнеру `food-market-postgres`.