Wallet Architecture Overview
System Components
Core Services
Wallet Account Service
Manages wallet lifecycle and balance operations:
- Account creation and activation
- Balance queries
- Transaction posting
- Balance reconciliation
Auto Top-Up Worker
BullMQ worker for scheduled and threshold-based top-ups:
- Monitors balance thresholds
- Triggers payment collection
- Handles failure retry logic
- Emits outbox events for notifications
Pass Provider Service
Apple Wallet and Google Wallet integration:
- Pass template management
- Pass generation and signing
- Push updates for balance changes
- Pass analytics tracking
API Layers
Portal API
Member-facing endpoints (/portal/wallet/*):
GET /balance- Current balancePOST /top-up- Initiate manual top-upGET /transactions- Transaction historyPOST /auto-top-up- Configure auto top-upGET /pass- Generate digital card
Admin API
Staff-facing endpoints (/admin/wallet/*):
GET /accounts- List all wallets (with filtering)GET /analytics- Cohort analyticsPOST /credit- Manual credit/debitPOST /reconcile- Trigger reconciliation
Webhook API
External integration endpoints:
- Payment processor callbacks
- Pass event webhooks
- Subscription lifecycle events
Data Model
Primary Entities
model WalletAccount {
id String @id @default(uuid())
memberId String
tenantId String
currency String @default("ZAR")
balance Int @default(0) // cents
status WalletStatus
createdAt DateTime
updatedAt DateTime
transactions WalletTransaction[]
autoTopUp AutoTopUpConfig?
passes WalletPass[]
}
model WalletTransaction {
id String @id @default(uuid())
walletId String
type TransactionType
amount Int // cents (positive = credit)
balanceAfter Int
reference String?
description String?
merchantCode String?
postedAt DateTime
}
model AutoTopUpConfig {
id String @id @default(uuid())
walletId String @unique
enabled Boolean @default(false)
type AutoTopUpType // THRESHOLD, SCHEDULED
threshold Int? // cents
amount Int // cents
schedule String? // cron expression
mandateRef String? // stored payment method
}
Event System
Wallet uses the outbox pattern for reliable event publishing:
Transaction Posted
↓
Insert to wallet_outbox
↓
Outbox Poller claims entry
↓
Process event (notifications, pass updates)
↓
Mark entry complete
Outbox entry types:
transaction.posted- New transaction recordedstatus_changed- Wallet status updatedauto_topup.scheduled- Auto top-up scheduledauto_topup.failed- Auto top-up charge failed
Integration Points
Payment System
- Top-up initiation → Checkout session creation
- Webhook processing → Transaction posting
- Mandate storage → Auto top-up execution
Notification System
- Outbox events → Notification handlers
- Handler → Channel resolution (email, WhatsApp, SMS, push)
- Preference gating → Final delivery
Pass Providers
- Apple Wallet: PKPass generation, APNS push
- Google Wallet: Google Pay API integration
- Balance sync: Periodic and event-driven updates
Security Considerations
Access Control
- Portal endpoints: Member authentication + ownership check
- Admin endpoints: Staff authentication + permission check
- Webhook endpoints: Signature verification
Data Protection
- All amounts stored in cents (integers)
- Transaction history immutable
- Audit trail for admin operations
- PCI compliance for payment references (no raw card data)
Scaling Considerations
Performance
- Balance queries cached with short TTL
- Transaction history paginated
- Analytics queries run on read replicas
Reliability
- Outbox pattern ensures at-least-once delivery
- Idempotent transaction posting
- Distributed locks for auto top-up execution