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
StatusMeaning
deliveryBuyer picking delivery method + address
paymentBuyer picking payment method (PIX / credit card / balance)
reviewFinal review screen before placing the order
completedOrder created — apps/web/app/api/v1/checkout/route.ts flips this after createOrder returns
expiredexpires_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.

On this page