Data & Execution Flow
Request lifecycle
Every protected request flows through the same middleware chain before reaching a thin controller that delegates to a service. Errors are never swallowed — handlers call next(error) and a single central errorHandler shapes the response and reports 5xx to Sentry.
Response envelope is uniform:
// success
{ "success": true, "data": { /* ... */ } }
// error
{ "success": false, "error": { "code": "STRING_CODE", "message": "..." } }Authentication & OTP flow
New users are created as Light Users (profileComplete: false) after OTP verification and can browse everything; the first write attempt routes them to /complete-profile, which promotes them to an Active User and assigns a membership number.
Refresh-token rotation is single-use with a grace window: each refresh issues a new token and keeps the previous one valid for REFRESH_TOKEN_GRACE_MS (default 60s) so a lost-response retry doesn't force a logout. The web axios interceptor distinguishes a transient refresh failure (5xx/network → keep the session) from a terminal one (401 on refresh → log out).
Notifications — never call MSG91 inline
A hard architectural rule: request handlers never call MSG91 directly. They enqueue a job and return; a separate worker process sends the SMS. Every SMS event also writes an in-app notification, which is the authoritative channel.
Deal lifecycle — deduct-on-receipt
Accepting an offer/bid materialises an Order in PLACED and reserves the seller's lot (held, not decremented). The physical stock-out happens only when the buyer confirms receipt, in the same transaction that creates the buyer's batch — so seller-out equals buyer-in exactly. Dispatch is a status-only step and never moves stock.
The Order carries three orthogonal axes so future capabilities append without churning the commercial spine:
status— commercial spine (PLACED→COMPLETED/CANCELLED/COMPLETED_OFF_PLATFORM)fulfilmentStatus—PENDING/DISPATCHED/DELIVERED(tracking states reserved)paymentStatus—OFF_PLATFORM(escrow reserved for Phase 2)
Offer / Bid state machine
An offer (on a sell lead) or bid (on a buy lead) moves through one shared state machine. There is no counter-of-counter — an owner may counter each engagement once.
Partial multi-acceptance: a lead allows up to 2 acceptances; total accepted quantity cannot exceed the lead's quantity. The lead auto-closes when either cap is hit, auto-rejecting the remaining PENDING/COUNTERED engagements.
Quota metering (3 axes, IST daily reset)
Continue to Design Patterns →.
