Инцидент #1791428701 (quality-watchdog): кассир получал 403 на /api/money/accounts
на странице смен. Фикс — узкий /api/money/shifts/accounts (см. 9dc033d). Retest на
стенде: menu-walk 3/3 роли зелёные.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4.4 KiB
Инцидент quality-watchdog #1791428701 — menu-walk, demo-cashier 403
- Время: 2026-10-08T08:05:01+05:00
- Шаг watchdog:
menu_walk—stage-ui-menu-walk.spec.ts› demo-cashier. - Подряд падений: 2.
- Стенд: https://test.admin.food-market.kz
Симптом
E2E «каждый пункт меню для каждой демо-роли без 4xx/5xx/toast.error/console.error» падал на роли demo-cashier:
NET: 403 GET https://test.admin.food-market.kz/api/money/accounts?pageSize=100&isActive=true
(4 раза — заход на пункт меню + reload). Воспроизведено локально:
npx playwright test scenarios/stage-ui-menu-walk.spec.ts -g "demo-cashier".
Sidebar кассира: / /dashboard /catalog/products /inventory/stock /sales/retail /money/shifts /help /whats-new. Падало на /money/shifts.
Root cause
Страница смен CashShiftsPage (/money/shifts) для выбора кассы/эквайринга при
открытии смены дёргала GET /api/money/accounts (хук useMoneyAccounts(true)).
Этот эндпоинт — под правом MoneyView. Но у роли «Кассир»
(DevDataSeeder.SeedEmployeeRolesAsync) по требованию владельца
MoneyView = false («кассир не видит денег»), есть только
CashShiftOperate = true. Итог: кассир может открыть смену, но страница падала
403 при загрузке списка счетов.
Эндпоинты самих смен (/api/money/shifts List/Get/Report/open/close/drawer) уже
принимали право по ИЛИ-семантике MoneyView OR CashShiftOperate, а список счетов —
нет. Это несоответствие и было дырой (пред-существующий баг модуля «Деньги»,
проявился на стенде). Не связано с другими правками спринта.
Исправление
- Новый узкий эндпоинт
GET /api/money/shifts/accounts(RequiresPermission("MoneyView,CashShiftOperate")): возвращает только активные наличные кассы + эквайринг, минимальные поля (id, name, kind, storeId, currency) — без остатков и банковских счетов. Кассиру хватает для выбора кассы при открытии смены, но модуль «Деньги» (остатки/платежи/чужие счета) по-прежнему недоступен — инвариант «кассир не видит денег» сохранён. - Веб:
CashShiftsPageиспользует новый хукuseShiftAccounts()вместоuseMoneyAccounts(true). Админ-страница счетов (/api/money/accounts) не тронута.
Файлы: CashShiftsController.cs (+эндпоинт), web/src/lib/money.ts (+useShiftAccounts),
web/src/pages/money/CashShiftsPage.tsx.
Тесты
tests/food-market.IntegrationTests/PermissionTests.cs (Testcontainers):
Cashier_can_list_shift_accounts_but_not_money_accounts— кассир (CashShiftOperate, без MoneyView):GET /api/money/shifts/accounts→ 200 (только kind 1/4, без банка);GET /api/money/accounts→ 403 (инвариант).Me_permissions_for_cashier_role— /api/me permissions кассира (ProductsView есть, advanced-only скрыт в простом режиме). Результат: PermissionTests 4/4 зелёные.
Деплой и retest
~/deploy-stage.sh— OK: guard isolation OK, api+web собраны/запушены, stage-api Healthy, https://test.admin.food-market.kz OK.- Ручной retest menu-walk demo-cashier на стенде — 1 passed (40.8s), 0 ошибок (ранее 403 на /api/money/accounts). Прогон всех трёх ролей (admin/ keeper/cashier) — зелёный (admin/keeper не задеты: их страница смен теперь тоже через /shifts/accounts, у них есть MoneyView по ИЛИ).
Коммит
9dc033d fix(money): кассир открывает смену без доступа к модулю «Деньги» (403).