Skip to content

About

A Spring Boot and React banking architecture implementing a double-entry ledger, idempotent UPI transaction processing, and deterministic pessimistic locking.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

29 Commits

Folders and files

Repository files navigation

🏦 Double Ledger & Banking System

Full-stack banking platform built with Spring Boot and React, focused on transaction correctness, double-entry accounting, concurrency safety, idempotent payments, security, and auditability.

Java Spring Boot PostgreSQL Spring Security JWT TypeScript React OpenAPI Maven

Live Demo


πŸ“Œ Contents


✨ What this project is

Double Ledger is a full-stack banking system built with Java 21, Spring Boot, Spring Security, PostgreSQL, React, and TypeScript.

The system models financial operations using an immutable double-entry ledger rather than treating an account balance as the primary source of truth.

It includes:

  • Double-entry financial ledger
  • Transaction processing
  • Idempotent UPI payments
  • JWT authentication
  • Refresh-token rotation
  • Role-based access control
  • Sender ownership validation
  • Pessimistic database locking
  • Deterministic account lock ordering
  • KYC and compliance checks
  • Audit logging
  • Session management
  • Security access logs
  • Notifications
  • Debit cards
  • Credit cards and credit plans
  • Loans and EMI schedules
  • QR code generation
  • Webhook subscriptions
  • Server-Sent Events for card events
  • CSV/PDF account statements
  • React role-based dashboards

The project is intentionally designed around backend concerns such as correctness, consistency, concurrency, security, and traceability.


🎯 Why this system matters

Financial systems cannot rely on simple balance updates such as:

balance = balance - amount

because concurrent requests, retries, partial failures, and duplicate requests can produce inconsistent results.

This system instead separates the concepts of:

Transaction
    ↓
Ledger Entries
    ↓
Derived Account Balance

For every successful transfer:

Alice β†’ Bob β‚Ή5,000

Alice account
    DEBIT   β‚Ή5,000

Bob account
    CREDIT  β‚Ή5,000

The implementation also protects money movement using:

  • Database transactions
  • Pessimistic locking
  • Deterministic lock ordering
  • Idempotency keys
  • Sender ownership validation
  • KYC validation
  • Append-oriented ledger entries
  • Unique database constraints
  • Audit trails

🧠 Core Engineering Problems

The project focuses on solving several problems commonly found in transactional backend systems.

1. Financial consistency

Every transfer produces balanced debit and credit ledger entries.

2. Duplicate requests

UPI payments use persisted idempotency state so retrying the same request does not create another payment.

3. Concurrent transfers

Account rows are protected using pessimistic locking.

4. Deadlock prevention

When two accounts need to be locked, they are locked in deterministic ascending ID order.

5. Authorization beyond authentication

Knowing an account number or UPI ID is not enough.

The authenticated user must actually own the sender account.

6. Auditability

Financial and security-related operations are recorded through audit and access logs.

7. Token security

Access tokens are short-lived and refresh tokens are rotated and stored in hashed form.


πŸ—ΊοΈ Engineering Architecture & Design

The following diagrams explain the main architectural and backend design decisions of the system.


1. System Architecture

double-ledger-architecture

The backend separates API handling, business logic, persistence, security, and financial transaction processing.


2. Authentication & RBAC

double-ledger-authentication-jwt-rbac

Authentication is implemented using Spring Security and JWT. Authorization is enforced at the endpoint/service boundary using method-level security.


3. Transaction Processing

double-ledger-transaction-flow

The financial operation is executed inside a transactional boundary so the transaction state and ledger entries remain consistent.


4. Concurrency Control

double-ledger-concurrency-locking

Concurrent transfers can attempt to update the same accounts at the same time. Both transactions therefore acquire locks in the same order.


5. Idempotent Payments

double-ledger-idempotency-flow

If the same idempotency key is submitted again, the existing payment state is checked instead of blindly creating another financial operation.

This protects against duplicate submissions and retry scenarios.


6. Double-Entry Ledger

double-ledger-ledger

Every successful money movement creates exactly two ledger entries.

Both entries share the same transaction reference.

This allows the system to maintain a complete financial trail and derive account balances from ledger activity.


7. Database Design

double-ledger-database-erd

The PostgreSQL schema models the banking domain across users, customers, accounts, transactions, payments, cards, loans, security, and auditing.

8. Deployment Architecture

double-ledger-deployment

The application is structured so the major components can be deployed independently:

The frontend communicates with the backend through REST APIs, while the backend manages persistence and financial business logic.


🧰 Tech Stack

Backend

Technology Version Purpose
Java 21 Backend language
Spring Boot 3.5.10 Application framework
Spring Security 6.x Authentication & authorization
Spring Data JPA Bundled Persistence layer
Hibernate 6.6.x JPA provider
PostgreSQL 15+ Primary database
JJWT 0.12.6 JWT generation & validation
MapStruct 1.6.3 DTO mapping
SpringDoc OpenAPI 2.7.0 API documentation
Spring Actuator Bundled Health & metrics
Spring Mail Bundled Password reset emails
Spring Cache / Redis Optional Caching
OpenPDF 1.3.30 PDF statement generation
ZXing 3.5.3 QR code generation
Lombok Bundled Boilerplate reduction
Jakarta Validation Bundled Request validation

Frontend

Technology Purpose
React 18 UI framework
TypeScript Type-safe frontend development
Vite Build tool and development server
Tailwind CSS Styling
shadcn/ui UI components
Radix UI Accessible primitives
Recharts Charts and analytics
React Router v6 Client-side routing
Lucide React Icons

πŸš€ Quick Start

Prerequisites

Install:

  • Java 21
  • PostgreSQL 15+
  • Node.js 18+
  • npm
  • Git

1. Clone the repository

git clone <your-repository-url>
cd <your-repository>

2. Configure PostgreSQL

Create a PostgreSQL database and configure the credentials in:

src/main/resources/application.yml

Example:

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/double_ledger
    username: postgres
    password: your_password

Use your actual database configuration.


3. Start the Spring Boot backend

Windows

.\mvnw.cmd spring-boot:run

macOS / Linux

./mvnw spring-boot:run

Backend:

http://localhost:8080

4. Start the React frontend

cd bank-frontend
npm install

Create:

bank-frontend/.env.local

Add:

VITE_API_BASE_URL=http://localhost:8080
VITE_ENABLE_AUDIT=true
VITE_ENABLE_SECURITY=true

Then:

npm run dev

Frontend:

http://localhost:5173

Depending on the Vite configuration, the application may also use port 8081.


5. Swagger / OpenAPI

Swagger UI:

http://localhost:8080/swagger-ui.html

OpenAPI JSON:

http://localhost:8080/v3/api-docs

OpenAPI YAML:

swagger-documentation/openapi.yaml

πŸ‘₯ Roles & Access Control

The system supports five roles.

Role Description
ROLE_ADMIN Full system access
ROLE_MANAGER Banking, customer, account, transaction and UPI management
ROLE_CUSTOMER_MANAGER Customer/account management and compliance operations
ROLE_AUDITOR Read-only financial and audit access
ROLE_USER Own accounts, transactions and UPI payments

Authorization is enforced using Spring Security method-level security.

Example:

@PreAuthorize("hasRole('ADMIN')")

or:

@PreAuthorize("hasAnyRole('ADMIN', 'MANAGER')")

πŸ“š API Reference

The application exposes REST APIs for authentication, banking, accounts, transactions, payments, cards, loans, auditing, security, and dashboard operations.


1. Authentication Module β€” /api/auth

Method Endpoint Auth Description
POST /api/auth/login Public Authenticate and receive access + refresh tokens
POST /api/auth/forgot-password Public Request password reset
POST /api/auth/reset-password Public Reset password using reset token
GET /api/auth/me Authenticated Return current user profile and banking metrics
POST /api/auth/change-password Authenticated Change current password
POST /api/auth/refresh Public Rotate refresh token
POST /api/auth/logout Authenticated Logout and terminate active session

Login response

{
  "accessToken": "eyJ...",
  "refreshToken": "eyJ...",
  "tokenType": "Bearer",
  "userId": 1,
  "username": "admin",
  "email": "admin@bank.com",
  "fullName": "Admin User",
  "roles": ["ROLE_ADMIN"],
  "expiresAt": "2026-05-11T19:38:00",
  "passwordChangeRequired": false
}

Enriched /api/auth/me

{
  "id": 1,
  "username": "alice",
  "email": "alice@bank.com",
  "primaryRole": "ROLE_USER",
  "customerId": "SBI_abc123",
  "kycStatus": "ACTIVE",
  "customerStatus": "ACTIVE",
  "accountCount": 2,
  "totalBalance": 45000.00,
  "upiProfileCount": 1,
  "transactionCount": 12
}

Additional fields are returned based on the authenticated user's role.


2. Bank Management β€” /bank

Method Endpoint Roles Description
GET /bank ADMIN, MANAGER, AUDITOR List banks
GET /bank/{id} ADMIN, MANAGER, AUDITOR Get bank
GET /bank/upi/{upiId} ADMIN, MANAGER, AUDITOR, USER Find bank by UPI ID
POST /bank/create ADMIN Create bank
PATCH /bank/{id} ADMIN Update bank
DELETE /bank/{id} ADMIN Delete bank

Bank fields include:

bankName
branch
ifscCode
city
state
branchAddress

3. Customer Management β€” /customer

Method Endpoint Roles Description
GET /customer ADMIN, MANAGER, CUSTOMER_MANAGER, AUDITOR List customers
GET /customer/paginated ADMIN, MANAGER, CUSTOMER_MANAGER, AUDITOR Paginated customers
GET /customer/me Authenticated Current customer
GET /customer/email/{email} ADMIN, MANAGER, CUSTOMER_MANAGER, AUDITOR Find customer
GET /customer/search ADMIN, MANAGER, CUSTOMER_MANAGER Search customers
GET /customer/bank ADMIN, MANAGER, CUSTOMER_MANAGER Customers by bank
PATCH /customer/update ADMIN, CUSTOMER_MANAGER Update customer
DELETE /customer/delete ADMIN Delete customer

Customer data includes:

fullName
email
phoneNumber
address
age
kycStatus
customerStatus

4. Account Management β€” /account

Method Endpoint Roles Description
GET /account ADMIN, MANAGER, CUSTOMER_MANAGER, AUDITOR List accounts
GET /account/paginated ADMIN, MANAGER, CUSTOMER_MANAGER, AUDITOR Paginated accounts
GET /account/my Authenticated Own accounts
GET /account/{id} ADMIN, MANAGER, CUSTOMER_MANAGER, AUDITOR Account details
GET /account/name/{bankName} ADMIN, MANAGER, CUSTOMER_MANAGER, AUDITOR Accounts by bank
GET /account/email/{email} ADMIN, MANAGER, CUSTOMER_MANAGER Accounts by email
GET /account/validate-receiver ADMIN, MANAGER, USER Validate receiver
GET /account/lookup-by-number ADMIN, MANAGER, CUSTOMER_MANAGER, AUDITOR Lookup account
GET /account/{accountNumber}/balance ADMIN, MANAGER, AUDITOR, USER Ledger-derived balance
POST /account/{bankName} ADMIN, MANAGER Create account
PATCH /account/{accNumber} ADMIN, MANAGER Update account
PATCH /account/{accNumber}/compliance ADMIN, MANAGER, CUSTOMER_MANAGER Update compliance
DELETE /account/{accNumber} ADMIN Delete account

Account numbers are generated automatically.

Example:

ACC_SBI_xxxxx

5. Transaction Processing β€” /transaction

Method Endpoint Roles Description
GET /transaction/all ADMIN, MANAGER, AUDITOR All transactions
GET /transaction/all/paginated ADMIN, MANAGER, AUDITOR Paginated transactions
GET /transaction ADMIN, MANAGER, AUDITOR, USER Filter transactions
GET /transaction/my Authenticated Own transactions
GET /transaction/customer/{customerId} ADMIN, MANAGER, AUDITOR, CUSTOMER_MANAGER Customer transactions
GET /transaction/accounts/{id}/balance ADMIN, MANAGER, AUDITOR, USER Ledger-derived balance
POST /transaction USER Transfer money
POST /transaction/{transactionId}/reverse ADMIN, MANAGER Reverse transaction
GET /transaction/{transactionId}/receipt ADMIN, MANAGER, AUDITOR, USER Transaction receipt

Transaction states

INITIATED
    ↓
PROCESSING
    ↓
COMPLETED

or:

INITIATED
    ↓
PROCESSING
    ↓
FAILED

Transfer request

{
  "senderAccount": "ACC_SBI_xxxxx",
  "receiverAccount": "ACC_HDFC_xxxxx",
  "amount": 5000.00
}

The sender must own the source account.


6. UPI Payment System β€” /upi

Method Endpoint Roles Description
POST /upi/register ADMIN, MANAGER, USER Register UPI profile
GET /upi ADMIN, MANAGER, AUDITOR, USER List UPI profiles
GET /upi/paginated ADMIN, MANAGER, AUDITOR, USER Paginated profiles
GET /upi/my Authenticated Own UPI profiles
GET /upi/{upiId} ADMIN, MANAGER, AUDITOR, USER Get UPI profile
GET /upi/account/{accountNumber} ADMIN, MANAGER, USER Account UPI profiles
PATCH /upi/{upiId}/status ADMIN, MANAGER, USER Update status
PUT /upi/{upiId}/toggle ADMIN, MANAGER, USER Enable/disable
DELETE /upi/{upiId} ADMIN Soft delete
POST /upi/pay USER Execute UPI payment

UPI payment request

{
  "fromUpi": "alice@sbi",
  "toUpi": "bob@hdfc",
  "amount": 1000.00,
  "idempotencyKey": "unique-client-key-123"
}

7. QR Code Generation β€” /qr

Method Endpoint Roles Description
GET /qr/generate ADMIN, MANAGER, USER Generate UPI payment QR
GET /qr/account ADMIN, MANAGER, USER Generate account QR

QR codes are generated using ZXing.

UPI QR format:

upi://pay?pa=...&pn=...&am=...&cu=INR

The API returns:

image/png

8. Audit Logging β€” /audit

Access is restricted to:

ROLE_ADMIN
ROLE_AUDITOR
Method Endpoint Description
GET /audit/logs Paginated audit log query
GET /audit/logs/{id} Get individual audit entry

Supported filters include:

startDate
endDate
action
userId
resource
page
size

Audit actions:

VIEW
CREATE
UPDATE
DELETE

Additional explicit security events include:

LOGIN
LOGOUT
PASSWORD_RESET_REQUEST
PASSWORD_RESET
PASSWORD_CHANGE

The AuditLoggingInterceptor automatically captures eligible HTTP activity.

Excluded paths include:

/audit
/security
/api/auth
/swagger-ui
/v3/api-docs
/actuator

9. Security & Session Management β€” /security

All endpoints are restricted to:

ROLE_ADMIN
Method Endpoint Description
GET /security/sessions List active sessions
DELETE /security/sessions/{sessionId} Terminate session
POST /security/sessions/terminate-all Terminate sessions
GET /security/access-logs Query access logs

Session tracking includes:

sessionId
tokenId
userId
userName
ipAddress
userAgent
createdAt
lastActivity
expiresAt
active

Access events include:

LOGIN_SUCCESS
FAILED_LOGIN
LOGOUT
PASSWORD_CHANGE

10. Notifications β€” /api/notifications

Method Endpoint Description
GET /api/notifications Paginated notifications
GET /api/notifications/unread Unread notifications
GET /api/notifications/unread/count Unread count
PUT /api/notifications/{notificationId}/read Mark as read
PUT /api/notifications/read-all Mark all as read

Users can only access their own notifications.

The user ID is derived from the authenticated JWT.


11. Debit Cards β€” /api/debit-cards

Method Endpoint Roles Description
GET /api/debit-cards/account/{accountId} ADMIN, MANAGER, USER Cards by account
GET /api/debit-cards/account-number/{accountNumber} ADMIN, MANAGER, USER Cards by account number
GET /api/debit-cards/{cardId} ADMIN, MANAGER, USER Card details
PUT /api/debit-cards/{cardId}/toggle-contactless ADMIN, USER Toggle contactless
PUT /api/debit-cards/{cardId}/toggle-international ADMIN, USER Toggle international
PUT /api/debit-cards/{cardId}/toggle-otp ADMIN, USER Toggle OTP
PUT /api/debit-cards/{cardId}/limits ADMIN, USER Update limits
PUT /api/debit-cards/{cardId}/merchant-blocks ADMIN, USER Merchant category controls
POST /api/debit-cards/{cardId}/freeze ADMIN, USER Freeze card
POST /api/debit-cards/{cardId}/unfreeze ADMIN, USER Unfreeze card
POST /api/debit-cards/{cardId}/replace ADMIN, USER Request replacement
PUT /api/debit-cards/{cardId}/block ADMIN, USER Permanently block

12. Debit Card Requests β€” /api/debit-card-requests

Method Endpoint Roles Description
POST /api/debit-card-requests USER Create card request
GET /api/debit-card-requests/my USER Own requests
GET /api/debit-card-requests/pending ADMIN, MANAGER Pending requests
GET /api/debit-card-requests/approved ADMIN, MANAGER Approved requests
GET /api/debit-card-requests/issued ADMIN, MANAGER Issued requests
POST /api/debit-card-requests/{requestId}/approve ADMIN, MANAGER Approve
POST /api/debit-card-requests/{requestId}/reject ADMIN, MANAGER Reject
POST /api/debit-card-requests/{requestId}/issue ADMIN, MANAGER Issue
POST /api/debit-card-requests/{requestId}/dispatch ADMIN, MANAGER Dispatch
POST /api/debit-card-requests/{requestId}/deliver ADMIN, MANAGER Deliver

13. Credit Cards & Plans

Credit Cards β€” /api/credit-cards

Method Endpoint Roles Description
GET /api/credit-cards/account/{accountId} ADMIN, MANAGER, USER Cards by account
GET /api/credit-cards/account-number/{accountNumber} ADMIN, MANAGER, USER Cards by account number
GET /api/credit-cards/{cardId} ADMIN, MANAGER, USER Card details
PUT /api/credit-cards/{cardId}/toggle-contactless ADMIN, USER Toggle contactless
PUT /api/credit-cards/{cardId}/toggle-international ADMIN, USER Toggle international
PUT /api/credit-cards/{cardId}/toggle-otp ADMIN, USER Toggle OTP
PUT /api/credit-cards/{cardId}/limits ADMIN, USER Update limits
PUT /api/credit-cards/{cardId}/merchant-blocks ADMIN, USER Merchant controls
POST /api/credit-cards/{cardId}/freeze ADMIN, USER Freeze
POST /api/credit-cards/{cardId}/unfreeze ADMIN, USER Unfreeze
POST /api/credit-cards/{cardId}/replace ADMIN, USER Replacement
PUT /api/credit-cards/{cardId}/block ADMIN, USER Permanent block

Credit Plans β€” /api/credit-plans

Method Endpoint Roles Description
GET /api/credit-plans ADMIN, MANAGER, USER List plans
GET /api/credit-plans/all ADMIN, MANAGER Admin/manager plan view
POST /api/credit-plans ADMIN, MANAGER Create plan
PATCH /api/credit-plans/{planId} ADMIN, MANAGER Update plan
POST /api/credit-plans/{planId}/assign/{cardId} ADMIN, MANAGER Assign plan

14. Loans & EMI

Loans β€” /api/loans

Method Endpoint Roles Description
GET /api/loans/customer/{customerId} ADMIN, MANAGER, USER Customer loans
GET /api/loans/account/{accountId} ADMIN, MANAGER, USER Account loans
GET /api/loans/{loanId} ADMIN, MANAGER, USER Loan details
POST /api/loans ADMIN, MANAGER Create loan

EMI β€” /api/emis

Method Endpoint Roles Description
GET /api/emis/loan/{loanId} ADMIN, MANAGER, USER EMI schedule
GET /api/emis/{emiId} ADMIN, MANAGER, USER EMI details

15. Account Statements

Endpoint:

GET /api/accounts/{accountNumber}/statement

Supports:

format=csv
format=pdf
from=
to=

Example:

GET /api/accounts/ACC_SBI_xxxxx/statement?format=pdf

Statements are generated from account transaction / ledger information.


16. Webhooks β€” /api/webhooks

Method Endpoint Roles Description
POST /api/webhooks ADMIN, MANAGER Register webhook
GET /api/webhooks ADMIN, MANAGER, AUDITOR List subscriptions
DELETE /api/webhooks/{id} ADMIN, MANAGER Delete subscription
PATCH /api/webhooks/{id}/active ADMIN, MANAGER Enable/disable

Webhook subscriptions contain configuration such as:

url
secret
eventTypes
active

17. Composite APIs & Card Events

Composite APIs β€” /api/composite

Method Endpoint Description
GET /api/composite/my/overview Aggregated dashboard overview
POST /api/composite/transfer Composite transfer workflow
GET /api/composite/customers/{customerId}/banking-profile Banking profile
GET /api/composite/banks/{bankId}/operations-summary Bank operations summary
POST /api/composite/accounts/balance-check Multi-account balance check
GET /api/composite/transactions/advanced Advanced transaction search
GET /api/composite/search/global Global entity search
POST /api/composite/accounts/{accountNumber}/freeze Freeze account
POST /api/composite/customers/{customerId}/kyc-verify KYC verification

Server-Sent Events

GET /stream/events

The endpoint provides real-time card-related events using Server-Sent Events (SSE).


🧾 Ledger Architecture β€” Double Entry

The ledger is the core financial component of the system.

Every successful transaction produces two entries:

Transaction
     β”‚
     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
     β–Ό               β–Ό
  DEBIT            CREDIT
     β”‚               β”‚
  Sender           Receiver

Example:

Transaction: TXN_001

Alice Account
    DEBIT    β‚Ή5,000

Bob Account
    CREDIT   β‚Ή5,000

Both entries reference the same transaction.


Balance derivation

Balances are derived from ledger entries:

SELECT COALESCE(
    SUM(
        CASE
            WHEN entry_type = 'CREDIT' THEN amount
            WHEN entry_type = 'DEBIT' THEN -amount
        END
    ),
    0
)
FROM ledger
WHERE account_id = :accountId;

Conceptually:

Balance = Total Credits - Total Debits

Duplicate ledger protection

A unique constraint is used to prevent duplicate entries:

uk_ledger_entry
(reference_id, account_id, entry_type)

This provides an additional database-level consistency guarantee.


πŸ›‘οΈ Security Design

JWT Authentication

The application uses:

Spring Security
        +
JWT
        +
Refresh Token Rotation

Protected requests use:

Authorization: Bearer <access-token>

Refresh Token Security

Refresh tokens are:

  • Stored as hashes
  • Rotated after use
  • Associated with token metadata
  • Revoked when reused
  • Managed as a token family

This prevents a previously used refresh token from being continuously reused.


Sender Ownership Validation

Authentication alone is not considered sufficient for financial operations.

For:

POST /transaction

the service verifies:

JWT User
    ↓
Customer
    ↓
Owned Account
    ↓
Sender Account

If the sender account does not belong to the authenticated user:

HTTP 403 Forbidden

The UPI payment flow applies the same ownership concept through UPI-to-account resolution.


Password Security

Passwords are protected using BCrypt.

Password reset flow:

Forgot Password
       ↓
Generate random reset token
       ↓
Store token + expiry
       ↓
Send reset link
       ↓
Validate token
       ↓
Update password
       ↓
Clear token

Reset tokens have a limited lifetime.


CORS

Configurable development origins include:

http://localhost:8081
http://localhost:5173
http://localhost:3000

πŸ” Concurrency Safety

The transaction layer uses database-level locking.

Pessimistic locking

Accounts involved in a transfer are locked before balance-sensitive operations.

Conceptually:

Transfer A β†’ B

Lock A
Lock B
   ↓
Validate balance
   ↓
Create transaction
   ↓
Create ledger entries
   ↓
Commit

Deterministic locking

When two accounts are involved:

accountId 10
accountId 25

the system locks:

10 β†’ 25

regardless of transfer direction.

Therefore:

A β†’ B
B β†’ A

both follow the same lock acquisition order.


πŸ—„οΈ Database Schema

The database contains the core banking and supporting infrastructure tables.

Main tables

Table Description
users Authentication users
roles Application roles
user_roles User-role relationship
banks Bank master data
customers Customer profiles
accounts Customer bank accounts
transactions Financial transactions
ledger Double-entry financial ledger
upi_profiles UPI identifiers
upi_payment_obj UPI payment intents and idempotency
audit_logs Application audit events
access_logs Security access events
user_sessions Active session tracking
refresh_tokens Refresh token metadata
notifications User notifications
debit_cards Debit cards
debit_card_requests Card issuance requests
credit_cards Credit cards
credit_plans Credit plan definitions
loans Loan records
emis EMI schedule
webhook_subscriptions Outbound webhook registrations

Key database relationships

users
  β”‚
  β”œβ”€β”€ user_roles ── roles
  β”‚
  └── customers
          β”‚
          └── accounts
                 β”‚
                 β”œβ”€β”€ transactions
                 β”‚
                 β”œβ”€β”€ ledger
                 β”‚
                 β”œβ”€β”€ upi_profiles
                 β”‚
                 β”œβ”€β”€ debit_cards
                 β”‚
                 β”œβ”€β”€ credit_cards
                 β”‚      β”‚
                 β”‚      └── credit_plans
                 β”‚
                 └── loans
                        β”‚
                        └── emis

Security-related data is maintained separately:

users
  β”‚
  β”œβ”€β”€ refresh_tokens
  β”œβ”€β”€ user_sessions
  β”œβ”€β”€ access_logs
  β”œβ”€β”€ audit_logs
  └── notifications

Important indexes

idx_ledger_account_id
idx_ledger_reference_id

idx_upi_payment_key
idx_upi_payment_status

idx_transactions_date

idx_audit_logs_timestamp
idx_audit_logs_action
idx_audit_logs_user_id
idx_audit_logs_resource

idx_access_logs_timestamp
idx_access_logs_event_type
idx_access_logs_user_id

idx_user_sessions_token_id
idx_user_sessions_active
idx_user_sessions_user_id

These indexes support common lookup, transaction, auditing, and session-management operations.


πŸ–₯️ Frontend β€” React Dashboard

The frontend is located in:

bank-frontend/

Technology:

React 18
TypeScript
Vite
Tailwind CSS
shadcn/ui
Radix UI
Recharts
React Router
Lucide React

Pages

Route Component Access
/ Index.tsx Public / redirect
/login LoginPage.tsx Public
/register RegisterPage.tsx Public
/forgot-password ForgotPasswordPage.tsx Public
/set-password SetPasswordPage.tsx Public
/dashboard Dashboard.tsx Authenticated
/banks BanksPage.tsx ADMIN, MANAGER, AUDITOR
/customers CustomersPage.tsx ADMIN, MANAGER, CUSTOMER_MANAGER, AUDITOR
/accounts AccountsPage.tsx Authenticated
/transactions TransactionsPage.tsx Authenticated
/payments PaymentsPage.tsx Authenticated
/upi UpiPage.tsx Authenticated
/audit-logs AuditLogsPage.tsx ADMIN, AUDITOR
/security SecurityPage.tsx ADMIN
/profile ProfilePage.tsx Authenticated

Frontend features

Role-based routing

ProtectedRoute
      ↓
PermissionGate
      ↓
Role-specific UI

Pages and UI sections are conditionally displayed based on the authenticated user's role.


Role-based dashboards

Different roles receive different dashboard views:

ADMIN
MANAGER
CUSTOMER_MANAGER
AUDITOR
USER

Global Command Palette

The dashboard includes:

Ctrl + K

for quick navigation through the application.


Dashboard analytics

The dashboard uses Recharts for:

  • Transaction volume
  • Status distribution
  • Bank distribution
  • Other operational metrics

QR Code viewer

UPI and account QR codes can be generated by the backend and displayed directly inside the React dashboard.


Security screens

Administrators can view:

  • Active sessions
  • Session metadata
  • Access logs
  • Login failures
  • Password-change events

and terminate sessions when required.


Feature flags

Audit and security modules can be toggled using:

VITE_ENABLE_AUDIT=true
VITE_ENABLE_SECURITY=true

Theme support

The dashboard supports:

Light Mode
Dark Mode

⭐ Engineering Highlights

The most important engineering decisions in this project are:

Double-entry accounting

One transaction
      ↓
Debit + Credit
      ↓
Balanced ledger

Idempotency

Same request
     ↓
Same idempotency key
     ↓
Existing payment state
     ↓
No duplicate financial operation

Concurrency control

Concurrent requests
       ↓
Pessimistic locks
       ↓
Deterministic lock ordering
       ↓
Safer account updates

Ownership enforcement

JWT identity
     ↓
Customer
     ↓
Account ownership
     ↓
Financial operation

Auditability

API operation
     ↓
Audit interceptor
     ↓
Audit log
     ↓
Traceable activity

Token rotation

Access Token
      +
Refresh Token
      ↓
Refresh
      ↓
New Access Token
      +
New Refresh Token
      ↓
Previous Refresh Token revoked

πŸ§ͺ Testing

The backend includes unit tests covering important business and security rules, including:

  • KYC validation
  • Authorization
  • Transaction rules
  • Ownership validation
  • Security-related behavior

Run tests using:

./mvnw test

Windows:

.\mvnw.cmd test

🧯 Troubleshooting

Frontend shows empty data

Verify:

VITE_API_BASE_URL=http://localhost:8080

and make sure the Spring Boot backend is running.


Port conflict

Default ports:

Backend  β†’ 8080
Frontend β†’ 5173

Depending on configuration, the frontend may use:

8081

Database connection failure

Check:

PostgreSQL is running
Database exists
Username is correct
Password is correct
application.yml is configured correctly

JWT 401 error

The access token may have expired.

Log in again or use the refresh-token flow.


Idempotency key conflict

Use a new unique idempotency key for a new payment attempt.

Do not reuse an existing key for a completely different payment.


Deadlock troubleshooting

The transaction layer uses deterministic account locking.

If investigating a locking problem, verify that account locking continues to use the intended ordered locking path.


πŸ“Ž Extra Documentation

Additional project documentation is available in the repository:


🌐 Live Demo

The frontend is deployed at:

https://ledgerlypay.vercel.app

Note: The live deployment demonstrates the frontend experience. Local development is recommended when exploring the complete backend, database, Swagger API, and transaction-processing workflow.


πŸ“ Important Project Structure

A simplified project structure:

.
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ main/
β”‚   β”‚   β”œβ”€β”€ java/
β”‚   β”‚   └── resources/
β”‚   β”‚
β”‚   └── test/
β”‚
β”œβ”€β”€ bank-frontend/
β”‚
β”œβ”€β”€ public/
β”‚   └── diagrams/
β”‚       β”œβ”€β”€ double-ledger-architecture.png
β”‚       β”œβ”€β”€ double-ledger-authentication-jwt-rbac.png
β”‚       β”œβ”€β”€ double-ledger-concurrency-locking.png
β”‚       β”œβ”€β”€ double-ledger-database-erd.png
β”‚       β”œβ”€β”€ double-ledger-deployment.png
β”‚       β”œβ”€β”€ double-ledger-idempotency-flow.png
β”‚       β”œβ”€β”€ double-ledger-ledger.png
β”‚       └── double-ledger-transaction-flow.png
β”‚
β”œβ”€β”€ swagger-documentation/
β”‚   β”œβ”€β”€ openapi.yaml
β”‚   └── openapi.json
β”‚
β”œβ”€β”€ PROJECT_REPORT.md
β”œβ”€β”€ pom.xml
└── README.md

πŸ“„ License

This project is licensed under the MIT License.

See LICENSE for details.


Built with Java Β· Spring Boot Β· PostgreSQL Β· React

Designed around correctness, concurrency, security, and reliability.

About

A Spring Boot and React banking architecture implementing a double-entry ledger, idempotent UPI transaction processing, and deterministic pessimistic locking.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Contributors

Languages