Checkout sessions
A checkout session is the buyer-facing wizard that culminates in an order. The row in checkout_sessions is short-lived (each session has an expires_at) and holds the buyer's snapshot of delivery method, payment method, and money breakdown until the order row gets created.
Unlike orders / items / disputes, the session is NOT a *-machine.ts FSM — it has no event log table, no transition workflow, and no actor-permission rules. The status is just the wizard step the buyer is on, plus two terminal states for "checkout happened" and "buyer abandoned."
Statuses
flowchart LR
delivery --> payment --> review --> completed
delivery -.expires_at hit.-> expired
payment -.expires_at hit.-> expired
review -.expires_at hit.-> expired| Status | Meaning |
|---|---|
delivery | Buyer picking delivery method + address |
payment | Buyer picking payment method (PIX / credit card / balance) |
review | Final review screen before placing the order |
completed | Order created — apps/web/app/api/v1/checkout/route.ts flips this after createOrder returns |
expired | expires_at passed without completion; expiry is lazy-on-read today (packages/features/checkout/queries/get-checkout-session.query.ts) |
Expiry today
Sessions expire lazily: when get-checkout-session.query.ts reads a row past its expires_at it flips the row to expired in-place. Support reading the table directly will see stale delivery / payment / review rows until that read happens. An eager hourly cron is planned to keep the table truthful for admin / support tools — see the roadmap in /Users/ignaciogiri/.claude/plans/gpt-says-indings-witty-brooks.md (Plan 6).
Why no FSM
The transitions are linear, no actor-permission gating beyond "session owner can act on their own session" (which is RLS, not FSM), and the row is throwaway once the order exists. The order's checkout_session_id FK (added in the god-view roadmap) preserves the link for audit.