Skip to content

Solution/aditya-dolui#100

Open
AdityaDolui wants to merge 5 commits into
Robustrade:mainfrom
AdityaDolui:solution/Aditya-Dolui_99
Open

Solution/aditya-dolui#100
AdityaDolui wants to merge 5 commits into
Robustrade:mainfrom
AdityaDolui:solution/Aditya-Dolui_99

Conversation

@AdityaDolui

Copy link
Copy Markdown

Wallet Transfer Service

Summary

Implemented a wallet-to-wallet transfer service with strong transactional guarantees.

The service ensures:

  • Idempotent request processing

  • Safe concurrent execution

  • Double-entry ledger consistency

  • Atomic transaction processing

  • Retry-safe behavior

  • Transfer state management


Database Schema

Introduced the following tables:

wallets

Stores wallet balances and represents the current state of each wallet.

transfers

Stores business transaction information and tracks the lifecycle of a transfer.

ledger_entries

Stores immutable accounting records used for auditability and reconciliation.

idempotency_records

Stores request fingerprints and cached responses to guarantee idempotent behavior.

The schema enforces referential integrity using foreign key constraints and supports financial auditability through a double-entry ledger model.


Idempotency Strategy

A dedicated idempotency_records table is used to handle duplicate requests safely.

For every incoming request:

  1. A SHA-256 request hash is generated.

  2. The system checks whether the idempotency key already exists.

  3. If the key exists and the request hash matches:

    • The previously stored response is returned.

  4. If the key exists but the request hash differs:

    • The request is rejected with a conflict response.

  5. If the key does not exist:

    • A new transfer is processed and the response is stored.

This guarantees retry-safe behavior and prevents duplicate transfers.


Concurrency Strategy

Concurrency is handled using:

  • PESSIMISTIC_WRITE row-level locking

  • Deterministic wallet lock ordering

  • Retry mechanism for lock acquisition failures

Deadlock Prevention

Before acquiring locks, wallet identifiers are sorted and always locked in a deterministic order.

Example:

Wallet A → Wallet B

instead of

Wallet B → Wallet A

This significantly reduces deadlock risk by preventing circular wait conditions.

Double Spending Protection

Wallet rows are locked before balance validation and updates occur.

This ensures that concurrent requests cannot spend the same balance simultaneously.


Database Consistency

The service follows a double-entry ledger model.

For every successful transfer:

  • One DEBIT ledger entry is created for the source wallet.

  • One CREDIT ledger entry is created for the destination wallet.

Example:

Transfer Amount = 100

Wallet | Entry Type | Amount -- | -- | -- Source Wallet | DEBIT | 100 Destination Wallet | CREDIT | 100

This guarantees:

  • Complete auditability

  • Historical traceability

  • Ledger consistency


Design Patterns Used

Repository Pattern

Used for data access abstraction.

Repositories:

  • WalletRepository

  • TransferRepository

  • LedgerEntryRepository

  • IdempotencyRecordRepository

Factory Pattern

Used through LedgerEntryFactory.

Responsibilities:

  • Create debit ledger entries

  • Create credit ledger entries

Domain Service Pattern

Used through TransferDomainService.

Responsibilities:

  • Balance validation

  • Wallet debit

  • Wallet credit

  • Ledger generation

  • Transfer state transitions

DTO Pattern

Used to separate API contracts from domain entities.

DTOs:

  • TransferRequest

  • TransferResponse

  • ErrorResponse

State Transition Pattern

Implemented inside the Transfer entity through:

  • markProcessed()

  • markFailed()

This prevents invalid status transitions.


Additional Notes

Implemented:

  • Global exception handling

  • Request hashing using SHA-256

  • Idempotency conflict detection

  • Transaction management using Spring Transactions

  • Retry support using Spring Retry

  • MapStruct-based DTO mapping

  • Clean layered architecture

  • SOLID design principles


Testing

Covered scenarios include:

  • Successful transfer execution

  • Insufficient balance validation

  • Idempotency replay

  • Idempotency conflict detection

  • Double-entry ledger verification

  • Concurrent transfer execution

  • Deadlock prevention validation


Documentation

Additional implementation details are available in:

DESIGN_DOC.md

Including:

  • Architecture overview

  • Database design

  • Class responsibilities

  • Concurrency strategy

  • Idempotency strategy

  • Future improvements

SrilekhaGhosh and others added 5 commits June 17, 2026 13:10
Added detailed documentation for the Wallet Transfer Service, including tech stack, prerequisites, database setup, running instructions, API endpoints, and testing.
Copilot AI review requested due to automatic review settings June 22, 2026 13:55

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements a Spring Boot–based wallet-to-wallet transfer service intended to provide transactional transfers with idempotency, concurrency protection, and double-entry ledger recording, alongside initial schema, configuration, and tests.

Changes:

  • Added core transfer API (controller/service/domain service) with idempotency records, wallet locking, and ledger entry creation.
  • Introduced Flyway migration and JPA entities for wallets/transfers/ledger/idempotency.
  • Added Maven/Spring/Testcontainers setup plus unit tests and documentation updates.

Reviewed changes

Copilot reviewed 53 out of 54 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
src/test/java/com/walletTransfer/walletTransfer/WalletTransferApplicationTests.java Spring context-load test wiring Testcontainers config
src/test/java/com/walletTransfer/walletTransfer/TestWalletTransferApplication.java Test application bootstrap with Testcontainers
src/test/java/com/walletTransfer/walletTransfer/TestcontainersConfiguration.java Defines Postgres Testcontainer bean
src/test/java/com/walletTransfer/walletTransfer/service/TransferServiceImplTest.java Mockito unit tests for TransferServiceImpl
src/test/java/com/walletTransfer/walletTransfer/service/TransferDomainServiceImplTest.java Mockito unit tests for domain transfer processing
src/test/java/com/walletTransfer/walletTransfer/service/IdempotencyServiceImplTest.java Mockito unit tests for idempotency service behaviors
src/main/resources/db/migration/V1__initial_schema.sql Initial database schema for wallets/transfers/ledger/idempotency
src/main/resources/application.yml Runtime datasource/JPA/Flyway/logging configuration
src/main/resources/application.properties Spring application name configuration
src/main/java/com/walletTransfer/walletTransfer/WalletTransferApplication.java Spring Boot entrypoint with retry enabled
src/main/java/com/walletTransfer/walletTransfer/util/WalletLockHelper.java Helper for deterministic wallet lock ordering
src/main/java/com/walletTransfer/walletTransfer/util/RequestHashUtil.java Utility for SHA-256 request hashing
src/main/java/com/walletTransfer/walletTransfer/util/GlobalExceptionHandler.java Centralized exception-to-HTTP mapping
src/main/java/com/walletTransfer/walletTransfer/service/TransferService.java Transfer service interface
src/main/java/com/walletTransfer/walletTransfer/service/TransferDomainService.java Domain service interface for transfer business rules
src/main/java/com/walletTransfer/walletTransfer/service/impl/TransferServiceImpl.java Transaction orchestration: idempotency, locking, persistence
src/main/java/com/walletTransfer/walletTransfer/service/impl/TransferDomainServiceImpl.java Balance validation + debit/credit + ledger generation
src/main/java/com/walletTransfer/walletTransfer/service/impl/Sha256HashingService.java HashingService implementation
src/main/java/com/walletTransfer/walletTransfer/service/impl/IdempotencyServiceImpl.java Idempotency lookup, persistence, and response serialization
src/main/java/com/walletTransfer/walletTransfer/service/IdempotencyService.java Idempotency service interface
src/main/java/com/walletTransfer/walletTransfer/service/HashingService.java Hashing service interface
src/main/java/com/walletTransfer/walletTransfer/repository/WalletRepository.java Wallet JPA repository with pessimistic lock query
src/main/java/com/walletTransfer/walletTransfer/repository/TransferRepository.java Transfer JPA repository
src/main/java/com/walletTransfer/walletTransfer/repository/LedgerEntryRepository.java Ledger entry JPA repository
src/main/java/com/walletTransfer/walletTransfer/repository/IdempotencyRecordRepository.java Idempotency record JPA repository
src/main/java/com/walletTransfer/walletTransfer/mapper/TransferMapper.java MapStruct mapper from Transfer to TransferResponse
src/main/java/com/walletTransfer/walletTransfer/factory/LedgerEntryFactory.java Factory for debit/credit ledger entries
src/main/java/com/walletTransfer/walletTransfer/exception/WalletNotFoundException.java Domain exception for missing wallet
src/main/java/com/walletTransfer/walletTransfer/exception/TransferNotFoundException.java Domain exception for missing transfer
src/main/java/com/walletTransfer/walletTransfer/exception/InsufficientBalanceException.java Domain exception for insufficient funds
src/main/java/com/walletTransfer/walletTransfer/exception/IdempotencyConflictException.java Domain exception for idempotency key conflicts
src/main/java/com/walletTransfer/walletTransfer/exception/DuplicateRequestException.java Domain exception placeholder for duplicate requests
src/main/java/com/walletTransfer/walletTransfer/exception/DeadlockRetryException.java Exception for exhausted lock-acquisition retries
src/main/java/com/walletTransfer/walletTransfer/enums/TransferStatus.java Transfer state enum
src/main/java/com/walletTransfer/walletTransfer/enums/LedgerEntryType.java Ledger entry type enum
src/main/java/com/walletTransfer/walletTransfer/enums/IdempotencyStatus.java Idempotency record status enum
src/main/java/com/walletTransfer/walletTransfer/entity/Wallet.java Wallet entity (balance + version + timestamps)
src/main/java/com/walletTransfer/walletTransfer/entity/Transfer.java Transfer entity (wallet refs, status, timestamps)
src/main/java/com/walletTransfer/walletTransfer/entity/LedgerEntry.java Ledger entry entity (transfer/wallet refs, timestamps)
src/main/java/com/walletTransfer/walletTransfer/entity/IdempotencyRecord.java Idempotency record entity (unique key, payload, status, timestamps)
src/main/java/com/walletTransfer/walletTransfer/dto/TransferResponse.java API response DTO
src/main/java/com/walletTransfer/walletTransfer/dto/TransferRequest.java API request DTO with validation constraints
src/main/java/com/walletTransfer/walletTransfer/dto/ErrorResponse.java Error response DTO used by exception handler
src/main/java/com/walletTransfer/walletTransfer/controller/TransferController.java REST endpoint for creating transfers
src/main/java/com/walletTransfer/walletTransfer/config/JacksonConfig.java Provides ObjectMapper bean
README.md Project overview, setup, and API docs
pom.xml Maven dependencies/plugins for Spring Boot + Flyway + MapStruct + Testcontainers
mvnw.cmd Maven wrapper (Windows)
mvnw Maven wrapper (Unix)
Design_Doc.md Design documentation for idempotency/concurrency/ledger approach
.mvn/wrapper/maven-wrapper.properties Maven wrapper configuration
.gitignore Ignore rules for build outputs/IDEs
.gitattributes Line-ending attributes for wrapper scripts
.env Local environment variables for DB connection

Comment on lines +1 to +9
CREATE TABLE wallets (
id UUID PRIMARY KEY,

balance BIGINT NOT NULL
CHECK (balance >= 0),

created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL
);
Comment on lines +40 to +45
type VARCHAR(20) NOT NULL,

amount BIGINT NOT NULL,

created_at TIMESTAMP NOT NULL,

Comment on lines +58 to +61
idempotency_key VARCHAR(255) NOT NULL,

request_hash VARCHAR(255) NOT NULL,

Comment on lines +66 to +69
status VARCHAR(20) NOT NULL,

created_at TIMESTAMP NOT NULL,

Comment on lines +3 to +15
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;

import java.util.UUID;

@Getter
@Setter
@Builder
public class TransferRequest {
Comment on lines +1 to +26
spring:

datasource:
url: ${DB_URL}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}

jpa:
hibernate:
ddl-auto: validate


show-sql: true

properties:
hibernate:
format_sql: true

flyway:
enabled: true
locations: classpath:db/migration

logging:
level:
org.hibernate.SQL: DEBUG
org.hibernate.orm.jdbc.bind: TRACE No newline at end of file
Comment thread README.md

Detailed design and architecture decisions are available in:

`DESIGN_DOC.md`
Comment on lines +11 to +13
import com.walletTransfer.walletTransfer.dto.TransferRequest;
import com.walletTransfer.walletTransfer.entity.LedgerEntry;
import com.walletTransfer.walletTransfer.dto.TransferResponse;
Comment on lines +37 to +42
@ExceptionHandler(TransferNotFoundException.class)
public ResponseEntity<ErrorResponse> handleTransfer(
TransferNotFoundException ex) {

return build(HttpStatus.INTERNAL_SERVER_ERROR, ex);
}
Comment on lines +30 to +32
@ExtendWith(MockitoExtension.class)
class TransferServiceImplTest {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants