Allows super user and support operators to curate platform-wide accessory upsells that surface on the IndieBrewer storefront.
Data & Dependencies
Access is limited to sessions with super user or support membership; all operations call the privileged /shop/upsells Fastify routes (list/create/update/delete plus image helpers).
Image uploads stream to the shared image storage bucket (500 × 500 main asset + 100 × 100 icon) and reuse the platform processing rules (JPG/PNG/WebP up to 5 MB).
Pricing inputs are up-converted to minor currency units on save so the API receives integers that align with the price_minor schema column.
Stock tracking is manual: operators set currentStock on each upsell; the value returns via /public/upsells so the storefront can surface “Sold out” badges and disable add-to-basket actions when the count hits zero.
Key Interactions
Left rail lists available upsells, exposes status chips, a toggle to include inactive records, and a refresh button that re-fetches the catalogue.
"New upsell" starts a blank form; selecting an entry loads its current data into the detail pane for editing.
Detail form captures name, optional slug, long-form description, price, coupler type (matching the KegCouplerType enum), display order, current stock, and an active toggle—client-side validation mirrors server limits (name ≤160 chars, description ≤5000 chars, numeric ranges, slug pattern).
When currentStock is set to 0 the list view flags the entry as sold out and the form surfaces a warning banner so operators can quickly see which accessories are unavailable.
Image management section lets operators upload square artwork with an optional "set as default" flag, preview existing images, switch the default image, or delete assets (each destructive action surfaces a confirmation dialog).
Save button handles both create and update flows; success and error states surface via snackbars, while deleting an upsell shows a dedicated confirmation prompt before removal.