In-shell receipt preview before the print dialog fires. Operators get to eyeball the receipt before handing it to a customer or before committing to a reprint. Bundled with this Gate cycle: the full Render→Supabase prod database migration after Render's free tier auto-suspended.
receipt-print-iframe-{orderNumber}); zero popup windows opened. Confirmed no popup-blocker risk.GET /api/cafe/orders/:id, opens the modal, Print receipt spawns the iframe.| test-receipt-preview-prod.mjs (this bundle) | 8/8 |
| test-r2-followups3-prod.mjs (round 3) | 7/7 |
| test-r2-followups2-prod.mjs (round 2) | 11/11 |
| test-r2-followups-prod.mjs (round 1) | 19/19 |
| test-nix-os-r2-4b-prod.mjs (Starter UI) | 12/12 |
| test-nix-os-70-2-prod.mjs (R2 uploads) | 10/10 |
| test-phase1-prod.mjs (route smoke + SSO) | 11/11 |
Trigger: Render free-tier Postgres auto-suspended on inactivity, blocking
prod tests. Migrated to Supabase (aws-1-ap-northeast-1.pooler.supabase.com)
during the Gate 2 cycle for receipt preview.
Steps executed:
1. Patched nix-outdoor-sales-backend/knexfile.ts + migrate.js to
enable SSL for any non-localhost host (was hardcoded "render.com").
Committed as fix(db): 76e9df5.
2. Ran 99 knex migrations against Supabase via session-mode pooler (port 5432).
Migrations hung on port 6543 — pgbouncer transaction mode kills knex's
prepared statements during apply.
3. Ran migrate.js to layer on cafe/commerce + discount columns. All
idempotent passes confirmed.
4. Seeded get-coffee tenant + Narong owner via env-driven seed script
(scripts/seed-supabase-getcoffee.ts — env-overridable). Used the same
DB_ENCRYPTION_KEY as the prod Worker so encrypted Odoo creds round-trip.
5. Seeded demo tenant for phase1 SSO tests.
6. wrangler secret put DATABASE_URL — Cafe Worker now points at Supabase.
7. wrangler hyperdrive update 47d252536c3746fcbdf39d332043810c —
INITIALLY targeted port 6543 (transaction mode); /cafe/dashboard 500'd
with "Failed query" on prepared statements. Switched to port 5432
(session mode) — Hyperdrive does its own edge pooling so the
session-mode origin doesn't add connection pressure.
8. Aligned DB_ENCRYPTION_KEY between local .env.local and Worker secret —
local key was different, so encrypted Odoo creds didn't decrypt.
getTenant returned null and /cafe/pos showed "Cafe is not configured".
9. Updated PROD_DB constant in 32 test-*-prod.mjs files (sed batch) +
reference_prod_database.md memory.
Heads-up captured in memory:
- Use port 5432 for EVERYTHING (Hyperdrive, runtime, migrations, seeds).
pgbouncer transaction mode (6543) breaks Drizzle/pg/knex prepared
statements.
- DB_ENCRYPTION_KEY must match between local .env.local and the Worker
secret, or encrypted columns (cafe.tenant_config.odoo_api_key_enc)
won't round-trip.
nix-cafe (commit cdfe197):
components/receipt/receipt-preview-modal.tsx — NEW shared modal
app/(authed)/pos/starter-register-client.tsx — LastOrderBanner uses modal
app/(authed)/orders/starter-orders-client.tsx — per-row Print uses modal
nix-outdoor-sales-backend (commit 76e9df5, ride-along):
knexfile.ts + migrate.js — SSL enabled for any non-localhost host
(supports Supabase migration off Render)
• "Skip preview" path on the success banner — currently every Print opens the modal first. If operators want fast-path printing immediately after a sale (since they just rang it up and know what's on it), one-line if. • Receipt preview is currently rendered at desktop width but uses the thermal 72mm template — looks a bit narrow on a 24" monitor. Could scale up the visual preview while keeping the print at 80mm. • Render free-tier database is permanently dead. Memory now points at Supabase. Old Render URL "dpg-d739ftoule4c73eup080-a..." in any of Narong's notes / scripts / .env files needs to be replaced. • Hyperdrive caching at the Cafe Worker layer is unchanged from before — still ~60s SELECT TTL bypassed via db.transaction() in getTenant. Same gotchas apply.