Skip to main content

Wallet

The wallet domain is the balance and redemption layer for consumer points.

Current Data Model​

  • wallets stores the fast-read balance snapshot.
  • wallet_ledger stores the append-only audit trail.
  • reward_events links transactions to wallet changes.
  • redemption_codes stores temporary codes for in-store redemption.

Credit Path​

apps/api/src/services/wallet-service.ts performs wallet credit in one transaction:

  1. Upsert the wallet row for (tenantId, userId).
  2. Append a credit entry to wallet_ledger.
  3. Update the wallet snapshot balance.
  4. Insert the linked reward_events row.

Redemption Path​

Consumer redemption happens in two steps:

  • preview: calculates the discount and new balance
  • confirm: locks the wallet row, writes a debit ledger entry, and issues a redemption code

The POS operator later validates the redemption code through /api/v1/pos/redemptions/*.

Invariants​

  • ledger rows are append-only
  • points are always stored as positive integers
  • the snapshot balance is a read optimization, not the source of truth
  • redemption uses FOR UPDATE to avoid concurrent overspend
Written byDhruv Doshi