0009. Storefront category grouping uses the V1 model; publish projects sections into it¶
- Status: Accepted
- Date: 2026-06-12
- Deciders: POS Integration team
Context¶
The consumer storefront (store-service) groups a store's menu into categories.
It reads a V1 category model spread across three tenant tables:
item_categories— the category definitions.item_item_category— product ↔ category (read byGetProductByStoreIdinto each product'scategories, and the source ofitems_flat.categories).menu_item_category— per-menu(menu_id, item_id, item_category_id)grouping (read byGetMenuItemCategories).
The category catalog (GetStoreCatalog, /v1/store/category) is keyed by
category — an item with no category is dropped from it entirely.
pos-integration-service's Menu Manager V2 publish writes the menu structure as
menu_sections + menu_section_items. But store-service does not read those
tables at all — they are the not-yet-consumed "V2" structure. The result: a
freshly published menu had items but no category grouping, so the storefront
showed nothing (items without a category are dropped). Verified during the
"menu doesn't load on mobile" debugging.
Decision¶
Until store-service is taught to read the V2 section structure, the publish
flow projects each menu section into the V1 category tables so the storefront
can group and display items. A section maps 1:1 to an item_category by
name.
At the end of publishDraftInTx (in the publish transaction),
projectSectionCategories:
- get-or-creates an
item_categoriesrow per section name (provider-scoped:(name, provider), reusing the same get/revive/insert pattern as the product-sync category path); - carries the section's
display_typeontocategory_view_type, normalised to uppercase (list/grid→LIST/GRID); - writes a
menu_item_categoryrow per section item (the per-menu grouping the storefront reads) and upserts anitem_item_categoryrow (product-level, fillsitems_flat.categories); - on republish, soft-deletes
menu_item_categoryfor the replaced menus so stale groupings don't accumulate.
menu_item_category is added to the SQLC-only schema in this repo
(012-categories-and-items-flat.sql), mirroring store-service's definition;
the real migration lives in dashboard-app/store-service.
Consequences¶
Positive
- The storefront groups and shows published items by category — for all
adapters, not just those that happened to set a product
POSCategory. - Reuses the existing category upsert/revive logic and the publish transaction; no new service or cross-service call.
Negative / costs
- Categories are provider-scoped, so a name that already exists under another
provider (e.g. a
CATA"Coffee") gets a second, provider-specific row. This is accepted (the storefront groups by the row the menu links to); it is a known duplication, not a bug. - We now maintain two representations of menu structure (V2
menu_sectionsfor the editor, projected V1 categories for the storefront) until store-service reads sections directly. This projection is the bridge and should be retired once that happens.
Alternatives considered¶
- Teach
store-serviceto readmenu_sections/menu_section_items— the proper long-term "V2" path, but a larger cross-repo change; deferred. This ADR is the interim bridge. - Reuse categories by name across providers (not provider-scoped) — rejected:
inconsistent with how
item_categories.provideris used elsewhere; we kept provider scoping and accept the duplicate-name rows. - Populate only
menu_item_category— rejected:GetProductByStoreId/items_flat.categoriesreaditem_item_category, so both are needed for the product-level and menu-level reads.
References¶
- PRs #131 (project sections → V1 categories), #132 (section display type → category view type).
- Code:
internal/repository/mysql_menu_draft_repository.go(projectSectionCategories),database/queries/menus.sql(InsertMenuItemCategory,SoftDeleteMenuItemCategoryByDeletedMenus). - store-service reads:
database/queries/menu.sql(GetMenuItemCategories),database/queries/product.sql(GetProductByStoreId),service/MainService/Store.go(GetStoreCatalog,collectCategoriesAndProducts). - Diagnostic:
script/check-store-menu.sh(Query 4 renders the projected category → product hierarchy). - Related: ADR 0008 (the sibling
publish-time projection into
items_flat).