Requirements for the Digital Wallet
Functional Requirements
Let's define what our Digital Wallet system needs to do. Each requirement is numbered and specific enough to drive at least one class, method, or design decision.
-
Create Wallet: The system shall allow creating a wallet for a registered user. Each user has exactly one wallet, and each wallet belongs to exactly one user.
-
Deposit Money: A user shall be able to deposit money into their wallet from a linked payment method (bank account or credit card). The wallet balance increases by the deposited amount.
-
Withdraw Money: A user shall be able to withdraw money from their wallet to a linked payment method. The withdrawal shall fail if the wallet has insufficient funds — balances must never go negative.
-
Transfer Money (P2P): A user shall be able to transfer money from their wallet to another user's wallet. The sender's balance decreases and the receiver's balance increases by the same amount. This operation must be atomic — either both sides succeed, or neither does.
-
Check Balance: A user shall be able to query their current wallet balance at any time.
-
Transaction History: Every wallet operation (deposit, withdrawal, transfer) shall be recorded as a Transaction with a unique ID, timestamp, type, amount, status, and involved wallet IDs. Users can retrieve their full transaction history.
-
Multiple Payment Methods: A user shall be able to link multiple payment methods (bank accounts and/or credit cards) to their account. Each deposit or withdrawal specifies which payment method to use.
-
Idempotency: Every wallet operation shall accept a client-generated idempotency key. If the system receives a request with a previously-processed key, it shall return the cached result without re-executing the operation. This prevents duplicate charges on network retries.
-
Transaction Notifications: When a transaction completes, all interested observers (e.g., notification service) shall be notified with the transaction details.
Non-Functional Requirements
Beyond correctness, the system must satisfy:
-
Balance Consistency: At no point shall a wallet have a negative balance. The check-and-debit operation must be atomic to prevent Time-of-Check-to-Time-of-Use (TOCTOU) race conditions. In P2P transfers, the total money in the system must be conserved — the sender's loss equals the receiver's gain.
-
Thread Safety: Multiple concurrent operations on the same wallet (or between wallets) must produce correct results. Two simultaneous withdrawals from the same wallet must not overdraft it. Two simultaneous transfers in opposite directions (A-to-B and B-to-A) must not deadlock.
-
Extensibility: Adding new transaction types (e.g., scheduled payments, recurring transfers, refunds) must not require modifying existing transaction logic. The Command pattern enables this — new commands extend the base without altering existing ones.
-
Testability: Each component (Wallet, Transaction, Command, Service) must be testable in isolation. Dependencies should be injected, not hard-coded.
Scope Clarification
In Scope:
- Wallet creation, deposit, withdrawal, and P2P transfer operations
- Transaction recording with unique IDs, timestamps, and status tracking
- Payment method abstraction (bank account and credit card)
- Idempotency key mechanism for duplicate request prevention
- Observer-based notification on transaction completion
- Thread-safe balance operations and atomic transfers
- Command-based transaction architecture
Out of Scope:
- Database persistence — we model in-memory objects, not SQL schemas or ORM mappings
- REST API layer — no HTTP endpoints, request/response DTOs, or authentication middleware
- Currency handling — we use a single currency (represented as a floating-point amount; production systems would use fixed-point decimal)
- Fraud detection — no anomaly detection, velocity checks, or risk scoring
- Regulatory compliance — no KYC verification, AML screening, or PCI DSS considerations
- Distributed systems — no saga pattern, two-phase commit, or event sourcing across services
Interview Tip
In a 45-minute LLD interview, you won't have time to design all of this. Spend the first 3-5 minutes clarifying scope with questions like:
- "Should the system support multiple currencies, or a single currency?" — This dramatically changes the Transaction model.
- "Do we need to support refunds or chargebacks?" — This affects whether transactions need a REVERSED status and impacts the Command pattern design.
- "Is thread safety in scope, or should I focus on single-threaded correctness first?" — This lets you manage time. Design single-threaded first, then layer in concurrency.
- "How should we handle failed transfers — automatic retry, or manual resolution?" — This determines whether you need a PENDING → FAILED → RETRYING state machine.
These questions signal to the interviewer that you think about edge cases and system boundaries before jumping into class diagrams. A well-scoped problem is half-solved.