J-Coin Wallet is a high-security backend simulation for a banking/wallet application. It is designed to demonstrate production-grade architectural patterns, focusing on data integrity, concurrency control, and secure session management.
Unlike standard CRUD applications, this project implements strict ACID compliance and Pessimistic Locking strategies to prevent race conditions (double-spending) and deadlocks during financial transactions.
- Language: Java 25
- Framework: Spring Boot 4.0.1
- Database: PostgreSQL (Relational Data)
- Cache & Session: Redis (In-Memory Data Structure Store)
- Security: Spring Security (Session Management)
- Containerization: Docker & Docker Compose
This project was built with a "Defense in Depth" and "Data Integrity First" mindset. Below are the key engineering decisions:
Instead of standard stateless JWTs (which are hard to revoke immediately), we implemented a Stateful Auth pattern using Spring Session and Redis.
- Reference Token Pattern: The client receives a random Session ID (via Cookie), while the actual user data is stored securely in Redis.
- Revocation: This allows for instant account suspension or logout, essential for banking apps.
- HttpOnly Cookies: The session ID is stored in an
HttpOnlycookie, making it inaccessible to client-side JavaScript, effectively neutralizing XSS (Cross-Site Scripting) attacks. - Strict Security Config: Unauthenticated requests are blocked at the filter chain level with a custom
AuthenticationEntryPointthat returns proper JSON errors instead of HTML.
Financial transactions require strict synchronization.
- Pessimistic Locking: We use
SELECT ... FOR UPDATE(via JPA@Lock(LockModeType.PESSIMISTIC_WRITE)) when fetching wallets during a transfer. This prevents two concurrent threads from reading the same balance before one has finished writing, eliminating the Double Spending risk. - Deadlock Prevention: To avoid database deadlocks when two users transfer money to each other simultaneously, we implemented Ordered Locking. Resources (Wallets) are always locked in a specific order (based on ID), ensuring that circular dependencies cannot occur.
The codebase is organized by domain features rather than technical layers:
core: Shared entities, exceptions, and security configurations.modules.auth: Registration and authentication logic.modules.wallet: Wallet management, deposits, transfers, and transaction history.
- Java 25 or higher
- Docker & Docker Compose
- Maven
- Clone the repository:
git clone https://github.com/your-username/j-coin-wallet.git
cd j-coin-wallet
- Start Infrastructure (Postgres & Redis): We use Docker Compose to spin up the required databases.
docker-compose up -d
- Run the Application:
mvn spring-boot:run
The application will start on http://localhost:8080.
The API follows RESTful standards. All responses are in JSON format.
- Endpoint:
POST /api/auth/register - Description: Creates a new user with
ROLE_USER. - Body:
{
"name": "John Doe",
"email": "[email protected]",
"password": "securePassword123"
}
- Response (201 Created):
"Registration successful"
- Endpoint:
POST /api/auth/login - Description: Authenticates the user and sets an
HttpOnlySESSION cookie. - Body:
{
"email": "[email protected]",
"password": "securePassword123"
}
- Response (200 OK):
{
"message": "Login successful",
"userId": 1,
"name": "John Doe"
}
Note: Check your browser or Postman cookies to see the SESSION cookie.
- Endpoint:
POST /api/wallets - Body:
{
"currency": "TRY"
}
- Response (201 Created):
{
"id": 1,
"currency": "TRY",
"balance": 0
}
- Endpoint:
GET /api/wallets - Response (200 OK):
[
{
"id": 1,
"currency": "TRY",
"balance": 5000.00
},
{
"id": 2,
"currency": "USD",
"balance": 100.00
}
]
- Endpoint:
POST /api/wallets/deposit - Description: Adds funds to a specific wallet.
- Body:
{
"walletId": 1,
"amount": 1000.50
}
- Endpoint:
POST /api/wallets/transfer - Description: Securely transfers money between two wallets using ACID transactions and Pessimistic Locking.
- Body:
{
"fromWalletId": 1,
"toWalletId": 2,
"amount": 250.00,
"description": "Debt payment"
}
- Response (200 OK):
"Transfer successful"
- Endpoint:
GET /api/wallets/{walletId}/transactions?page=0&size=10 - Description: Fetches incoming and outgoing transactions for a specific wallet.
- Response (200 OK):
{
"content": [
{
"referenceNumber": "c89d-...",
"amount": 250.00,
"type": "TRANSFER",
"date": "2024-01-04T15:30:00",
"description": "Debt payment",
"fromWalletId": 1,
"toWalletId": 2
}
],
"pageable": { },
"totalPages": 1,
"totalElements": 1
}
The application features a GlobalExceptionHandler and a Custom AuthenticationEntryPoint.
- 401 Unauthorized: Invalid email/password or missing session.
{
"error": "Unauthorized",
"message": "Please login. Your session might be expired.",
"path": "/api/wallets"
}
- 400 Bad Request: Validation errors (e.g., negative amount, invalid email).
- 500 Internal Server Error: Unexpected system failures (e.g., Database connection lost).
Developed as a comprehensive study on Secure Java Backend Architecture.