Back to Projects
PROJECT CASE STUDY / DOUBLE LEDGER BANKING SYSTEM

Double Ledger Banking System

Transaction-Safe Banking Backend

A banking backend designed around double-entry accounting, transactional correctness, concurrency control, idempotency and secure API design.

Test access

Credentials for authorized evaluation.

These are non-production test accounts. Customer registration and account opening still follow the bank onboarding workflow.

TEST USERkumar@gmail.comPasswd: Kumar@123
TEST USERgaurav@gmail.comPasswd: Gaurav@123
LIVE SITEOpen live site
STACKJavaSpring BootSpring SecurityPostgreSQLReactDockerGitHub ActionsMaven
What is it?

Double Ledger models money movement as a financial operation rather than a simple balance update. A transfer records a debit, a credit and the transaction that binds both sides together.

The problem

A CRUD banking application can appear correct in a happy-path demo while remaining unsafe under retries, concurrent requests or partial failure. This project focuses on correctness, consistency, concurrency, security, idempotency and auditability.

Technical deep dive

How the system holds together.

Engineering Challenges

Transfers must preserve the relationship between sender and receiver inside one database transaction. Concurrent requests require protected account updates, while deterministic ordering reduces deadlock risk when more than one account is locked.

  • Transactional correctness keeps debit and credit together.
  • Pessimistic locking protects concurrent account updates.
  • Idempotency makes retried transfer requests safe.
  • JWT authentication, refresh-token rotation and RBAC protect the API.
  • Audit logs make important operations traceable.

Double-Entry Ledger

Every financial transaction produces a DEBIT for the sender and a CREDIT for the receiver. Both entries belong to the same transaction, so the movement can be reconciled and traced instead of relying on an unexplained balance mutation.

  • Account A: -₹500
  • Account B: +₹500

Concurrency Control

Multiple requests can arrive at the same time. Account balances cannot be safely updated without concurrency control. Row-level locks protect shared account state inside a database transaction; deterministic ordering reduces deadlock risk, but does not itself solve race conditions.

Fund Transfer Flow

The transfer path validates the request, authenticates the caller, checks idempotency, loads accounts, acquires locks, validates balance, ownership and status, creates the transaction and ledger entries, updates account state, and commits. Validation, lock or persistence failures can roll the transaction back.

Idempotency

Payment-like requests may be retried when a client times out. A clientRequestId lets the API distinguish an existing operation from a new one: an existing result is returned, while a new request is processed and its result saved before responding.

Security

The documented security design uses Spring Security, JWT access tokens, refresh-token rotation, BCrypt password hashing and role-based access control. Authorization belongs at the protected API boundary as well as in the application flow.

Customer Onboarding & Test Access

The banking system does not provide open public customer signup. An authorized Admin, Manager or Staff user must register the customer with the bank first; an account can only be opened after that customer registration exists. The credentials below are non-production test accounts for authorized evaluation.

Failure Scenarios

Insufficient balance, invalid accounts, unauthorized access, duplicate requests, validation failures, concurrent updates and transaction failures are treated as explicit failure paths. Database rollback prevents a partial transfer from becoming visible.

REST API Design

The API is organized around authentication, accounts, transfers, transactions, users, administration and audit concerns. Exact endpoint names are intentionally omitted here because this repository contains the portfolio, not the backend source of truth.

Diagrams

System surfaces.

ARCHITECTURESystem Architecture
System Architecture
LEDGERDouble-Entry Ledger
Double-Entry Ledger
CONCURRENCYConcurrency and Locking
Concurrency and Locking
TRANSACTIONFund Transfer Flow
Fund Transfer Flow
IDEMPOTENCYIdempotency
Idempotency
AUTHENTICATIONAuthentication and RBAC
Authentication and RBAC
DATABASEDatabase Design
Database Design
DEPLOYMENTDeployment
Deployment
Engineering decisions

Why I made these decisions.

Why PostgreSQL?

Relational transactions and constraints fit financial state that must remain consistent.

Why Spring Boot?

It provides a focused foundation for REST APIs, dependency injection, security and data access.

Why pessimistic locking?

Account updates need protected shared state when concurrent transfers target the same rows.

Why deterministic ordering?

Acquiring multiple account locks in a consistent order reduces deadlock risk.

Why double-entry accounting?

A debit and credit provide a traceable, balanced representation of money movement.

Why idempotency?

Retries should return the existing result instead of creating a second operation.

Why JWT and refresh rotation?

Short-lived API access and replaceable refresh credentials support protected sessions.

Why RBAC?

Authorization rules can express which authenticated users may perform protected operations.

Testing

JUnit, Mockito, Postman and Swagger / OpenAPI are the documented testing and API tools. The testing focus is business logic, validation, authentication and authorization, transfer behavior, failure scenarios, idempotency and concurrency-sensitive logic where applicable. Because public signup is disabled, live testing requires authorized Admin, Manager or Staff credentials to register a customer before opening an account.

Deployment & DevOps

The application is deployed with Vercel for the frontend, Render for the Spring Boot backend, and Neon PostgreSQL for the database. GitHub Actions provides the CI/CD pipeline, with Docker included in the delivery workflow.

What I learned

Lessons that travel.

  • Database transactions are part of business correctness.
  • Concurrency problems cannot be solved only at the API layer.
  • Idempotency matters for retryable operations.
  • Security requires both authentication and authorization.
  • Financial operations require stronger consistency guarantees than ordinary CRUD operations.