Skip to content

Repository files navigation

Transaction System

Spring Boot wallet engine built around safe account creation and money-transfer rules. PostgreSQL is the source of truth; all monetary values use long minor units (for example, 2500 represents 25.00 THB).

Current status

  • POST /api/accounts creates an active THB/USD/etc. account.
  • POST /api/transfers performs an atomic, idempotent transfer.
  • GET /api/transfers/{transferId} returns a persisted transfer result.
  • Transfers use PostgreSQL row-level locks and create debit/credit ledger entries in the same transaction.
  • Kafka, Debezium, and Redis read models are deferred until the core transfer flow is complete.

Prerequisites

  • Java 21
  • Docker

Run locally

Start PostgreSQL and Redis:

docker compose up -d

Start the application:

./mvnw spring-boot:run

Check health:

curl http://localhost:8080/actuator/health

Create an account:

curl -X POST http://localhost:8080/api/accounts \
  -H 'Content-Type: application/json' \
  -d '{"ownerId":"user-001","currency":"THB","initialBalance":100000}'

Create two accounts, then transfer money between their response id values:

curl -X POST http://localhost:8080/api/transfers \
  -H 'Content-Type: application/json' \
  -d '{
    "idempotencyKey":"transfer-001",
    "fromAccountId":"<source-account-uuid>",
    "toAccountId":"<destination-account-uuid>",
    "amount":2500,
    "currency":"THB"
  }'

A completed transfer returns 201 Created. Insufficient balance returns 422 and records a failed transfer without changing either balance. Reusing the same idempotencyKey with the same request returns the saved result.

Fetch a transfer:

curl http://localhost:8080/api/transfers/<transfer-uuid>

Tests

Run the complete suite (Docker is required for Testcontainers):

./mvnw test

Run only fast transfer business-rule tests:

./mvnw test -Dtest=TransferUseCaseTest

Core flow

HTTP request → Controller → Use Case → Persistence Adapter → PostgreSQL

The transfer use case locks both accounts in deterministic UUID order before changing balances, then persists the transfer and its debit/credit ledger entries in one database transaction.

Further reading

Reference documentation

Guides

Testcontainers

Core integration tests use postgres:17. The optional Testcontainers setup also defines Kafka and Redis containers; pin their image tags before using them in production-like tests.

About

A mini banking core simulator

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages