Item Catalog — Backend Feedback¶
Endpoint gaps and shape mismatches found while planning the FE for this module. This document is intended for the BE team. Each row is a concrete blocker or quality issue the FE encountered against the published OpenAPI spec.
OpenAPI source used: ./openapi/openapi.json (mirror of ../grinsystem-api/docs/api/openapi.json, item-catalog slice carved out by tag filter in orval.config.ts).
Status¶
resolved — closed 2026-05-25 via GRF-31. All four flagged items shipped on BE and were synced into the FE Orval client. linear-issue-creator-fe is unblocked for this module.
Gaps¶
| ID | Use case | Required operation | Category | Detail | FE impact | Suggested resolution |
|---|---|---|---|---|---|---|
| BF-01 | IC-UC-04 (search/browse catalog) | GET /api/v1/items/stats |
endpoint missing | No tenant-wide stats endpoint for items. ItemListPage chosen variant A renders a StatsBar showing total / active / archived counts plus per-item_type counts that are unfiltered (tenant-wide), so they cannot be derived from the paginated list response's total. Computing them client-side would require ~9 separate list calls per page render (one per filter combo at page_size=1), which is wasteful and breaks if BE caps concurrent requests. |
M1 list ticket has nothing to wire StatsBar against. |
Add GET /api/v1/items/stats returning { total, by_status: { active, inactive }, by_item_type: { ingredient, product, intermediate, packaging, consumable, service, resale } }. Filter-agnostic — stable tenant-wide counts per docs/standards.md § Stats endpoints. |
| BF-02 | IC-UC-05 (item groups) | GET /api/v1/item-groups/stats |
endpoint missing | Same shape gap as BF-01 but for item-groups. GroupListPage chosen variant A renders a StatsBar with total groups, empty groups, and per-item_type group counts. |
M3 group-list ticket has nothing to wire StatsBar against. |
Add GET /api/v1/item-groups/stats returning { total, empty, by_item_type: { … } }. Filter-agnostic. |
| BF-03 | IC-UC-01 (create item) / IC-UC-02 (edit item) / IC-UC-04 (search/browse catalog) | GET /api/v1/item-groups/options[?item_type=…] |
endpoint missing | The group <Combobox> on ItemCreateForm, ItemEditForm, and the ItemListPage FilterBar's group filter all need a lightweight picker fetch — a flat [{ id, label }] array, optionally scoped by item_type (BR-IC-05). The paginated GET /api/v1/item-groups is the wrong shape: it returns bloated Group objects with version / audit fields, forces a pagination decision (fetch-all-pages or page_size=1000?), and shares its cache key with GroupListPage, causing invalidation collisions. This pattern recurs across every future module with a "pick one from a list" field (suppliers, warehouses, BOM templates, …). |
M2 item-create / item-edit pickers + M1 list FilterBar group filter cannot be wired against the right shape. | (1) Add a new convention § "List Resource Options Endpoints" to ../../grinsystem-api/docs/architecture/conventions.md, mirroring § Stats endpoints (FE side: docs/standards.md § Options endpoints). (2) Ship GET /api/v1/item-groups/options?item_type=<…> as the first compliance application — bare Array<{ id, label }>, sorted alphabetically, no pagination, no q. Tracked on BE as GRI-103. |
Conventions issues¶
| ID | Endpoint | Issue |
|---|---|---|
| BC-01 | GET /api/v1/items/{item_id} and PATCH /api/v1/items/{item_id} |
Neither ItemDetailResponse nor EditItemResponse includes the version field. ItemGroup follows the convention (EditItemGroupResponse has version: int). Without version on Item, the FE cannot honour the optimistic-locking contract in docs/standards.md § Optimistic Concurrency — concurrent edits will silently last-write-win and the documented 409 CONCURRENT_MODIFICATION refresh-and-retry UX has no signal to react to. |
FE workarounds (none)¶
| Gap ID | Workaround | Why acceptable |
|---|---|---|
| — | — | — |
No FE workarounds chosen. The user opted to plan tickets as if all four items would be resolved (stats endpoints shipped, options endpoint shipped + convention documented, item version added) and BE landed the fixes incrementally. All four shipped in time for GRF-31's sync — shipped shapes matched FE plan assumptions exactly, no rewrites needed beyond dropping the (pending …) annotations.
Resolution log¶
- [x] BF-01 —
GET /api/v1/items/statsshipped by grinsystem-api#39 (GRI-92); reflected inopenapi/openapi.jsonand synced to the FE Orval client in GRF-31. - [x] BF-02 —
GET /api/v1/item-groups/statsshipped by grinsystem-api#38 (GRI-93); reflected inopenapi/openapi.jsonand synced in GRF-31. - [x] BF-03 —
GET /api/v1/item-groups/optionsshipped (+ "List Resource Options Endpoints" convention added to BEconventions.md) by grinsystem-api#40 (GRI-103); reflected inopenapi/openapi.jsonand synced in GRF-31. - [x] BC-01 —
version: intadded toItemDetailResponseandEditItemResponse(and theItemGroupdetail mirror) by grinsystem-api#36 (GRI-94); reflected inopenapi/openapi.jsonand synced in GRF-31.
Non-gaps (deliberately recorded, do not action)¶
These came up during planning but are not gaps — they're recorded here so future planners don't re-flag them:
PATCH /api/v1/items/{id}does not acceptgroup_id— intentional. The group is a REST sub-resource (PUT|DELETE /items/{id}/group) with its own permission (ITEM_GROUP_ASSIGN) and its own audit semantics (a no-op reassignment still bumps the audit row, while a no-op field PATCH does not). The FE handles this via the composite-edit pattern documented in../../standards.md§ Composite Edits (aggregates with sub-resource endpoints). No BE change requested.