Эпик 9 ревью: ownership :own-KU склада + admin/board access #10

Closed
ant wants to merge 1 commits from chore/review-E9-sklad-fixes into marketplace2
Owner

Эпик 9 ревью «Склад и отчётность» — фиксы CRITICAL

CRITICAL fix

  • marketplaceListInventory resolver: был @RequireMarketplaceAccess('Warehouse', 'read:own-KU') — этот action есть только у operator. admin/board_readonly с read:all отбивались guard'омAdminWarehouseSummaryPage фронт сломан (admin не мог загрузить сводный склад).
  • Заменён на @RequireMarketplaceRole('admin', 'board_readonly', 'operator') + runtime ownership-проверка:
    • admin/board → весь склад без фильтра;
    • operator → enforce data.braname === member.username (MVP-приближение к chairman lookup);
    • прочие роли → ForbiddenException.

Story coverage

  • Story 9.1 — операторский мини-склад (теперь ownership-safe).
  • Story 9.2 — сводный склад админа (admin теперь проходит guard).
  • Story 9.3 — process-hash-locator уже содержит p.mkt.supply / p.mkt.return / p.mkt.wroff (lines 124-126), интегрити-чек активен. Реализовано, без правок.

Known limitations (Phase 2)

  • AdminWarehouseSummaryPage делает full-list load + 4 client-side aggregations через computed. На прод-объёме (10k+ inventories) UI повиснет — нужны server-side агрегации + пагинация.
  • marketplaceListInventory без пагинации (нарушение CLAUDE.md «Пагинация — стандартный паттерн»).
  • enum MarketplaceInventoryStatus = {LABELED, ISSUED, RETURNED, WRITTEN_OFF}. AC Story 9.1 требует 5 — добавить EXCESS_RETURNED_TO_WAREHOUSE для излишков из Story 6.4.
  • ownership operator → membership chairman lookup через coop_ku.chairman_account вместо MVP fallback username == braname.
  • Story 9.4 (federation registry) и 9.5 (history по process_hash) — не реализованы (UI/backend отсутствуют).
  • Story 9.6 (bookkeeping API годовой формы) — техдолг core, не marketplace MVP.

Test plan

  • admin/board_readonly загружают AdminWarehouseSummaryPage — данные приходят.
  • operator загружает OperatorOwnWarehousePage без braname → подставляется свой username.
  • operator пытается загрузить чужой braname → 403 Forbidden.
  • orderer пытается загрузить inventory → 403 Forbidden.

🤖 Generated with Claude Code

# Эпик 9 ревью «Склад и отчётность» — фиксы CRITICAL ## CRITICAL fix - `marketplaceListInventory` resolver: был `@RequireMarketplaceAccess('Warehouse', 'read:own-KU')` — этот action есть только у operator. **admin/board_readonly с `read:all` отбивались guard'ом** → `AdminWarehouseSummaryPage` фронт сломан (admin не мог загрузить сводный склад). - Заменён на `@RequireMarketplaceRole('admin', 'board_readonly', 'operator')` + runtime ownership-проверка: - admin/board → весь склад без фильтра; - operator → enforce `data.braname === member.username` (MVP-приближение к chairman lookup); - прочие роли → ForbiddenException. ## Story coverage - **Story 9.1** — операторский мини-склад (теперь ownership-safe). - **Story 9.2** — сводный склад админа (admin теперь проходит guard). - **Story 9.3** — process-hash-locator уже содержит `p.mkt.supply` / `p.mkt.return` / `p.mkt.wroff` (lines 124-126), интегрити-чек активен. **Реализовано, без правок.** ## Known limitations (Phase 2) - AdminWarehouseSummaryPage делает full-list load + 4 client-side aggregations через computed. На прод-объёме (10k+ inventories) UI повиснет — нужны server-side агрегации + пагинация. - `marketplaceListInventory` без пагинации (нарушение CLAUDE.md «Пагинация — стандартный паттерн»). - enum MarketplaceInventoryStatus = {LABELED, ISSUED, RETURNED, WRITTEN_OFF}. AC Story 9.1 требует 5 — добавить `EXCESS_RETURNED_TO_WAREHOUSE` для излишков из Story 6.4. - ownership operator → membership chairman lookup через `coop_ku.chairman_account` вместо MVP fallback `username == braname`. - Story 9.4 (federation registry) и 9.5 (history по process_hash) — не реализованы (UI/backend отсутствуют). - Story 9.6 (bookkeeping API годовой формы) — техдолг core, не marketplace MVP. ## Test plan - [ ] admin/board_readonly загружают `AdminWarehouseSummaryPage` — данные приходят. - [ ] operator загружает `OperatorOwnWarehousePage` без braname → подставляется свой username. - [ ] operator пытается загрузить чужой braname → 403 Forbidden. - [ ] orderer пытается загрузить inventory → 403 Forbidden. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
ant added 1 commit 2026-05-20 15:56:12 +00:00
CRITICAL:
- resolver: marketplaceListInventory был guarded только `read:own-KU`,
  что отбивало admin/board_readonly (их matrix capability — `read:all`).
  Frontend AdminWarehouseSummaryPage был сломан — admin не мог
  получить инвентарь. Заменён на @RequireMarketplaceRole admin/
  board_readonly/operator с runtime ownership-проверкой:
  - admin/board → весь склад без braname-фильтра;
  - operator → enforce `data.braname === member.username` либо подстановка
    своего braname при отсутствии (MVP-приближение к chairman lookup,
    полная интеграция coop_ku.chairman_account — Phase 2);
  - прочие роли → ForbiddenException.

Story coverage:
- Story 9.1 — операторский мини-склад (теперь ownership-safe).
- Story 9.2 — сводный склад админа (admin теперь проходит guard).
- Story 9.3 — process-hash-locator уже содержит p.mkt.supply/return/wroff
  (lines 124-126 process-hash-locator.ts), интегрити-чек активен.

Known limitations (Phase 2):
- AdminWarehouseSummaryPage делает full-list load + 4 client-side
  aggregations через computed. На прод-объёме (10k+ inventories)
  UI повиснет. Нужны server-side агрегации + пагинация.
- marketplaceListInventory без пагинации (нарушение CLAUDE.md
  «Пагинация — стандартный паттерн»).
- enum MarketplaceInventoryStatus = {LABELED, ISSUED, RETURNED,
  WRITTEN_OFF}. AC Story 9.1 требует 5: добавить
  EXCESS_RETURNED_TO_WAREHOUSE для излишков из Эпика 6.4.
- ownership operator → membership chairman lookup через
  coop_ku.chairman_account вместо MVP fallback `username == braname`.
- Story 9.4 (federation registry) и 9.5 (history по process_hash) —
  не реализованы (UI и backend отсутствуют).
- Story 9.6 (bookkeeping API годовой формы) — техдолг core, не
  marketplace MVP.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Owner

Закрываю как устаревший.

В marketplace2 уже мерженный коммит 46f5269b89794371df416f842283cd8d070ba495 ([review][@ant] fix(marketplace): ownership :own-KU учитывает trustees председателя КУ) делает тот же role-fork admin/board_readonly/operator для marketplaceListInventory, но:

  1. Ownership operator'а — через MarketplaceBranchOwnershipService.assertCanActAsBraname(...) с учётом branch.trusted[], не упрощённое member.username === braname.
  2. Семантически строже: оператор обязан явно передать braname (throw ForbiddenException('Оператор обязан указать кооперативный участок для чтения склада.')), без implicit fallback branameFilter = member.username, как в этом PR.

Resolve конфликта в пользу feature-ветки деградирует ownership и меняет семантику (вернёт implicit fallback). Resolve в пользу base — no-op merge. Закрываю без merge, ветку chore/review-E9-sklad-fixes удаляю.

Если в семантике implicit-fallback есть умысел (UX-причина) — обсудим отдельно, починим в новом PR.

Закрываю как устаревший. В `marketplace2` уже мерженный коммит `46f5269b89794371df416f842283cd8d070ba495` ([review][@ant] fix(marketplace): ownership :own-KU учитывает trustees председателя КУ) делает тот же role-fork admin/board_readonly/operator для `marketplaceListInventory`, но: 1. Ownership operator'а — через `MarketplaceBranchOwnershipService.assertCanActAsBraname(...)` с учётом `branch.trusted[]`, не упрощённое `member.username === braname`. 2. Семантически строже: оператор **обязан** явно передать `braname` (`throw ForbiddenException('Оператор обязан указать кооперативный участок для чтения склада.')`), без implicit fallback `branameFilter = member.username`, как в этом PR. Resolve конфликта в пользу feature-ветки деградирует ownership и меняет семантику (вернёт implicit fallback). Resolve в пользу base — no-op merge. Закрываю без merge, ветку `chore/review-E9-sklad-fixes` удаляю. Если в семантике implicit-fallback есть умысел (UX-причина) — обсудим отдельно, починим в новом PR.
claude closed this pull request 2026-05-22 08:16:59 +00:00

Pull request closed

Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: C9S/mono#10