Happy House - Ecommerce Docs
Developer ResourcesPayment

Payment Features and Flows

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

Payment Features and Flows

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

1. Documentation Evidence

Source TypeFiles or DocsWhat Was Extracted
APIapps/api/src/modules/payment/customer/payment-customer.controller.ts, admin/payment-admin.controller.ts, gateway-return/gateway-return.controller.tsRoutes, permissions, statuses
Backendshared/payment-attempt.service.ts, payment-settlement.service.ts, payment-completion.service.ts, payment-reconciliation.service.ts, payment-verification.processor.tsTransitions, verification, reconciliation
Gatewaysgateways/esewa.gateway.ts, cod.gateway.ts, payment-gateway.port.tsThe port, the amount-carrying outcome
Schemapackages/db/src/schema/payment/{payment-attempt,payment-event,enums}.tsSix-status enum, flag columns, partial uniques
Error registryapps/api/src/common/types/error-codes.ts (// PAYMENT)PAYMENT_* codes

2. Feature Summary

FieldValue
Modulepayment
SubmoduleN/A (eSewa gateway + COD gateway behind one port)
Primary user valueThe customer pays for a frozen checkout and learns one of seven business outcomes; the operator reconciles the cases where money moved and no sale was recorded
ActorsCustomer, admin, gateway (eSewa), Order module (future)
Main entry points/api/mobile/payments/* (4), /api/payments/esewa/return/* (4 method variants = 2 paths), /api/payments* (3 admin)
Main outputsPayment attempts with signed redirect forms, status polls, admin timelines
Related docsAPI, Backend

3. Actor Matrix

ActorCan DoCannot DoAuth RequirementNotes
CustomerList methods, start a payment, poll an attempt, cancel an attemptCall gateway-return routes, mark a payment paid, learn eSewa's vocabularyJWTPAYMENT_ALREADY_SETTLED is a success wearing a 409 — see §5.2
AdminList (incl. the reconciliation queue), read the full timeline, resolve a flagged paymentMark paid, edit an amount, retry a charge, refundAdmin JWT + Payments_READ/Payments_UPDATEResolve records a note; changes no status
Gateway (eSewa)Call the return routesPer-attempt token in the URLThe routes carry a secret — never call them
Order (future)Create the order from a paid paymentInternalA paid payment means the checkout is completed

4. Capability Matrix

CapabilitySurfaceActorRoute/TriggerState ReadState WrittenLinked API Section
List methodsCustomerCustomerGET /api/mobile/payments/methodsgateway registryAPI §4
Start paymentCustomerCustomerPOST /api/mobile/paymentscheckout, attemptsattempt + eventAPI
Poll attemptCustomerCustomerGET /api/mobile/payments/:idattemptsAPI
Cancel attemptCustomerCustomerPOST /api/mobile/payments/:id/cancelattemptstatus + eventAPI
Gateway returnGatewayeSewaGET/POST /api/payments/esewa/return/:id/:token/success-or-failureattemptstatus + eventsAPI
Admin listAdminAdminGET /api/paymentsattemptsAPI
Admin timelineAdminAdminGET /api/payments/:idattempt + eventsAPI
Admin resolveAdminAdminPOST /api/payments/:id/resolveattemptflag cleared + noteAPI

5. User-Facing Flows

5.1 Start a payment (eSewa)

Summary

A customer picks eSewa. The API creates an attempt, builds a signed form, and the client hands the customer to eSewa. eSewa returns to the API, which verifies server-to-server, then redirects the browser to the storefront result page.

Sequence Diagram

Branches and Edge Cases

BranchConditionBehaviorError/Result
Double submitAttempt already in flight200 with the same body — not an errorsame attempt
Other method liveDifferent method in flight409PAYMENT_ATTEMPT_ALREADY_LIVE
Gateway unansweredPrevious attempt pending409 — do not offer a retry, pollPAYMENT_VERIFICATION_PENDING
Already settledCheckout paid, order being written409 — a success wearing 409PAYMENT_ALREADY_SETTLED
eSewa not configuredNo credentialsMethod list has only CODPAYMENT_METHOD_UNAVAILABLE if asked

5.2 The seven business statuses

statusWhat happenedWhat the client does
awaiting_gatewayAttempt exists; hand to the gatewayPOST redirect.fields to redirect.url as a form
processingGateway not final — also what needs-manual-review reports, deliberatelyShow "confirming", poll after retryAfterSeconds; for review, show the message verbatim, no retry button
paidDone; order can be createdSuccess — always render it as one; if shortVariants (renamed from shortProducts) is non-empty, additionally say those items will not be included. Never render paid as a plain success without checking it first
failed_retryableNot paid; checkout still usableShow message, offer another method
failed_finalNot paid; checkout closedShow message, back to cart
cancelledCustomer stopped itBack to checkout
already_settledThis attempt was already resolvedTreat as paid

processing is what a payment needing manual review reports — money may have moved and a human is looking at it; telling the customer it failed would invite them to pay again.

5.3 Cash on Delivery

COD returns status: "paid" and redirect: null in the same response — nothing to hand off; the order can be created immediately. COD is a payment method, not a bypass: same attempt row, same transitions, same audit trail. Its "gateway" approves at hand-off.

5.4 The result page

After eSewa, the API lands the browser on {FRONTEND_BASE_URL}{PAYMENT_RESULT_PATH}?status=…&payment={attemptId}&checkout={checkoutId} (statuspaid, processing, failed, cancelled, unknown). Treat the query string as a hint, not as truth — it is unauthenticated and a customer can edit it. Call GET /api/mobile/payments/:id and render from that.

6. Admin Flows

  • List — standard pagination; filters status, method, customerId, checkoutId, minAmount, maxAmount, awaitingReconciliation, sortBy, order.
  • awaitingReconciliation=true is the queue that matters — payments where money moved and no sale was recorded. The screen an operator opens every morning; it empties as they resolve.
  • Detail — the attempt plus timeline: every transition and every gateway message, oldest first, append-only. The row says where a payment ended; the timeline says how it got there — what a disputed charge needs. Gateway payloads are already redacted.
  • Resolve{ "note": "…" } (10–2000 chars) records what a human decided; changes no status, no amount, no outcome; takes the case out of the queue.

There is deliberately no admin route to mark a payment paid, edit an amount, retry a charge or refund one. Marking paid is refused by a database constraint, not merely absent.

7. Lifecycle and State Transitions

7.1 The attempt lifecycle

FromEvent/ActionToGuard ConditionSide Effects
createinitiatedcheckout not expired
initiatedhand to gatewayawaiting_gatewaymethod configuredsigned form (eSewa)
awaiting_gatewaygateway contactedpending_verificationpoll begins
pending_verificationverified, amount matchessucceededconfirmed amount = requested (CHECK)checkout completes + outbox enqueue in the same tx
pending_verificationgateway declinesfailedretryable/final per outcome
pending_verificationgave up after asksexpiredbackoff exhaustedflagged for reconciliation
any non-terminalcustomer cancelscancellednot paid

payment_attempt_status has SIX valuesinitiated, pending_verification, succeeded, failed, cancelled, expired. There is no seventh "needs a human" status: that is the reconciliation flag (reconciliation_flagged_at + reconciliation_reason), orthogonal to the outcome and true of succeeded, failed and expired attempts alike.

7.2 PENDING is not a decline

A gateway that says "ask later" parks the attempt (pending_verification), keeps the checkout's payment slot held so a second charge cannot start, and is re-asked on a bounded backoff. Running out of asks expires the attempt and flags it — a customer whose money left their account deserves better than a silent expiry.

9. Data and Side Effects by Flow

FlowDB WritesCache EffectsJobsRealtimeAnalyticsNotifications
Start paymentattempt + event
Gateway successattempt → succeeded + eventoutbox → COMPLETE_SETTLED_CHECKOUT (same tx)
Verify/polleventsverification retries (bounded backoff)
Expiryattempt → expired + flagexpiry sweep
Resolveflag cleared + note

Payment caches nothing.

10. Error and Recovery Flows

ScenarioTriggerUser/System ExperienceRecoverySource
Double-charge riskTwo refusals are NOT failuresSee §5.1 branchesPoll, never retryPAYMENT_VERIFICATION_PENDING, PAYMENT_ALREADY_SETTLED
Gateway silentNo callbackAttempt pending until backoff exhaustsExpiry + flag → admin resolveverification processor
Amount mismatchGateway confirms different figureRefused by CHECK; flaggedAdmin resolveschema
Confirmation lands lateOn a closed attemptZero matched rows → re-read, never benignFlag if genuinely strandedsettlement service
Method unavailableNot configured400Re-fetch /methodsregistry

11. Diagrams Required Per Module

  • Actor capability diagram — §3/§4.
  • Sequence diagram per major flow — §5.1.
  • State machine diagram — §7.1.
  • 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
Start201 vs 200CustomerDouble submitBoth same bodystatus code distinguishes
StartSigned formCustomereSewaPOST exactly as givenHMAC over field set
StartCOD instant paidCustomerCODredirect nullsame transitions
PollNever re-queries gatewayCustomerRepeated callsFreereads state only
ReturnToken in URLGatewayRedirectSHA-256 stored onlyredactUrlSecrets
VerifyServer-to-serverSystemReturn hitBrowser redirect never proofstatus API
Admin listReconciliation queueAdminawaitingReconciliation=trueMorning screen
Admin detailTimelineAdminDisputeAppend-only eventspayloads redacted
ResolveNote onlyAdminDecisionQueue emptiesno status change

12.2 Business Process Diagram Pack

12.3 Business Rules and Policy Traceability

RuleBusiness ReasonActor ImpactEnforced InAPI ImpactBackend ImpactTests
No payment tableOne copy of the amountschema (none exists)grand_total stays singularprobe
Outcome carries amountReplay unwritableSafe chargesport + CHECKverified amount must matchint spec
Succeeded before completeNo order without moneyordering + outboxCOMPLETE_SETTLED_CHECKOUT same txspec
Reconciliation = flagOutcome not erasedQueue screencolumnsawaitingReconciliationsix-status enumprobe
Zero-match re-readNo silent discardsservicere-read before benignint spec
Four return defencesForged redirectsSafetoken + HMAC + status check + DBredactionspec
COD same pathNo bypassStock decrementportsame transitionsspec
Never write checkout_sessionNo silent bypassservice boundaryinventory finalisation intactspec

12.4 Tradeoffs and Product Rationale

Product DecisionUser BenefitEngineering BenefitAlternativeTradeoffRisk
Attempt/event tablesAudit trailReplay-proofpayment tableMore rowsAccepted
Short transactionsNo locks over HTTPIdempotent writesOne txPartial statesAttempt-scoped
Flag not statussucceeded_at survivesQueue by flagSeven-status enumTwo columnsDocumented
Signed form to clientStorefront never learns gatewayServer-side redirectClient must POST exactlyWarned
No admin mutationsConstraint-refusedNo repriced chargesAdmin overrideSupport burdenResolve note

12.5 Flow Edge-Case Matrix

FlowEdge CaseTriggerExpected BehaviorUser/System FeedbackSource
StartCheckout lapsedexpires_at passed409CHECKOUT_SESSION_EXPIRED
StartNot their checkoutWrong id404 (no oracle)CHECKOUT_SESSION_NOT_FOUND
StartMethod unlistedNot configured400PAYMENT_METHOD_UNAVAILABLE
ReturnForged tokenAttackerRefusedSHA-256 + HMAC
ReturnTampered fieldsEdited formHMAC fails
VerifyStatus API omits amountGateway bugPort rejectsflagged
ConfirmLate on closed attemptSlow gatewayRe-read, flag
ExpiryBackoff exhaustedGateway silentexpired + flaggedadmin queue
CancelAlready paidDouble tap409 NOT_CANCELLABLEshow success
ResolveAlready resolvedTwo admins400PAYMENT_RESOLUTION_NOT_APPLICABLE

12.6 Flow-to-Data Trace

FlowReadsWritesCacheJobs/EventsResponse Fields
Startcheckout, attempts, registryattempt + eventid, status, amount, redirect
Pollattemptsstatus, message, retryAfterSeconds
Return/verifyattemptstatus + eventsoutbox → complete303 to result page
Admin listattemptsrows + pagination
Resolveattemptflag + notemessage

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 (amount-carrying outcome, outbox ordering, four defences).
  • The doc covers every minor flow and branch.
  • The doc includes user, admin, gateway 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