2026-05-03 on prod. Pro tier no longer hits Odoo on the cashier's critical
path. Orders write to cafe.orders (same as Starter); a
cron-trigger Worker fires every minute and drains pending rows into Odoo
as eventual consistency. Reads (/cafe/orders, dashboard,
reports, in-POS Orders view) are fully NIX-native — no JSON-RPC round
trips. Dashboard load went from 3–6s (Odoo) to single-digit ms
(Hyperdrive). Driven by Narong's ask "PRO should just be an upgrade
on Starter — should still work without Odoo API or connection."
cafe.orders + odoo_partner_id + pos_config_id + odoo_product_id on lines + odoo_payment_method_id on payments. 2 partial indexes for the worker queues. Migrations 20260503100000/100100/100200 on backend; batches 6/7/8.submitOrder now POSTs /cafe/api/cafe/orders (the tier-agnostic native route). Orders land with odoo_order_id=NULL and a sync-pending flag. Legacy /api/odoo/{order, order/refund, session, dashboard} routes deleted./cafe/orders, /cafe/orders/[id], /cafe/reports, /cafe/reports/daily, in-POS Orders tab, Telegram /report + cron daily — all switched to aggregateStarterPeriod / listOrdersForTenant / aggregateNativeDailyReport. Pro Odoo-shaped order detail page deleted; orders modal preview is now the universal flow.openShiftAction already wrote cafe.sessions for both tiers (verified). In-shell /cafe/pos?config=N now auto-creates a session row when none exists (silent open with beginningCash=0). Lockable flow keeps explicit cash entry./cafe/api/cafe/cron/odoo-sync route; cron-trigger fires every minute (* * * * *). Per-tenant batch (30 creates + 30 refunds), exponential backoff (1m → 2m → 4m → 8m → 16m), dead-letter at 5 retries, refund counter-orders. Lazy openPosSession per (config, business_date) cached per run. Confirmed firing on prod via wrangler tail.scripts/backfill-pro-tenant-orders.ts get-coffee pulled all 131 historical pos.orders (130 paid + 1 cancelled) and reconstructed 18 closed cafe.sessions. Idempotent — safe to re-run. Backfilled rows carry source='odoo_pulled' so the worker skips them.odoo_order_id stamped: 10–88 seconds in observed runs. The cashier's success modal renders instantly (no Odoo round trip).