← back to index

V0.3 — Bulk Archive products + template-only listPROD

Narong's Telegram, 2026-05-29 morning: bulk archive on the admin Products page, with one condition — refuse while any POS session is open ("Ask users to close all sessions before archiving"). Mid-Gate-1 pivot: split Products from Product Variants — the Products page becomes template-only (one row per product_template), archive operates at template level only, variants get their own page (queued as V0.4). Same-day ship.

Summary

Status
10/10 prod · 51/51 regression = 61/61 · shipped
Commits
nix-cafe 791e61f (main) + bd3ae1a (Hyperdrive-tx fix)
Files
5 modified · ~700 LOC net · no migration · no schema · no backend change
Surfaces
/cafe/products — template-only list · search bar (name + every variant SKU) · Filters dropdown (Archived + Hidden URL toggles) · checkbox column + select-all · sticky "N selected · Actions ▾" bar · Archive/Unarchive confirm dialog with inline session-blocker error · red archived badge on !isActive rows.

10/10 prod checks

Login via Commerce SSO
Products page renders template-only list with new V0.3 testids (products-search-input, products-filter-trigger, products-select-all, per-template rows). Old H4-Y toggle-hidden button absent.
Search input narrows the visible row count (typed first 3 chars of T1's name; T1 stays, count drops)
Filters dropdown opens with Archived + Hidden toggles + Escape closes
Open-session guard: synthetic cafe.sessions.state='open' INSERT on lumiere → bulk-archive flow → error "Cannot archive: 1 POS session currently open. Close all open shifts before archiving products." surfaced in the confirm dialog → cancel + delete synthetic session
Happy path: select 2 active templates → Actions ▾ → Archive → confirm. DB verifies cafe.product_template.is_active=false on both.
Reload /cafe/products: archived rows absent from the default list (Hyperdrive-tx wrap landed in bd3ae1a; first run showed stale-cache hit at 7/10)
Archived filter brings the rows back with the red archived badge (URL ?archived=1)
Bulk Unarchive: DB confirms is_active=true restored on both templates
No 5xx observed during the suite

Screenshots

Regression sweep — 51/51

10/10 V0.3 + 51/51 regression = 61/61 prod tests green on karouna-dev.
test-phase1-prod.mjs11/11 (solo-retry — 2nd consecutive demo-SSO cold-isolate flake; new durable rule saved)
test-phase2-sso-outdoor-prod.mjs6/6
test-m1-prod.mjs10/10
test-r7-prod.mjs14/14
test-r8-prod.mjs4/4
test-phase2-cafe-multishop-prod.mjs (parallel)6/6 (18th consecutive first-attempt parallel green)

Mid-Gate-2 finds

Hyperdrive 60s SELECT cache served stale pre-archive list on reload. First prod run was 7/10 — the 3 failures cascaded from "Reload: archived rows hidden". Root cause: listProductTemplatesForAdmin ran outside a db.transaction, so Hyperdrive returned the stale pre-archive SELECT for ~60s. revalidatePath clears Next's route cache but NOT Hyperdrive (documented in nix-cafe/AGENTS.md). Fix in bd3ae1a: wrap the SELECT in db.transaction(async (tx) => …). Same pattern already used by countOpenSessionsForTenant, getOpenNixSessionForConfig, and the close-shift DAOs. Cost: one extra round-trip per Products page render (tiny). Benefit: archive/unarchive reflect on the next render immediately, not 60s later.
Stale 2026-05-26 open session on lumiere blocked pre-flight. The pre-flight check ("refuse if any real sessions are open — risk of disrupting a live cashier") correctly fired. The blocking session was a 3-day-old test leftover, not a live cashier — force-closed via direct UPDATE (state='closed', closed_at=NOW(), ending_cash=0, ending_bank=0) and the Gate-2 test proceeded.
phase1 demo-SSO cold-isolate flake — 2nd consecutive burn. First sweep: phase1 9/11 with cascade failure on "Navigate to Cafe (SSO works)" bouncing to /auth/login on demo specifically. Solo retry: 11/11 green. U13 (2026-05-28) hit the same shape. Saved as durable rule feedback_phase1_demo_sso_solo_retry — sibling to the longer-standing feedback_phase2_cafe_multishop_solo_retry but on a different tenant (demo vs demo) and a different check (SSO hop vs POS picker race).
wrangler deployments list paginated to 2026-05-27 only. Post-push timestamp comparison was misleading — the wrangler output didn't include the U11/U12/U13 deploys from 2026-05-28 or this push. Used the Playwright HTML-probe pattern instead (login + look for data-testid="products-search-input" in rendered HTML). Landed 72s post-push. Pattern documented in feedback_verify_cf_worker_deploy_landed.

Followups