A Spring Boot-based fintech backend for wallets, loans, and transactions. This project follows SOLID principles and clean architecture patterns.
Controller Layer (HTTP concern only)
↓
Service Layer (Business logic)
↓
Repository Layer (Data access)
↓
Database
- Service-oriented architecture: Controllers delegate to services
- DTO pattern: Entities are never exposed directly; DTOs are used for API responses
- Mapper pattern: Clean conversion between entities and DTOs
- Interface-based services: All services have interfaces for dependency injection and testability
- Custom exceptions: Domain-specific exceptions for better error handling
- Dependency injection: Spring's
@Autowiredto inject dependencies
src/main/java/com/LoanManagement/WalletSystem/
├── controller/ # HTTP request handling only
├── service/ # Business logic (interfaces)
├── service/impl/ # Service implementations
├── repository/ # Data access layer
├── model/ # JPA entities
├── dto/ # DTOs (separated by domain)
├── mapper/ # Entity to DTO mappers
├── mapper/impl/ # Mapper implementations
├── security/ # JWT and authentication
├── config/ # Spring configuration
├── exception/ # Custom exceptions
├── util/ # Utility classes
└── advice/ # Global exception handler
- Controllers handling business logic → Now only handle HTTP concerns
- Direct repository access in controllers → Controllers delegate to services
- Manual DTO mapping in controllers → Dedicated mapper layer
- Weak exception handling → Custom exceptions with granular handling
- SecurityContextHolder scattered → Centralized in SecurityUtil
ResourceNotFoundException- for 404 scenariosBusinessRuleException- for business logic violationsAuthenticationFailedException- for auth failures
-
AuthService(interface) →AuthServiceImpl- Encapsulates registration and login logic
- Auto-creates wallet on signup
- Returns DTOs instead of entities
-
WalletService(interface) →WalletServiceImpl- Get wallet details
- Fund wallet with transaction creation
- Get transaction history
- Enforces user ownership (authorization)
-
TransactionService- handles transaction persistence -
UserService- kept for backward compatibility
-
UserMapper→UserMapperImpl- Converts User entity to UserResponse DTO
-
WalletMapper→WalletMapperImpl- Converts Wallet entity to WalletResponse DTO
-
TransactionMapper→TransactionMapperImpl- Converts Transaction entity to TransactionResponse DTO
SecurityUtil- Centralized security context accessgetCurrentUserEmail()- Extract authenticated user emailisAuthenticated()- Check auth status
- Global exception handler now maps all custom exceptions
- Structured error responses (JSON)
- HTTP status codes aligned with REST standards
UserResponse- User data for API responsesWalletResponse- Wallet data for API responsesAuthResponse- Login response with token and type
- Docker & Docker Compose installed
- Java 17 and Maven (if running locally)
- PowerShell (for example commands)
From project root:
cd C:\Users\USER\IdeaProjects\WalletSystem
docker-compose up --build -dWait for both services to be healthy (check logs):
docker-compose logs -f appApplication will be available at: http://localhost:8080
curl -X POST http://localhost:8080/api/auth/register `
-H "Content-Type: application/json" `
-d '{
"fullName": "Alice Smith",
"email": "alice@example.com",
"password": "password123",
"phone": "08010000000",
"bvn": "12345678901"
}'curl -X POST http://localhost:8080/api/auth/login `
-H "Content-Type: application/json" `
-d '{"email":"alice@example.com","password":"password123"}'Response:
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer"
}$token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
curl -H "Authorization: Bearer $token" http://localhost:8080/api/wallets/mecurl -X POST http://localhost:8080/api/wallets/<walletId>/fund `
-H "Authorization: Bearer $token" `
-H "Content-Type: application/json" `
-d '{
"amount": 5000.00,
"reference": "TOPUP-001"
}'curl -H "Authorization: Bearer $token" http://localhost:8080/api/wallets/<walletId>/transactionsSPRING_DATASOURCE_URL- MySQL JDBC URLSPRING_DATASOURCE_USERNAME- Database userSPRING_DATASOURCE_PASSWORD- Database passwordAPP_JWT_SECRET- JWT signing secret (min 32 chars for production)
- Update
src/main/resources/application.propertieswith your MySQL credentials - Run:
cd C:\Users\USER\IdeaProjects\WalletSystem
.\mvnw.cmd spring-boot:run$env:SPRING_PROFILES_ACTIVE = "h2"
.\mvnw.cmd spring-boot:run- Controllers handle HTTP only
- Services handle business logic
- Repositories handle data access
- Mappers handle transformations
- Services are interfaces (open for extension via new implementations)
- Exception handlers can be extended to handle new exception types
- Mappers defined as interfaces for easy replacement
- All service implementations properly substitute their interfaces
- Exception hierarchy allows polymorphic exception handling
- Service interfaces are focused (AuthService, WalletService)
- Mappers have specific, single-purpose interfaces
- Services depend on abstractions (interfaces)
- Constructor injection ensures explicit dependencies
- No hidden dependencies in methods
- Create
LoanServiceinterface - Create
LoanServiceImplwith business logic - Create
LoanRequestandLoanResponseDTOs - Create
LoanMapperfor entity conversion - Inject in
LoanControllerwhich only handles HTTP
The architecture enforces separation of concerns automatically.
- Loan entity and endpoints (apply, approve, disburse, repay)
- Webhook integration (Paystack/Flutterwave)
- Scheduled jobs (loan reminders, mark overdue)
- Email notifications
- Swagger/OpenAPI documentation
- Unit and integration tests
- Flyway database migrations
- RabbitMQ/Kafka messaging (bonus)
# Clean build
cd C:\Users\USER\IdeaProjects\WalletSystem
.\mvnw.cmd clean package -DskipTestsExpected output: BUILD SUCCESS
All dependencies are managed in pom.xml. Key libraries:
- Spring Boot 4.0.6
- Spring Security 6
- Spring Data JPA
- JWT (jjwt)
- MySQL Connector
- Lombok (optional, can be added for cleaner code)
Architecture Status: ✅ Clean architecture with SOLID principles applied Current Endpoints: 2 (register, login) Protected Endpoints: 3 (getMyWallet, fundWallet, getTransactionHistory)