Event Sourcing & CQRS · Capstone
Capstone: Event-Sourced Wallet Ledger
Design an event-sourced digital wallet with audit-grade history.
Scenario
A fintech offers wallets: top-ups, transfers between users, card payments, refunds and holds. Regulators require complete history and point-in-time balances. The mobile app shows balances and transaction lists that must reflect a user's own actions immediately.
Requirements
- No negative balances (except allowed overdraft)
- Transfers between wallets are consistent
- Point-in-time balances
- GDPR erasure for closed accounts
Constraints
- Peak 2,000 transfers/s
- Team runs PostgreSQL today
Deliverables
- Model aggregates, events and the transfer flow.
- Design storage, projections and read-your-writes.
- Handle GDPR erasure and auditing.
Draft each deliverable below before revealing the model answer and rubric.
Further reading: Martin Fowler: Event Sourcing
Deliverables
Model aggregates, events and the transfer flow.
Model answer
Aggregate: Wallet (stream wallet-{id}); events: WalletOpened, FundsDeposited, FundsWithdrawn, FundsHeld, HoldReleased, HoldCaptured, TransferOut, TransferIn, WalletClosed.
Transfer = process manager: debit source (TransferOut with transfer_id; enforces balance) → credit destination (TransferIn, idempotent by transfer_id) → on failure compensate (TransferReversed). Each command idempotent by transfer_id.
Rubric
Strong answers keep aggregates small (one wallet), handle cross-wallet consistency via a process manager with idempotency, and name intent-revealing events.
Design storage, projections and read-your-writes.
Model answer
Postgres event table with UNIQUE(stream_id, stream_version); global log with commit-safe ordering; projections: balances (per wallet), transactions list, regulatory reports; checkpoints in same tx. Commands return position; app queries min_position for own data; snapshots every 1,000 events per wallet.
Rubric
Look for concurrency control, checkpointing and an explicit read-your-writes strategy.
Handle GDPR erasure and auditing.
Model answer
PII (names, emails) not in events — referenced by customer_id in a separate deletable store; free-text fields encrypted per customer (crypto-shredding). Event metadata: actor, correlation, causation, device. Point-in-time balance via replay or periodic balance snapshots per day.
Rubric
Strong answers keep PII out of the immutable log and keep audit metadata rich.
Open in the app to mark lessons complete, take notes and track your progress.