Problem statement
Design the class model and public APIs for the core of a personal-banking account system: the object graph that holds accounts, moves money in and out, applies the right interest, and keeps an auditable record of every transaction. This is the in-process domain kernel a teller UI, an ATM, or a REST layer would drive — not those front ends themselves.
Operating context. A single retail branch runs one in-memory service. Each customer holds one or more accounts of different kinds — a checking account that permits an overdraft down to a per-account limit, and a savings account that forbids overdraft but accrues interest. Money enters via deposit and leaves via withdraw; a transfer is a withdraw from one account and a deposit into another. Interest rules differ by account kind and may change (a promo rate next quarter), so the accrual policy must be swappable without touching the account classes. Several tellers and ATMs may hit the same account concurrently, so no interleaving of deposits and withdrawals may corrupt a balance or let a withdrawal slip past the overdraft rule.
Out of scope. Persistence / database layer (assume in-memory for v1), authentication and authorization, the REST/RPC surface, currency conversion and multi-currency math (assume one currency), fraud detection, and the customer-onboarding workflow.
What to produce. The class hierarchy (Account and its subtypes, Money, Transaction, the interest-policy seam, and any account registry/service), the public API each class exposes, and the state transitions of an account (open -> active -> frozen -> closed) and of a transaction. Be explicit about: how each account kind enforces its own withdrawal rule polymorphically (overdraft for checking, no-overdraft for savings), how the interest strategy is pluggable so a new rate or account kind is a localized change, how every posting appends an immutable transaction-history entry, and how concurrent deposits and withdrawals on one account stay correct.
Functional requirements
- Deposit a positive amount into an account, updating the balance and appending a transaction-history entry.
- Withdraw an amount, enforcing the account kind's rule: checking may go negative down to its overdraft limit, savings may never go below zero.
- Transfer between two accounts as a withdraw from the source and a deposit into the destination that both succeed or both fail.
- Accrue interest on an account by applying its current interest policy, posting the earned amount as a transaction.
- Return an account's transaction history in chronological order, optionally filtered by a time range.
- Reject invalid operations (non-positive amount, overdraft breach, operation on a closed or frozen account) with a distinct error per case.
Non-functional requirements
- A balance never violates its account kind's floor: savings stays >= 0 and checking stays >= its overdraft limit after every applied operation.
- Concurrent deposits and withdrawals on the same account are serialized so no lost update or interleaving corrupts the balance.
- Each account kind owns its own withdrawal rule; adding a new account kind must not edit existing account classes (open/closed).
- The interest policy is pluggable via a strategy seam, so swapping a rate or rule must not touch deposit/withdraw code paths.
- The transaction log is append-only and immutable: a posted entry is never mutated or deleted, giving a total audit trail.
- The core is unit-testable with no database and no wall clock: the clock is injected so interest and timestamps are deterministic.
Topics
- System Design LLD
- Oop Solid
- Patterns Strategy
- Concurrency Locks
- Statemachine