Escrow & Order Lifecycle Architecture
1. Executive Summary & Core Philosophy
Debelu is built upon a closed-loop escrow financial model. In campus and digital commerce across Nigeria, the absence of trust between unacquainted student buyers and independent merchants is the single greatest barrier to transaction completion.
Debelu bridges this trust gap through an automated escrow state machine:
- Buyer Protection: Funds are collected at checkout and held securely in Debelu's master escrow settlement account. Funds are never released to the seller prior to verified physical receipt.
- Seller Protection: Sellers receive an immutable guarantee that payment has been captured and locked before dispatching goods or handing over inventory.
- Physical Handover Verification (Delivery PIN): Proof-of-delivery relies on a cryptographically secured 4-digit PIN generated for the buyer. When the seller or courier inputs this PIN, the escrow contract executes atomically.
- Historical Commission Invariant (Fee Freezing): Commission percentages are frozen at the exact millisecond of order placement (
fee_snapshot), immunizing historical transactions from future platform fee changes.
sequenceDiagram
autonumber
actor Buyer
participant Storefront
participant API as Backend API
participant Paystack as Paystack Gateway
participant DB as Postgres (Supabase)
actor Vendor
Buyer->>Storefront: 1. Place Order (Cart items)
Storefront->>API: 2. POST /api/payments/intent (CheckoutPaymentIntent)
API->>DB: 3. reserve_checkout_payment() & Snapshot Frozen Fees
API->>Paystack: 4. POST /transaction/initialize (timeout 15s)
Paystack-->>API: 5. Return authorization_url & access_code
API->>DB: 6. complete_checkout_payment_dispatch() (State: ready)
API-->>Storefront: 7. Deliver Paystack Inline Checkout Modal
Buyer->>Paystack: 8. Authorize Card / USSD / Bank Transfer
Paystack-->>API: 9. Webhook charge.success (HMAC SHA-512)
API->>DB: 10. Update payment_status='paid', status='Processing'
DB->>DB: 11. Generate 4-digit Delivery PIN in order_verification
Note over DB,Vendor: Vendor notified to dispatch goods
Vendor->>Buyer: 12. Physical Delivery / Campus Meetup
Buyer-->>Vendor: 13. Shares 4-Digit Delivery PIN upon inspection
Vendor->>API: 14. POST /api/orders/:id/verify-delivery (delivery_code)
API->>DB: 15. Verify PIN & UPDATE status='Completed', payment_status='released'
DB->>DB: 16. Trigger trigger_on_order_released()
DB->>DB: 17. Execute process_order_fund_release() -> ledger_post()
Note over DB: Escrow unlocked -> Vendor Wallet Balance credited2. Comprehensive Order Finite State Machine (FSM)
The lifecycle of an order is strictly governed by PostgreSQL triggers (guard_order_payment_state) preventing illegal state skips.
stateDiagram-v2
[*] --> PaymentPending : Order Created (Cart Checkout)
PaymentPending --> Processing : Payment Verified (Webhook charge.success)
PaymentPending --> Cancelled : Payment Window Expired / Cancelled by Buyer
state Processing {
[*] --> AwaitingFulfillment
AwaitingFulfillment --> Shipped : Vendor Dispatches / Couriered
Shipped --> InTransit : Arrived at Campus Hub / Out for Delivery
}
Processing --> ReturnInitiated : Defect / Return Case Opened
Processing --> Disputed : Delivery Dispute Raised
InTransit --> DeliveredPendingRelease : Courier Handover Attempt
DeliveredPendingRelease --> Completed : Delivery PIN Verified
DeliveredPendingRelease --> Completed : Auto-Release Timer Expired (72h without dispute)
state ReturnInitiated {
[*] --> CaseReview
CaseReview --> PickupConfirmed : Courier Acknowledges Custody
PickupConfirmed --> Inspected : Vendor Verifies Restock Condition
Inspected --> Refunded : Atomic Return Approved & Executed
}
Disputed --> Completed : Arbiter Releases to Vendor
Disputed --> Refunded : Arbiter Approves Buyer Refund
Completed --> [*] : Funds Released to Vendor Balance
Refunded --> [*] : Funds Credited to Buyer Wallet / Original Card
Cancelled --> [*] : Inventory Restocked3. Checkout Payment Intent & Three-Phase Commit
Debelu prevents ghost orders, double-charging, and distributed race conditions through CheckoutPaymentIntent ([debelu-backend/src/services/CheckoutPaymentIntent.ts](file:///c:/Users/frank/OneDrive/Desktop/Chisom/Debelu/New%20Debelu%20Marketplace/debelu-backend/src/services/CheckoutPaymentIntent.ts)).
3.1 Strict Reference Specification
Payment references are deterministic UUIDv4 mappings: $$\text{Reference} = \text{"checkout-"} + \text{checkoutId.replace(/-/g, "")}$$ Matches regex: /^checkout-[a-f0-9]{32}$/
3.2 The Three-Phase Intent Protocol
- Reservation Phase (
reserve_checkout_payment):- Acquires an atomic lock on the order.
- Generates a cryptographic
claimToken(UUID). - Verifies emergency platform control
assertSubsystemAvailable('checkoutDisabled').
- Dispatch Phase (
begin_checkout_payment_dispatch):- Atomically transitions state to
dispatching. - Outbound HTTP call to Paystack API (
https://api.paystack.co/transaction/initialize) with a strict 15-second timeout. - Validates that Paystack's returned
authorization_urlresides on the HTTPS hostnamecheckout.paystack.com.
- Atomically transitions state to
- Commit or Uncertainty Isolation:
- Success (
complete_checkout_payment_dispatch): Recordsreadystate, access code, and URL. - Failure / Timeout (
mark_checkout_payment_uncertain): If the outbound request times out or network drops, the intent is flagged asuncertain. The system rejects subsequent payment attempts on that checkout until status is definitively verified via Paystack transaction check, preventing double-debits.
- Success (
4. The Frozen Fee Snapshot (fee_snapshot) Invariant
A primary enterprise vulnerability in multi-vendor marketplaces is ledger corruption through retroactively modified commission rates. Debelu eliminates this risk through immutable fee snapshots at checkout ([scripts/db-order-fee-snapshot-checks.mjs](file:///c:/Users/frank/OneDrive/Desktop/Chisom/Debelu/New%20Debelu%20Marketplace/scripts/db-order-fee-snapshot-checks.mjs)).
4.1 Snapshot Data Structure
At the moment create_order() executes, the database computes and freezes the exact calculation in orders.fee_snapshot (JSONB):
{
"configurationRevision": 4,
"globalRateBasisPoints": 500,
"platformFeeMinor": 6900,
"vendorNetMinor": 33100,
"discountMinor": 1000,
"netSubtotalMinor": 39000,
"lines": [
{
"productId": "301e0000-0000-4000-8000-000000000000",
"categoryId": "101e0000-0000-4000-8000-000000000000",
"approvedProposalId": "201e0000-0000-4000-8000-000000000000",
"rateBasisPoints": 1000,
"rateSource": "category_proposal",
"netMinor": 9000
}
]
}4.2 Mathematical Invariants
- Gross Order Total: $$\text{TotalMinor} = \text{PlatformFeeMinor} + \text{VendorNetMinor} + \text{DiscountMinor}$$
- Category Hierarchy Precedence:
- If a product belongs to a category with an executed proposal $\to$ Use
proposed_overridebasis points. - If uncategorized or proposal unexecuted $\to$ Fall back to
platform_settings.platform_fee_percent(global_unreviewed_category_override).
- If a product belongs to a category with an executed proposal $\to$ Use
- Coupon Line-Item Isolation: Targeted coupons apply strictly to eligible line items; fees on non-discounted line items remain invariant.
- Historical Isolation: When an administrator updates category commissions via a new proposal, previously placed orders release funds strictly based on their stored
fee_snapshot.
5. Delivery Handover & PIN Verification
5.1 PIN Generation & Secrecy
- At the moment
payment_statusshifts to'paid', a database trigger inserts a random 4-digit code ($0000 - 9999$) intopublic.order_verification(order_id, delivery_code). - Zero-Leak Protection: The PIN is visible only to the purchasing buyer inside their authenticated storefront order view. It is strictly excluded from vendor APIs, courier tracking payloads, and audit exports.
- Brute-Force Oracle Elimination: The API enforces exponential backoff after 3 invalid PIN attempts.
5.2 Atomic Release Trigger
When the buyer inspects the goods and provides the PIN:
- Vendor submits PIN via
/api/orders/:id/verify-delivery. - Database checks:sql
IF v_order.delivery_code = p_input_pin THEN UPDATE public.orders SET status = 'Completed', payment_status = 'released', updated_at = now() WHERE id = p_order_id; END IF; - PostgreSQL trigger
trigger_on_order_releasedactivates immediately:- Calls
process_order_fund_release(). - Invokes
ledger_post()to credit vendor pending wallet and debit escrow liabilities in a single ACID transaction.
- Calls
6. Atomic Return Cases & Reverse Logistics
When an order arrives defective or incorrect, Debelu initiates an Atomic Return Case governed by AtomicReturnCaseService and validated by [scripts/db-atomic-return-case-checks.mjs](file:///c:/Users/frank/OneDrive/Desktop/Chisom/Debelu/New%20Debelu%20Marketplace/scripts/db-atomic-return-case-checks.mjs).
sequenceDiagram
autonumber
actor Buyer
participant ReturnSvc as AtomicReturnCaseService
actor Courier as Campus Runner / Courier
actor Vendor
participant Ledger as Ledger & Refund Engine
Buyer->>ReturnSvc: 1. File Return Request (photo proof, reason)
ReturnSvc->>ReturnSvc: 2. Generate evidenceFingerprint (excluding PIN)
Note over ReturnSvc: Staff reviews return evidence
ReturnSvc->>ReturnSvc: 3. apply_atomic_return_case('approve') [Revision: 1]
ReturnSvc-->>Courier: 4. Dispatch Runner for Pickup
Courier->>ReturnSvc: 5. apply_atomic_return_case('confirm_pickup') [Revision: 2]
Courier->>Vendor: 6. Handover item to Vendor
Vendor->>ReturnSvc: 7. apply_atomic_return_case('confirm_inspection', restockEligible: true) [Revision: 3]
ReturnSvc->>Ledger: 8. Trigger ReviewedWalletRefundService
Ledger-->>Buyer: 9. Credit Buyer Wallet / Initiate Card Refund6.1 Sequential Evidence Integrity
- Action
confirm_inspectioncannot precedeconfirm_pickup(enforced via error40001). - Action
refundcannot be called until inspection is recorded. - Stale command replays (
replayed: true) return existing receipts without duplicating notifications or audit log records.
6.2 The evidenceFingerprint Shield
To prevent a malicious client from using return snapshots to brute-force a buyer's delivery PIN, evidenceFingerprint computes an SHA-256 hash over: $$\text{Fingerprint} = \text{SHA256}(\text{order_id} + \text{total} + \text{items} + \text{vendor_id} + \text{buyer_id})$$ The buyer's delivery_code is explicitly omitted from the hash input.
7. Edge Cases & Concurrency Mitigations
| Edge Case | Failure Mode | Mitigation Strategy |
|---|---|---|
| Duplicate Paystack Webhooks | Paystack retries charge.success 3+ times. | Deduplication table processed_webhook_events. Event is processed once; subsequent arrivals return HTTP 200 immediately. |
| Concurrent PIN Verification & Dispute | Vendor submits correct PIN while buyer files dispute. | PostgreSQL row-level lock (SELECT ... FOR UPDATE). First transaction to commit wins; second receives 40001 Serialization Failure. |
| Buyer Unresponsiveness | Goods delivered at campus station, but buyer fails to share PIN. | 72-hour automated countdown. After 72 hours with no dispute filed, auto-release worker triggers process_order_fund_release(). |
| Vendor Vacation / Ban Mid-Escrow | Vendor suspended for fraud while orders are in transit. | In-transit orders continue to delivery. Escrow funds unlock into a quarantined balance (ReviewedPayoutBatchService hold). |