Controller layer
REST controllers receive requests and expose authentication, wallet, transfer, history, and admin endpoints.
Case study · Java backend
A Spring Boot wallet backend with stateless JWT authentication, USER/ADMIN authorization, wallet balances, deposits, user-to-user transfers, paginated transaction history, and PostgreSQL persistence.
The problem
A wallet transfer changes more than one row: the sender balance decreases, the recipient balance increases, and a transaction record is created. The backend needs to validate the request, authorize the caller, persist all related changes together, and return consistent API errors when something fails.
Architecture
REST controllers receive requests and expose authentication, wallet, transfer, history, and admin endpoints.
Business rules such as self-transfer checks, balance validation, deposits, transfers, and transaction mapping stay outside the controller.
Spring Data JPA repositories manage wallet, user, and transaction persistence through Hibernate and PostgreSQL.
Authentication & authorization
Registration and login issue JWTs that are processed by Spring Security for protected API requests.
Wallet routes require authenticated access, while administration endpoints are restricted to the ADMIN role.
Passwords are stored as BCrypt hashes, while JWT and database secrets are externalized from source control.
Transactional consistency
The transfer service is annotated with @Transactional. If validation or persistence fails before completion, Spring rolls the transaction back instead of leaving only one balance updated.
Wallet balances and transfer amounts use BigDecimal so decimal monetary values are not handled with binary floating-point arithmetic.
The Wallet entity uses @Version so concurrent updates can be detected instead of silently overwriting a newer wallet state.
Debit, credit, and transaction-record creation belong to the same transaction boundary and commit together.
API correctness
Requests validate transfer amounts, users, available balance, self-transfers, and authenticated identity before changing state.
A global exception handler turns application errors into a consistent API response structure rather than exposing stack traces.
Transaction history uses Spring Data pagination so clients can request pages instead of loading all records at once.
The project is packaged with Docker and Docker Compose, with PostgreSQL data stored in a persistent Docker volume.
What I would improve next
The repository identifies Flyway migrations, OpenAPI documentation, broader integration testing, explicit optimistic-lock conflict handling, refresh tokens, rate limiting, audit logging, and CI as logical next improvements. The current project remains a portfolio wallet simulation and does not process real money or connect to banking networks.