Overview
I’m building a production-style banking core focused on correctness and auditability. The system models customers, accounts, and a
double-entry ledger that records every money movement as balanced debits and credits. Transfers are processed
transactionally with idempotency keys to prevent duplicates, and all changes are traceable via immutable audit logs.
Goals
- Guarantee financial correctness with a double-entry ledger and ACID transactions.
- Expose a clean, versioned REST API that client apps can consume.
- Provide auditability and reconciliation reports for operations.
My Role
- Domain modeling (accounts, ledger entries, transfers, statements).
- Spring Boot services, validation, and error handling.
- Security (JWT), migrations (Flyway), tests (JUnit + Testcontainers), and Dockerization.
Architecture
- Services:
account-service (open/close/list), transfer-service (initiate/commit), reporting-service (balances/statements).
- Ledger: Double-entry model: each transfer posts two
LedgerEntry rows (debit/credit) that must balance to zero.
- Persistence: PostgreSQL, JPA/Hibernate; Flyway for schema migrations; optimistic locking on balances.
- Security: Spring Security + JWT (roles: Customer, Operator, Admin); request idempotency via
Idempotency-Key header.
- APIs: REST with OpenAPI/Swagger; example endpoints:
POST /api/accounts, POST /api/transfers, GET /api/accounts/{id}/balance, GET /api/statements?month=....
- Messaging (optional): Kafka events (TransferCreated, LedgerPosted) to drive async notifications or downstream analytics.
- Deployment: Docker Compose (app + Postgres + Kafka optional); profiles for
dev and prod.
Highlights
Double-Entry Correctness
All transfers post balanced debit/credit entries; integrity enforced by constraints and service-level invariants.
Idempotent Transfers
Clients can safely retry requests; duplicate transfer submissions won’t double charge.
Operational Reporting
Daily balance snapshots and monthly statements generated from ledger entries — no derived side effects.
What I Learned
- Designing financial domains with clear invariants and isolation levels that avoid race conditions.
- How to structure Spring apps with controllers → services → repositories and keep business logic testable.
- Using Testcontainers to run integration tests against a real Postgres instance in CI.
Next Steps
- Outgoing webhooks and email notifications for posted transfers.
- Limits & fraud rules (velocity checks, daily caps, blacklist/whitelist).
- Batch reconciliation job and downloadable PDF statements.