33 · QSR & pizzeria vertical pack
How independent pizzerias and quick-service restaurants run on the
same Business OS — POS, KDS, inventory, payments, and one shared storefront —
without a forked “pizza product.”
Markdown twin: docs/PLATFORM-VERTICAL-QSR.md.
businessMode (retail | restaurant).
Restaurant mode adds pickup/delivery, configurators, and kitchen/delivery handoff after pay.
1. Goal
| Pack provides | Not the pack |
|---|---|
| Order type / channel / promise / guest | Generic barcode-only retail POS |
| Pizza / BYO product configurator | Full franchise ERP |
| Station graph + expo whole-order ready | Third-party delivery fleet by itself |
| Delivery dispatch board | Separate pizza.com host |
| Shared storefront restaurant mode | Forked eatery-only storefront codebase |
2. Day-in-the-life flow
flowchart LR POS[Modern POS
fulfillment + builder + deals] SF[Storefront
restaurant mode] CART[Cart metadata
orderType · channel · guest] KDS[Kitchen tickets
orderId = cart id] EXPO[Expo board
all stations DONE] DEL[Delivery board
prep → ready → out] INV[Inventory burn
SKU or configurator] POS --> CART SF --> CART CART --> KDS CART --> INV KDS --> EXPO EXPO --> DEL CART -->|orderType delivery| DEL
3. Order fulfillment (POS cart metadata)
| Field | Values / purpose |
|---|---|
orderType | dine_in · carryout · delivery · drive_thru |
orderChannel | counter · phone · online · kiosk · third_party |
guestName / phone | Carryout & delivery contact |
addressLine* / city | Delivery address |
promiseMinutes | Quoted wait (KDS chip) |
deliveryFeeCents / notes | Dispatch ops |
UI: Modern POS → Order fulfillment bar.
API: PATCH /api/pos/carts/:id/metadata.
Codes: backend/utils/orderFulfillment.js.
4. Product configurator (pizza builder)
- Catalog item
metadata.configurator(sizes, crusts, sauces, toppings, half & half). - Admin:
/admin/catalog/configurator— attach builder + inventory Inv ID / SKU / burn qty. - POS / storefront:
ProductConfiguratorDialog→ line name, base +modifierCents,mods[]. - Mixed carts: configured pizza plus normal inventory SKUs in one cart is supported.
5. Kitchen · Expo · bake timers
| Piece | Behavior |
|---|---|
orderId | Cart id — multi-station tickets group for expo |
| Stations | Category routing; Apply pizzeria stations (pizza→make, drinks→bar) |
| Expo | GET /api/kds/expo — ready when all stations DONE; Bag handoff |
| Bake | Line bakeSeconds (default 12m pizza); countdown on KDS card |
| UI | /pos/kitchen — lanes + Expo tab (keyboard 5) |
See also 15 · Floor · KDS · Beacon.
6. Delivery dispatch
Status: quoted → prep → ready →
out → delivered (+ cancelled).
- UI:
/pos/delivery(alias/pos/dispatch) - Table:
delivery_orderson tenant main - Auto: send-to-kitchen on delivery cart → prep; Expo bag → ready
- QA: Admin Tools → Seed delivery board
| Method | Path |
|---|---|
| GET | /api/delivery/board |
| POST | /api/delivery/from-cart/:cartId |
| POST | /api/delivery/orders/:id/status |
| POST | /api/delivery/orders/:id/assign |
7. Deals / combos (pilot)
| Deal | Rule |
|---|---|
| 2 Large Pizzas | $3 off for 2+ large pizzas |
| Pizza + Drink | $1.50 per pizza+drink pair |
| Carryout 5% | 5% off carryout (max $5) |
GET /api/pos/deals ·
POST /api/pos/carts/:id/deals/apply ·
POS button Apply deals.
8. Shared storefront (not a pizza site)
| Mode | Use |
|---|---|
retail | Merch / shipping e‑commerce |
restaurant | Pickup/delivery, builders, KDS + delivery after pay |
- Admin → Storefront Settings → Business mode
- Fields:
businessMode,verticalConfigonstorefront_settings - Guest:
/{tenant}/store· paid handoff viastorefrontKitchen.bridge.js
9. Inventory on finalize
| Line type | Behavior |
|---|---|
| Stocked catalog / inventory SKU | Decrement finished good when tracking on |
| Recipe consumable (Sous Chef) | Burn recipe ingredients |
| Configured pizza with Inv ID/SKU on options | Burn size/crust/sauce/toppings (half burn for halves) |
| Unlinked demo “Build a pizza” | Kitchen only — no stock change |
Util: backend/utils/configuratorInventory.js.
Admin: Catalog → Configurator → Inv ID / SKU / burn.
Detail: 25 · Inventory.
10. API map (quick)
| Area | Endpoints |
|---|---|
| Fulfillment | PATCH /api/pos/carts/:id/metadata |
| Deals | GET /api/pos/deals · POST .../deals/apply |
| Kitchen | POST .../send-to-kitchen · GET /api/kds/orders · bump / expo / bag |
| Delivery | /api/delivery/board · status · assign |
| Admin KDS | POST /api/admin/kds/routing/preset/pizzeria |
| Storefront | /api/storefront/:slug/* (config includes businessMode) |
| Aggregators | POST /api/integrations/orders · GET .../by-ref/:source/:id |
11. Aggregator ingest (Phase 3a)
Generic third-party order webhook → same cart / KDS / delivery spine. Partner-specific DoorDash/Uber adapters and menu sync are still later.
| Endpoint | Purpose |
|---|---|
POST /api/integrations/orders | Ingest (idempotent on source + externalOrderId) |
GET /api/integrations/orders/by-ref/… | Lookup prior ingest |
GET /api/integrations/health | Auth / tenant probe |
Auth: staff session or X-Api-Key.
Cart metadata: channel=aggregator, orderChannel=third_party, channelRef.
Table: aggregator_order_refs.
DoorDash / Uber-shaped JSON is auto-mapped.
Optional HMAC: X-Integrations-Signature (+ tenant secret or env).
Smoke: npm run smoke:qsr in app/backend.
Kitchen Displays includes an oven handoff toggle
(ovenHandoffEnabled). Mobile POS supports seating when the device has the visualizer enabled.
Brand pack (3b):
GET/PUT /api/admin/franchise · Storefront Settings → multi-unit brand metadata
for this tenant only (locations under one business — not cross-tenant HQ menu push).
Storefront card tries the payment orchestrator; ?demo=1 for simulate.
12. Operator pilot checklist
- Kitchen Displays → Apply pizzeria stations · set oven handoff on/off.
- Catalog → Configurator → BYO pizza + link toppings to inventory.
- Optional:
/admin/deals— custom fixed $ off + toggle builtins. - POS or Mobile POS → Build pizza + soda → fulfillment / seating → Apply deals → pay / send kitchen.
- If ingredients short → add is blocked with shortfall message.
- KDS → bump make → auto oven ticket (if enabled) → bump oven → Expo → Bag.
- If delivery → ZIP for zone fee ·
/pos/delivery→ assign driver → Out → Delivered. - Storefront Settings → Restaurant mode + zone rows → guest order on
/{tenant}/store. - Tools → QSR smoke check (deals, burns, zones, oven setting, sample aggregator order, make ticket).
- Optional:
POST /api/integrations/orderswith a DoorDash-like payload for channel testing.
13. File anchors
| Area | Path |
|---|---|
| Design MD | docs/PLATFORM-VERTICAL-QSR.md |
| Fulfillment | backend/utils/orderFulfillment.js |
| Configurator inv | backend/utils/configuratorInventory.js |
| Deals | backend/utils/posDeals.js |
| Expo | backend/utils/kdsExpo.js |
| Delivery | backend/services/deliveryDispatch.service.js · routes/delivery.routes.js |
| Aggregator | backend/services/aggregatorIngest.service.js · routes/aggregator.routes.js |
| Storefront kitchen | backend/services/storefrontKitchen.bridge.js |
| POS UI | ModernPOS.jsx · MobilePOS.jsx · fulfillment / seating |
| KDS UI | KitchenDisplay.jsx |
| Dispatch UI | DeliveryDispatch.jsx |
| Storefront UI | Storefront.jsx |