This project is a Spring Boot REST API designed using Clean Architecture principles.
It manages vehicle service operations including customers, vehicles, and service tracking.
The system demonstrates:
- Layered architecture (Domain → UseCase → Infrastructure → Web)
- DTO + MapStruct mapping
- Role-based authorization via interceptors
- Business rule enforcement in domain models
- Exception handling with centralized handler
- Pagination support
- Customer management (CRUD)
- Vehicle management (CRUD)
- Vehicle service tracking (PENDING → IN_PROGRESS → COMPLETED)
- Automatic next service date calculation
- Soft delete support using Hibernate
- Pagination support
- Role-based access control (ADMIN)
- Global exception handling
- Standard API response structure
- Clean Architecture implementation
- Swagger API documentation
- Rich Domain Models
| Category | Technology |
|---|---|
| Language | Java 21 |
| Framework | Spring Boot 3.4 |
| Build Tool | Gradle |
| Database | PostgreSQL / H2 |
| ORM | Spring Data JPA / Hibernate |
| Mapping | MapStruct |
| API Docs | Springdoc OpenAPI |
| Security | Spring Security |
| Boilerplate | Lombok |
| Architecture | Clean Architecture |
| Code Analysis | SonarQube |
The project follows Clean Architecture:
Controller → UseCase → Domain → Repository Interface
↓
Infrastructure (JPA)
This project uses explicit Bean Configuration classes instead of relying only on annotations like @Service or @Repository.
This ensures the system remains:
- Loosely coupled
- Easily testable
- Fully aligned with Clean Architecture principles
Dependencies are wired manually using:
@Configuration@Bean
This allows:
- UseCase layer to depend only on interfaces
- Infrastructure layer to provide implementations
- Easy replacement of components (e.g., switching database)
- customer usecase bean config
@Configuration
class CustomerBeanConfig {
@Bean
CustomerUseCase customerUseCase(CustomerRepository customerRepository) {
return new CustomerUseCaseImpl(customerRepository);
}
}- customer persistence bean config
@Configuration
class CustomerPersistenceBeanConfig {
@Bean
CustomerRepository customerRepository(
JpaCustomerRepository jpaCustomerRepository,
CustomerPersistenceMapper customerPersistenceMapper
) {
return new CustomerRepositoryImpl(jpaCustomerRepository, customerPersistenceMapper);
}
}- vehicle usecase bean config
@Configuration
class VehicleBeanConfig {
@Bean
VehicleUseCase vehicleUseCase(
VehicleRepository vehicleRepository,
CustomerRepository customerRepository) {
return new VehicleUseCaseImpl(vehicleRepository, customerRepository);
}
}- vehicle persistence bean config
@Configuration
class VehiclePersistenceBeanConfig {
@Bean
VehicleRepository vehicleRepository(
JpaVehicleRepository jpaVehicleRepository,
VehiclePersistenceMapper vehiclePersistenceMapper
) {
return new VehicleRepositoryImpl(jpaVehicleRepository, vehiclePersistenceMapper);
}
}UseCase (Business Logic)
↓ depends on
Repository Interface
↓ implemented by
Infrastructure (JPA)
- Framework-independent business logic
- Easier unit testing (mock interfaces)
- Flexible implementation replacement
- Strong separation of concerns
- The UseCase layer avoids using @Service to remain framework-independent.
Client
↓
Controller (DTO)
↓
Mapper → Domain
↓
UseCase
↓
Repository Interface
↓
Infrastructure (JPA)
↓
Database
↓
Response (DTO)
Contains core business logic.
- Customer
- Vehicle
- VehicleFuelType (Enum)
- VehicleServiceStatus (Enum)
- VehicleUpdateResult
- Next service date = lastServiceDate + 6 months
- Default vehicle status = PENDING
- Prevent update if service is COMPLETED
- CustomerRepository
- VehicleRepository
Handles application logic.
- Get all customers
- Save customer
- Update customer
- Delete customer
- Get all vehicles
- Register vehicle
- Update vehicle
- Delete vehicle
- Customer must exist before assigning vehicle
- Inprogress or Completed vehicles cannot be updated or deleted
- Service date auto-calculated
- Default update vehicle service status as PENDING
- Register new vehicle should have customer ID along with registration
Handles database operations.
- CustomerEntity
- JpaCustomerRepository
- CustomerRepositoryImpl
- CustomerPersistenceMapper
- VehicleEntity
- JpaVehicleRepository
- VehicleRepositoryImpl
- VehiclePersistenceMapper
Handles HTTP requests.
- CustomerController
- VehicleController
- CustomerRequestDTO / CustomerResponseDTO
- VehicleRequestDTO / VehicleResponseDTO / VehicleShortInfoDTO
- CustomerWebMapper
- VehicleWebMapper
- CustomerInterceptor
- VehicleInterceptor
- Spring Security configured
- CSRF disabled
- Swagger endpoints allowed
- Role-based control via interceptors
Handled using:
- ResourceNotFoundException → 404
- ServiceAlreadyCompletedException → 409
- ForbiddenAccessException → 403
- Generic Exception → 500
Fields:
- statusCode
- message
- timestamp
- data
- Pagination using PageRequest
- Soft delete using Hibernate
- DTO mapping using MapStruct
- Domain-driven business logic
- Interceptor-based authorization
- Automatic service scheduling
# 📂 Project Structure
📁 vehicle_service_system
├── 📁 domain @Core Business Logic & Enterprise Rules
│ ├── 📁 models @Pure Domain Entities (No Framework Logic)
│ │ ├── Customer.java
│ │ ├── Vehicle.java
│ │ ├── VehicleFuelType.java
│ │ ├── VehicleServiceStatus.java
│ │ └── VehicleUpdateResult.java
│ └── 📁 repositories @Domain Repository Interfaces (Outbound Ports)
│ ├── CustomerRepository.java
│ └── VehicleRepository.java
│
├── 📁 usecase @Application Specific Business Rules
│ ├── 📁 customer
│ │ ├── CustomerUseCase.java @Inbound Port
│ │ └── CustomerUseCaseImpl.java @Business Logic Implementation
│ └── 📁 vehicle
│ ├── VehicleUseCase.java
│ └── VehicleUseCaseImpl.java
│
├── 📁 infrastructure @External Frameworks & Tools (Persistence)
│ ├── 📁 customer
│ │ ├── 📁 config @Dependency Injection Configurations
│ │ │ ├── CustomerBeanConfig.java
│ │ │ └── CustomerPersistenceBeanConfig.java
│ │ └── 📁 persistence
│ │ ├── 📁 entity @Database Entities (JPA)
│ │ │ └── CustomerEntity.java
│ │ ├── 📁 jpa @Spring Data Repositories
│ │ │ └── JpaCustomerRepository.java
│ │ ├── 📁 mapper @Persistence Mapping (Domain <-> Entity)
│ │ │ └── CustomerPersistenceMapper.java
│ │ └── CustomerRepositoryImpl.java @Persistence Adapter
│ └── 📁 vehicle
│ ├── 📁 config
│ │ ├── VehicleBeanConfig.java
│ │ └── VehiclePersistenceBeanConfig.java
│ └── 📁 persistence
│ ├── 📁 entity
│ │ └── VehicleEntity.java
│ ├── 📁 jpa
│ │ └── JpaVehicleRepository.java
│ ├── 📁 mapper
│ │ └── VehiclePersistenceMapper.java
│ └── VehicleRepositoryImpl.java
│
├── 📁 web @Entry Points & Delivery (UI/API)
│ ├── 📁 config @Web MVC Configurations
│ │ └── WebConfig.java
│ ├── 📁 customer
│ │ ├── 📁 controllers @REST API Controllers
│ │ │ └── CustomerController.java
│ │ ├── 📁 DTOs @Request/Response Data Objects
│ │ │ ├── CustomerRequestDTO.java
│ │ │ └── CustomerResponseDTO.java
│ │ ├── 📁 interceptor @Request Pre-processing
│ │ │ └── CustomerInterceptor.java
│ │ └── 📁 webMappers @Web Mapping (DTO <-> Domain)
│ │ └── CustomerWebMapper.java
│ └── 📁 vehicle
│ ├── 📁 controllers
│ ├── 📁 DTOs
│ │ ├── VehicleRequestDTO.java
│ │ ├── VehicleResponseDTO.java
│ │ └── VehicleShortInfoDTO.java
│ ├── 📁 interceptor
│ └── 📁 webMappers
│
├── 📁 GlobalExceptionHandler @Centralized Exception Management
│ ├── ErrorMessage.java
│ ├── ForbiddenAccessException.java
│ ├── GlobalExceptionHandler.java
│ ├── ResourceNotFoundException.java
│ └── ServiceAlreadyCompletedException.java
│
├── 📁 GlobalResponseHandler @Generic Response Wrapping
│ └── StandardResponse.java
│
├── 📁 spring_security @Security & Access Control
│ └── SecurityConfig.java
│
└── VehicleServiceSystemApplication.java @Spring Boot Bootstrap Class
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/autocare/customers/all | Get all customers |
| POST | /api/v1/autocare/customers/register | Register customer |
| PUT | /api/v1/autocare/customers/{id} | Update customer |
| DELETE | /api/v1/autocare/customers/{id} | Delete customer |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/autocare/vehicles/all | Get all vehicles |
| POST | /api/v1/autocare/vehicles/register | Register vehicle |
| PUT | /api/v1/autocare/vehicles/{id} | Update vehicle |
| DELETE | /api/v1/autocare/vehicles/{id} | Delete vehicle |
| Action | Access |
|---|---|
| View all customers | ADMIN |
| Delete customer | ADMIN |
| Manage vehicles | ADMIN |
Swagger UI:
http://localhost:5000/swagger-ui/index.html
OpenAPI JSON:
http://localhost:5000/v3/api-docs
{
"customerName": "James Smith",
"customerPhone": "555-0101",
"customerEmail": "james.smith@example.com"
}
{
"statusCode": 200,
"message": "Customers details fetched successfully",
"timestamp": "2026-04-27T19:05:11.8739514",
"data": [
{
"customerId": 1,
"customerName": "James Smith",
"customerPhone": "555-0101",
"customerEmail": "james.smith@example.com",
"vehicles": [
{
"vehicleId": 1,
"vehicleNumber": "NY-7829-K",
"vehicleModel": "Ford F-150",
"lastServiceDate": "2024-01-15",
"nextServiceDate": "2024-07-15",
"mileage": 15000
}
]
}
]
}{
"vehicleNumber": "CAB-1234",
"vehicleModel": "Toyota Prius",
"vehicleFuelType": "HYBRID",
"mileage": 50000,
"lastServiceDate": "2025-01-01",
"customerId": 1
}
{
"statusCode": 200,
"message": "Details fetched successfully",
"timestamp": "2026-04-27T19:16:15.648869",
"data": [
{
"vehicleId": 1,
"vehicleNumber": "NY-7829-K",
"vehicleModel": "Ford F-150",
"vehicleFuelType": "PETROL",
"lastServiceDate": "2024-01-15",
"nextServiceDate": "2024-07-15",
"mileage": 15000,
"customerId": 1,
"customerName": "James Smith",
"vehicleServiceStatus": "COMPLETED"
}
]
}git clone https://github.com/yahan-botheju/vehicle-service-system.gitcd vehicle-service-system./gradlew bootRunDeveloped as a Clean Architecture practice project focusing on:
- Real-world backend structure
- Scalable system design
- Separation of concerns
This project was built to practice:
- Clean Architecture
- Spring Boot advanced structuring
- DTO & mapping strategies
- Business rule implementation
- API design best practices
- Rich Domain Models
- Standered Error Response
- This is a learning-focused project, but the architecture is strong enough to evolve into a production-ready system.