The second half of the Edit Product rework. The tabs shipped separately; this adds the Menu Display section, turns Tracking into a dropdown, and brings Reference and Barcode onto the form — following the mockup.
"Menu badges — Choose up to 2 badges to highlight this product on the menu." A fixed set of three — Best Seller, New, Limited — set on the product, with a live preview of the customer menu card beside it.
The vocabulary is deliberately fixed rather than merchant-editable, and a badge marks the whole product rather than one variant — a menu card shows a product, not a variant. The preview reflects the current selection rather than the saved one, so the effect is visible before committing.


At the cap the third badge is genuinely disabled, not silently ignored, and it never quietly evicts one of your existing picks.
Tracking is now a dropdown — By Quantity, By Lot, By Serial Number. Lot and Serial are stored but display-only for now, since no lot or serial tracking exists yet; the merchant's intent survives until it does.
Quantity on Hand is deliberately read-only: it is a placeholder for the future inventory work, not an editable number and not wired to POS decrement. Reference and Barcode appear for single-variant products, following the same rule price and image already use — multi-variant products keep editing them per row, since they are per-variant values.

That reload matters more than it looks. This form has historically had fields that appeared to save but re-opened blank — after which the next save wiped them. Every new field is asserted to survive a round trip.
The badges don't reach the customer menu yet. They are stored on the product and previewed here; carrying them through to the loyalty app's menu is the next piece of work. Until then the preview is exactly what its caption says — how it may look.
| Suite | Result |
|---|---|
| Local — the cap, the preview, chip removal, save-to-database, reload hydration, Quantity not editable, Tracking options, multi-variant behaviour, and a deliberately malformed badge list | 11/11 |
| Staging — real sign-in on the deployed build, save, reload, plus a tab regression check | 6/6 |
| Staging smoke | 5/5 |
tsc --noEmit (nix-cafe) | clean |
The cap was verified by breaking it on purpose: raising the limit from two to three failed exactly the two checks that enforce it — one in the interface, one on the server — and restoring it returned the suite to green. A malformed badge list written straight into the database (an unknown badge, a duplicate, five entries) is cleaned up on read, so a bad row cannot put the screen into an impossible state. No product with multiple variants exists in any local tenant, so rather than let that branch quietly skip, the test creates the condition and restores it.
nix-cafe staging 0152671 (Worker fe79569d) · nix-OS-backend dev
1884d7a · localization main ab5edaa.
Migration 20260726130000 — additive, applied to staging. Joins the scheduled promote.