Solution/aditya-dolui#100
Open
AdityaDolui wants to merge 5 commits into
Open
Conversation
Added detailed documentation for the Wallet Transfer Service, including tech stack, prerequisites, database setup, running instructions, API endpoints, and testing.
There was a problem hiding this comment.
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 |
|
|
||
| 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 { | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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_recordstable is used to handle duplicate requests safely.For every incoming request:
A SHA-256 request hash is generated.
The system checks whether the idempotency key already exists.
If the key exists and the request hash matches:
The previously stored response is returned.
If the key exists but the request hash differs:
The request is rejected with a conflict response.
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_WRITErow-level lockingDeterministic 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 | 100This 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
Transferentity 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.mdIncluding:
Architecture overview
Database design
Class responsibilities
Concurrency strategy
Idempotency strategy
Future improvements