Busflow Docs

Internal documentation portal

Skip to content

ADR-013: Seat Hold TTL Alignment with Checkout Session TTL ​

Status: βœ… Approved β€” 2026-04-12 Impacts: schema-commerce.md (Β§seat_reservations, Β§checkout_sessions)


Context ​

SeatReservation originally used a 10-minute hold TTL (hold_expires_at), while CheckoutSession used a 30-minute session TTL (expires_at). This mismatch creates a broken UX: a passenger can hold a valid checkout session but lose their seat at the 10-minute mark. This causes a confusing failure at payment time ("Your seat is no longer available").

Conversely, holding seats too long blocks inventory and reduces conversion for other shoppers.

Options Evaluated ​

#OptionProsCons
1Extend seat hold to match session TTL (30 min)Simple, consistent, no UX failure riskBlocks inventory longer
2Heartbeat refresh during checkoutInventory-friendly (short default + extend on activity)Complex frontend logic, requires WebSocket or polling
3Re-acquire at payment timeMinimal hold timeRisk: another shopper may already hold the seat, poor UX

Decision ​

Option 1 for V1: Align seat hold TTL to checkout session TTL (30 minutes).

  • SeatReservation.hold_expires_at is set to the same value as CheckoutSession.expires_at at session creation time.
  • Both expire simultaneously, maintaining consistency.
  • The seat_hold_cleanup Hasura Scheduled Trigger (runs every 60s) releases expired holds.
  • The checkout_abandoned_sweep Hasura Scheduled Trigger (runs every 5 min) expires abandoned sessions.

Phase 2 consideration: The team may implement Option 2 (heartbeat refresh) as a yield optimization when inventory pressure increases. This would shorten the default hold to 10 minutes but extend on frontend activity (every 5 minutes), capped at the session TTL.

Consequences ​

Positive:

  • Zero UX failures from mismatched TTLs
  • Simple implementation β€” single TTL source, no frontend polling
  • Consistent cleanup: both triggers work in harmony

Negative:

  • 30-minute seat holds are longer than typical e-commerce (5–15 min). Acceptable for bus tours where operators measure inventory in dozens of seats, not thousands.

Neutral:

  • Phase 2 heartbeat optimization is backwards-compatible (reduces TTL, doesn't change cleanup mechanics)

Internal documentation β€” Busflow