Skip to content

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/stats shipped by grinsystem-api#39 (GRI-92); reflected in openapi/openapi.json and synced to the FE Orval client in GRF-31.
  • [x] BF-02 — GET /api/v1/item-groups/stats shipped by grinsystem-api#38 (GRI-93); reflected in openapi/openapi.json and synced in GRF-31.
  • [x] BF-03 — GET /api/v1/item-groups/options shipped (+ "List Resource Options Endpoints" convention added to BE conventions.md) by grinsystem-api#40 (GRI-103); reflected in openapi/openapi.json and synced in GRF-31.
  • [x] BC-01 — version: int added to ItemDetailResponse and EditItemResponse (and the ItemGroup detail mirror) by grinsystem-api#36 (GRI-94); reflected in openapi/openapi.json and 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 accept group_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.