Approved
Builder: Flux + Gluon
QA: Quasar
Pre-build checklist in progress
BEO ↔ Square Sync
Auto-create Events + BEOs from Square estimates, invoices, and online orders. Maintain linkage for status sync. Package line item model with FOH/kitchen split view. Iris conversational intake for Tina.
End-to-End Workflow
Package Line Item Model
Square sells packages as a single line item (e.g. "Corporate Package — 25 Count"). The BEO needs to show both views:
- FOH / invoice reconciliation — sees the package name to match against the Square invoice
- Kitchen / production — sees the individual component items, each on its own line with quantity
Print / UI Rendering
📦 Corporate Package (25 Count) × 2 · Sq Invoice #000891 ✓
Bánh Mì Sliders × 50
Ham & Cheese Sliders × 50
Caesar Wrap × 25
Sparkling Water × 50
Breakfast Burrito × 10 · ⚠ not on invoice
Breakfast Burrito × 10 · ⚠ not on invoice
Line items added after invoice payment are editable but flagged "not on invoice." Kitchen sees them; FOH knows they're additions outside the original charge.
Do We Need a Package Reference Table?
Yes — a
Without it, package expansion is manual every time and there's no data integrity. The table maps a Square catalog item (package) to its component items with quantities. Ops maintains it; the system reads it at BEO creation time to auto-expand packages.
package_line_items table is required.Without it, package expansion is manual every time and there's no data integrity. The table maps a Square catalog item (package) to its component items with quantities. Ops maintains it; the system reads it at BEO creation time to auto-expand packages.
-- Package reference: maps Square package catalog IDs to BEO component items
CREATE TABLE IF NOT EXISTS package_components (
id TEXT PRIMARY KEY,
package_catalog_id TEXT NOT NULL, -- Square catalog item ID for the package
package_name TEXT NOT NULL, -- e.g. "Corporate Package (25 Count)"
component_name TEXT NOT NULL, -- e.g. "Bánh Mì Sliders"
component_variation TEXT, -- e.g. "Regular (2 Count)"
quantity_per_package INTEGER NOT NULL DEFAULT 1,
menu_item_id TEXT REFERENCES menu_items(id),
sort_order INTEGER DEFAULT 0,
active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- beo_line_items additions
ALTER TABLE beo_line_items ADD COLUMN IF NOT EXISTS parent_line_item_id TEXT REFERENCES beo_line_items(id);
-- NULL = top-level item; non-NULL = component child of a package
ALTER TABLE beo_line_items ADD COLUMN IF NOT EXISTS is_package_parent BOOLEAN DEFAULT FALSE;
ALTER TABLE beo_line_items ADD COLUMN IF NOT EXISTS invoice_matched BOOLEAN DEFAULT NULL;
-- TRUE = matches Square invoice line item; FALSE = added post-invoice; NULL = unknown
ALTER TABLE beo_line_items ADD COLUMN IF NOT EXISTS square_line_item_id TEXT;
Auto-Expansion Logic
- Square order line item arrives with catalog_object_id
- Look up
package_componentsbypackage_catalog_id - If found → create parent BEO line item (package) + child items (components), linked via
parent_line_item_id, qty = package qty × component qty_per_package - If NOT found → create single line item, set
needs_expansion = TRUE, flag in health check for manual expansion by ops
Status Mapping — Square → BEO
Square: DRAFT
→ Estimate Out / In Progress Order
Kitchen print suppressed. Not sent to customer yet.
Square: UNPAID
→ Estimate Out / In Progress Order
Sent to customer, awaiting payment.
Square: PAID / PARTIALLY_PAID
→ Confirmed / Confirmed Order
line_items_locked = TRUE
Square: CANCELED
→ Cancelled / Cancelled
Event and BEO both cancelled.
Post-Payment Line Item Editing
Model (confirmed by Robert 2026-05-13): When an invoice is paid, line items remain editable — but any item added or changed after payment is flagged
invoice_matched = FALSE. The flag persists on the BEO print so FOH knows these items are outside the original charge and kitchen knows what to actually produce.
Why not a second BEO?
A second BEO would confuse the kitchen — they'd have two documents to reconcile for one event. Instead, all items for an event stay on one BEO. The
invoice_matched flag provides the financial audit trail FOH needs without splitting the kitchen's pick list.
UI Behaviour
- Items with
invoice_matched = TRUE→ show invoice # badge (e.g.#000891 ✓) - Items with
invoice_matched = FALSE→ show ⚠ not on invoice badge - No hard lock after payment — editing stays open, flag is automatic
- BEO print template renders invoice-matched and non-matched items with distinct visual treatment
- Package children inherit the parent's
invoice_matchedstatus
Full Schema Migration (additive only)
-- New table
CREATE TABLE IF NOT EXISTS package_components ( ... );
-- events
ALTER TABLE events ADD COLUMN IF NOT EXISTS square_invoice_id TEXT;
-- beos
ALTER TABLE beos ADD COLUMN IF NOT EXISTS square_invoice_id TEXT;
ALTER TABLE beos ADD COLUMN IF NOT EXISTS square_invoice_status TEXT;
-- beo_line_items
ALTER TABLE beo_line_items ADD COLUMN IF NOT EXISTS parent_line_item_id TEXT REFERENCES beo_line_items(id);
ALTER TABLE beo_line_items ADD COLUMN IF NOT EXISTS is_package_parent BOOLEAN DEFAULT FALSE;
ALTER TABLE beo_line_items ADD COLUMN IF NOT EXISTS invoice_matched BOOLEAN DEFAULT NULL;
ALTER TABLE beo_line_items ADD COLUMN IF NOT EXISTS square_line_item_id TEXT;
ALTER TABLE beo_line_items ADD COLUMN IF NOT EXISTS needs_expansion BOOLEAN DEFAULT FALSE;
All changes are additive. No existing columns dropped, renamed, or type-changed. No FK changes to existing tables.
Pre-Build Checklist
| Item | Status | Owner |
|---|---|---|
| Robert answers 5 open questions | Done — 2026-05-13 | Robert |
| Axiom confirms schema is additive-only | In progress | Axiom |
| Dedup audit script written + run read-only | In progress | Axiom |
create-beo skill written | In progress | Axiom |
| Quasar test plan written | In progress | Axiom |
| Robert approves to proceed to build | Pending checklist | Robert |
Phased Delivery
Phase 1 — Build now
Schema · create-beo skill · sync worker · package_components table · invoice_matched flag · UI badges
Phase 2
Iris conversational intake · Square DRAFT invoice creation · Square webhooks (replace polling)
Phase 3
Ops-maintained package_components UI · BEO → Square partial reverse sync (pre-payment only)