Cart & Orders — Reference
Lookup tables for the cart lifecycle, statuses, and payment branches. For the concept, read Cart & Checkout — the cart that mirrors the vendor.
Verified against
flex-v3-backendcode (src/modules/cart/), 2026-06-10.
Cart endpoints (the fan lifecycle)
| Endpoint | Does | Vendor interaction |
|---|---|---|
POST /cart/initialize | creates the cart + events (pre-hold) | none — DB only; exists for abandoned-cart analytics |
GET /cart/:cartId | read the cart (cached) | none |
PATCH /cart/:cartId/events | add/remove events | none |
PATCH /cart/:cartId/bind | attach an anonymous cart to a logged-in user | none |
POST /cart/:cartId/manage | hold seats / suites / add-ons | vendor holds (see retry ladder below) |
POST /cart/:cartId/auto-assign | async seat-matching across events (202 + poll GET …/auto-assign/:jobId) | delegates to manage |
POST /cart/:cartId/validate | pre-checkout check: holds alive, prices match | Host: expiry check · Archtics: shopping_cart verify |
POST /cart/:cartId/checkout | payment + vendor commit + order insert | see payment branches |
DELETE /cart/:cartId[/events/:id|/items/:id] | cancel all / one event / one item | releases vendor holds |
The hold retry ladder (4 attempts in manage)
- Exact seats requested.
- Best-available — same section + price code.
- Best-available — same price code, any section.
- Best-available — ticket types only.
Hold expiry: TM Host = vendor-provided hold_time · TM Archtics = fixed constant
(ARCHTICS_DEFAULT_HOLD_SECONDS). If persisting a hold fails, the vendor hold is released immediately.
Statuses
Cart (tbl_carts.cartStatus) | Meaning |
|---|---|
active | initialized, fan shopping |
processing | atomic lock during checkout (race guard, always reset) |
paid | order created successfully |
failed / cancelled / expired | self-explanatory |
Order (tbl_orders.orderStatus) | Meaning |
|---|---|
completed | all items purchased |
refunded / partially_refunded | set by the refund flow, not checkout |
The order row is inserted only after payment succeeds; then the cart flips to paid.
Operational notes: tbl_ticket_sales is written at checkout and read by
GET /transaction/orders to serve order/ticket history. There is no hold-cancelling cron —
Archtics cancels holds by seat block, not cart ID, so a cleanup job could release another fan's
seats; the vendor's ~30-min hold expiry + the ~20-min full inventory rebuild self-heal instead.
(A separate daily job snapshots abandoned carts into tbl_abandoned_carts for analytics.)
Response caching is disabled in production (TTL = 0); the cache layer exists for high-traffic
events. TM Host is not in production yet (no final key).
Cart & order table schema (row level)
The cart is a 3-level hierarchy that mirrors the vendor: tbl_carts → tbl_cart_events →
tbl_cart_items → tbl_cart_seats. Orders carry extra key/value fields in tbl_order_additional_details.
tbl_cart_events — events the cart spans
Created at /cart/initialize and /cart/:id/events (DB-only, no vendor call yet).
| Column | Notes |
|---|---|
cartEventId | PK |
cartId | FK to tbl_carts |
eventCode | the event this row covers |
cartEventStatus | pending · assigned · failed · removed |
tbl_cart_items — one line per held suite / seat-block / add-on
The heart of "the cart mirrors the vendor" — each item tracks its own vendor hold + state.
| Column | Notes |
|---|---|
cartItemId | PK |
cartId / cartEventId | parents (which cart, which event) |
itemType | what this line is (seat block / suite / add-on) |
addonOptionId | set when the item is an add-on (FK to the chosen add-on option) |
eventCode | event the item belongs to |
cartItemStatus | per-item lifecycle (held / committed / released / failed …) |
seatCount | seats represented by this item |
subtotal / serviceFee / totalAmount | money for this line |
holdExpiresAt | when the vendor hold lapses |
retryCount | attempts used by the hold retry ladder |
saleType | sale path (e.g. seat-level vs suite) |
checkoutPhase | where this item is in the checkout state machine |
vendorCartId · vendorEtag · vendorInvoiceReference · vendorShippingId · vendorOrderNumber · vendorOrderToken · vendorRedemptionUrl · vendorAppUrl | vendor handles returned during hold/commit |
vendorRawResponse | full raw vendor payload (debugging / audit) |
tbl_cart_seats — per-seat detail under an item
| Column | Notes |
|---|---|
cartSeatId | PK |
cartItemId | FK to the parent item |
sectionName / rowName / firstSeat / lastSeat / seatCount | the seat block |
suiteId | set for suite inventory |
priceCode / ticketTypeCode | the price combination that resolved |
inventoryType | seat-level vs suite-level |
basePrice / serviceFee / allInPrice / totalPrice | per-seat money breakdown |
vendorOrderLineItem / vendorOfferId / vendorSeatIds | vendor references for the held seats |
tbl_order_additional_details — extra fields on a completed order
| Column | Notes |
|---|---|
detailId | PK |
orderId | FK to tbl_orders |
fieldKey | machine key |
displayLabel | human label shown on the order |
value | the value |
Payment branches at checkout
| Vendor | Mechanism |
|---|---|
| TM Host | Stripe PaymentIntent (idempotency-keyed), manual capture after all vendor commits — capture failure queues refunds |
| TM Archtics | native payment_request with a MOP (method-of-payment) array — no Stripe |
| Payment plan (Archtics) | charge installment 1 only; rows 2..N inserted pending in tbl_payment_plan_installments, charged against a TM invoice by a recurring job; card is force-saved. ⚠️ Not live yet — charging code still in testing |
| Account credit | ⚠️ designed (credit first, card remainder) but not yet implemented in code — upcoming "bank of credit" work |
Partial multi-event commit failure (Host): already-committed events are queued in
tbl_checkout_refunds and refunded by cron (~30 min).
Saved cards (tbl_user_card_details)
- Vendor tokens only, never raw card data: Stripe
pm_…(Host) ·cc_seq_numviacc_update(Archtics). - Scoped per user per team schema — the same fan on two teams has two separate card rows.
- Archtics card lists are cross-checked against the live vendor (
cc_query); stale cards are filtered out.