The payments and ledger service for Northwind Bank (fictional). Spring Boot 3 + JPA.
Accounts hold balances; transfers move money between them. This service is the source of truth for customer balances, so atomicity and correctness under concurrency are non-negotiable — a lost update or a torn transfer is real money gone missing.
controller/ REST endpoints (accounts, transfers)
service/ business logic — transfers, interest, statements
repository/ Spring Data JPA repositories
model/ JPA entities (Account, Transaction)
| Area | Files |
|---|---|
| Transfers | service/TransferService.java |
| Accounts | service/AccountService.java, controller/AccountController.java |
| Statements / batch | service/StatementService.java |
| Entities | model/Account.java, model/Transaction.java |
mvn spring-boot:runH2 in-memory DB (console at /h2-console). The Hikari pool is deliberately
small (5) so concurrency and pool-exhaustion issues surface under load.
- Money is
BigDecimal(scale 4) — neverdouble. Floating point loses cents. - A transfer must be atomic: debit and credit succeed together or not at all.
- Concurrent transfers on the same account must not lose updates.
- Statements are exported nightly to disk by a batch job.