Happy House - Ecommerce Docs
Developer ResourcesCheckout

Checkout Features and Flows

Complete feature list, actor journeys, state flows, business rules, edge cases, and diagrams for the Checkout module.

Checkout Features and Flows

Use this page for the checkout domain: what it does for customers and admins, and how each flow behaves from start to finish.

1. Documentation Evidence

Source TypeFiles or DocsWhat Was Extracted
APIapps/api/src/modules/checkout/customer/checkout-customer.controller.ts, admin/checkout-admin.controller.tsRoutes, permissions, rate limits
Backendshared/checkout-session.service.ts, checkout-payment.service.ts, checkout-release.service.ts, checkout-transition.util.ts, checkout-validation.util.tsOne transaction, transitions, attempt scoping
Schemapackages/db/src/schema/checkout/{checkout-session,checkout-session-item,checkout-session-promotion,enums}.tsGrand-total CHECK, partial uniques, expiry
Workersworkers/checkout-expiry-sweep.processor.ts, checkout-maintenance.scheduler.tsThe sweep and its exemption
Error registryapps/api/src/common/types/error-codes.ts (// CHECKOUT)CHECKOUT_* codes

2. Feature Summary

FieldValue
Modulecheckout
SubmoduleN/A
Primary user valueA validated, price-frozen purchase attempt that holds stock for fifteen minutes, recoverable from every failure short of a silent gateway
ActorsCustomer (signed in), admin (read + release only), payment module (future)
Main entry points/api/mobile/checkout (3 routes), /api/checkout/sessions (4 routes)
Main outputsCheckout sessions with frozen pricing, reservations, and a payment contract
Related docsAPI, Backend

3. Actor Matrix

ActorCan DoCannot DoAuth RequirementNotes
CustomerStart checkout, fetch their active session, cancel their own pending sessionCall payment-side transitions (no HTTP surface), see another customer's session (404, never 403), cancel while a payment is at the gatewayJWTCUSTOMER_CHECKOUT_ATTEMPT 10/min (start), CUSTOMER_READ 60/min, CUSTOMER_WRITE 20/min — account-keyed
AdminList, read, cancel (fraud/duplicate), force-expire (stuck at gateway)Edit or delete a session — a purchase contract an operator can reprice is not a contractAdmin JWT + Checkout_READ/Checkout_UPDATEBoth release actions record which administrator acted
Payment (future)markPaymentStarted / complete / failInternalAttempt-scoped contract — see backend §6

4. Capability Matrix

CapabilitySurfaceActorRoute/TriggerState ReadState WrittenLinked API Section
Start checkoutCustomerCustomerPOST /api/mobile/checkoutcart, address, inventory, promotionsession + holds (one tx)API §4
Active sessionCustomerCustomerGET /api/mobile/checkout/activesessionsAPI
Cancel own sessionCustomerCustomerPOST /:id/cancelsessionstatus + releasesAPI
Admin listAdminAdminGET /api/checkout/sessionssessionsAPI
Admin detailAdminAdminGET /:idone sessionAPI
Admin cancelAdminAdminPOST /:id/cancelsessionreleases + auditAPI
Admin force-expireAdminAdminPOST /:id/expiresessionreleases + auditAPI
Payment transitionsInternalPayment (future)service callssessionstatus + attemptbackend §6

5. User-Facing Flows

5.1 Start checkout

Summary

A customer confirms their basket. The server validates everything (cart readiness, product availability, stock, address serviceability, coupon), reserves inventory and the promotion slot, freezes prices, and commits it all in one transaction. The customer is shown the frozen total and sent to the payment gateway.

Sequence Diagram

Branches and Edge Cases

BranchConditionBehaviorError/Result
Repeat POSTLive session existsSame session, 200 — double-click/retry/two tabs safe200, one live session
Empty cartNo cart or no lines409CHECKOUT_CART_EMPTY
Stale cart versionAnother device changed it409CHECKOUT_CART_CHANGED
Blocking validationCart not ready409 + details.blockingReasonsCHECKOUT_CART_NOT_READY
Product goneWithdrawn/deleted409 + unavailableVariantIdsCHECKOUT_PRODUCT_UNAVAILABLE
Not enough stockShortfall409 + shortfalls[]CHECKOUT_INSUFFICIENT_STOCK
Address problemUnknown/archived/not theirs404CHECKOUT_ADDRESS_NOT_FOUND
UnserviceableNo delivery to district409CHECKOUT_ADDRESS_NOT_SERVICEABLE
Coupon inapplicableDoes not apply409 + details.reasonretry without the coupon is validCHECKOUT_COUPON_NOT_APPLICABLE

5.2 The payment window

The session holds stock for the session TTL plus a full payment window (CHECKOUT_HOLD_TTL_SECONDS) — the holds deliberately outlive the session, because inventory and promotion sweep their own holds on their own schedules and would reclaim them mid-payment. The countdown runs from server-computed expiresInSeconds; at zero the session reads expired (the read predicate, regardless of any background job) and the customer starts again.

5.3 A declined card

A retryable failure returns the session to pending_payment with the holds intact — the customer reaches for a second card. A non-retryable one releases everything.

5.4 Cancel and force-expire (admin)

  • cancel — for a pending_payment session an operator judges fraudulent or duplicated.
  • expire — for a session stuck at a payment gateway that never called back. The only lever for that state, because the automatic sweep deliberately never touches payment_in_progress.

Both release the held stock and the coupon slot, unlock the cart, and record which administrator acted.

6. Admin Flows

List (status/customer/date/total filters, offset pagination, sort by createdAt/updatedAt/expiresAt/grandTotal) and detail. Admin may read and release, never edit — no update route, no delete route: a purchase contract an operator can reprice is not a contract.

7. Lifecycle and State Transitions

7.1 Session states

FromEvent/ActionToGuard ConditionSide Effects
startpending_paymentOne live session per customer (partial unique)Holds taken, prices frozen
pending_paymentmarkPaymentStartedpayment_in_progressexpires_at > now()Attempt number assigned
payment_in_progresscompletecompletedSame attemptOrder may be created elsewhere
payment_in_progressfail (retryable)pending_paymentSame attemptHolds intact
payment_in_progressfail (non-retryable)cancelledSame attemptHolds released
pending_payment / payment_in_progresscancel / force-expirecancelledNot already terminalHolds + coupon released, cart unlocked
any non-terminalsweep (past expires_at)expiredpayment_in_progress exemptHolds released, audit

Every payment-side transition carries the attempt number. The retry makes the state machine cyclic, and once a cycle exists "a duplicate matches nothing" stops being true — a redelivered decline for a superseded attempt would knock a live payment back and let the real success no-op silently.

9. Data and Side Effects by Flow

FlowDB WritesCache EffectsJobsRealtimeAnalyticsNotifications
Startsession + items + promotions + holds (one tx)
Cancel (customer/admin)status + releases + audit
Force-expirestatus + releases + audit
Sweepexpired sessions + releasescheckout queue

Checkout caches nothing. The module is synchronous apart from the sweep.

10. Error and Recovery Flows

ScenarioTriggerUser/System ExperienceRecoverySource
Stale cartCart changed elsewhere409Reload, show changes, retryCHECKOUT_CART_CHANGED
Payment declinedCard rejectedSession back to pendingSecond card — holds intactretryable fail
Session expiredCustomer dawdled409 CHECKOUT_SESSION_EXPIREDStart againread predicate
Not cancellableAlready terminal409RefreshCHECKOUT_SESSION_NOT_CANCELLABLE
Payment in progressGateway live409 CHECKOUT_PAYMENT_IN_PROGRESSFinish or contact supportattempt guard
Silent gatewayNever calls backSession stuckAdmin force-expiresweep exemption

11. Diagrams Required Per Module

  • Actor capability diagram — §3/§4.
  • Sequence diagram per major flow — §5.1.
  • State machine diagram — §5.3/§7.
  • Data side-effect diagram — §9.
  • Error branch diagram — §10.

12. Mandatory Feature and Flow Deep-Dive Pack

12.1 Feature Inventory With Minor Behaviors

FeatureMinor BehaviorActorTriggerUser/System ResultBackend Side EffectSource
StartUnknown property rejectedCustomerExtra field in body400 — not silently strippedstrict DTO
StartRepeat POSTCustomerDouble-clickSame session, 200partial unique
StartcartVersion optionalCustomerNo loaded cartOmitted → no conflict
Startreserved: false lineCustomerUntracked productNormal, not failurenothing held
StartpriceChange.changedCustomerPrice movedWarning, not blockerfrozen at current
StartDiscount from reservationSystemPromotion re-evaluatesSession agrees with ledgerown row lock
Start404 same for others/unknownCustomerWrong idNo existence oracle
CancelOwn pending onlyCustomerLive payment409 PAYMENT_IN_PROGRESS
Admin cancelFraud/duplicateAdminJudgmentRelease + audit
Admin expireStuck gatewayAdminNo callbackOnly lever
SweepExempt payment_in_progressSystemPast expiryNever released mid-paymentpartial index
PaymentAttempt scopingSystemRedelivered declineHarmless for old attemptattempt number

12.2 Business Process Diagram Pack

12.3 Business Rules and Policy Traceability

RuleBusiness ReasonActor ImpactEnforced InAPI ImpactBackend ImpactTests
One transactionNo partial stateFailed checkout leaves nothingDbExecutor threadingatomic commitint spec
Holds outlive sessionSweeps don't know sessionsNo mid-payment reclamationTTL constantexpiresInSecondsCHECKOUT_HOLD_TTL_SECONDSspec
Expiry as read predicateNo stale pay-for-stock windowStatus always correctreadsstatus: expiredsweep writes only to recordspec
payment_in_progress sweep-exemptNo unfulfillable chargeStuck sessions possiblepartial indexadmin force-expirespec
Grand total CHECKNo wrong chargeDisplay any partschematotalsarithmetic invariantprobe
One live per customerDouble-click story200 on repeatpartial uniquespec
Retryable fail keeps holdsDeclined card ≠ lost basketSecond card possibletransitionspec
Attempt-scoped transitionsCyclic machine safeRedelivered decline harmlesstransition utilattempt numberspec
Discount from reservationSession agrees with ledgerConsistentservicespec
Everything snapshottedHistory immutableReceipts never join live tablesschemaprobe

12.4 Tradeoffs and Product Rationale

Product DecisionUser BenefitEngineering BenefitAlternativeTradeoffRisk
One transactionNo orphan stateSmall moduleSaga/coordinatorAll modules must accept DbExecutorAlready true
Holds TTL = session + payment windowNo mid-payment lossSimpleSession-length holdsLonger holdsReleased on expire immediately
Expiry as predicateAlways correctNo flip jobStored statusCompute per readCheap
Sweep exempts gatewayNo unfulfillable chargeSweep everythingStuck sessionsAdmin force-expire
Attempt scopingSafe retriesIdempotency onlyCyclic machineAttempt number
Admin read-onlyContract integrityAdmin editCan't fix errorsCancel/expire only
Snapshots everywhereImmutable historyReferencesStorageAccepted

12.5 Flow Edge-Case Matrix

FlowEdge CaseTriggerExpected BehaviorUser/System FeedbackSource
StartEmpty cartNo lines409CART_EMPTY
StartStale versionCart changed409CART_CHANGED
StartShortfallStock dropped409 + shortfallsINSUFFICIENT_STOCK
StartUnserviceableBad district409ADDRESS_NOT_SERVICEABLE
StartCoupon invalidNot applicable409 + reasonCOUPON_NOT_APPLICABLE
StartRepeatLive session200 same session
CancelExpiredLapsed409SESSION_EXPIRED
CancelAt gatewayPayment live409PAYMENT_IN_PROGRESS
PaymentRedelivered declineOld attemptNo-opattempt
PaymentDecline then successAttempt 2Success winsattempt
SweepGateway never callsSilentSession stuckforce-expire
Expiry raceCustomer pays at boundaryexpires_at passesPayment transition guardedSTART_PAYMENT requires expires_at > now()

12.6 Flow-to-Data Trace

FlowReadsWritesCacheJobs/EventsResponse Fields
Startcart, address, inventory, promotionsession + items + promotions + holdscheckout, pricing, items, promotions, shipping, payment
Active/cancelsessionsstatus + releasessession/whole shape
Admin list/detailsessionsrows + pagination
Admin cancel/expiresessionstatus + releases + auditmessage
Sweepsessionsexpired + releasescheckout queue

12.7 Experience Quality Checklist

  • The doc explains what the actor is trying to accomplish.
  • The doc explains what the backend does that the actor does not see (one transaction, holds TTL, attempt scoping, snapshots).
  • The doc covers every minor flow and branch.
  • The doc includes user, admin and system flows.
  • The doc explains business logic, tradeoffs, and rationale.
  • The doc maps every flow to API routes and backend side effects.
  • The doc includes diagrams appropriate to each flow type.
  • The doc covers edge cases and failure recovery.

13. Completion Checklist

  • Every feature, minor action, and submodule capability is listed.
  • Every actor has allowed and forbidden behavior.
  • Every major and minor flow includes steps, branches, and diagrams.
  • Every lifecycle has a transition table and state diagram.
  • Every flow links to the API and backend docs.
  • TDD dependencies are called out where they shape behavior (no TDD pages published yet).

See Also