A production-grade library management system built with Domain-Driven Design (DDD), Clean Architecture, and Hexagonal Architecture principles. This project demonstrates enterprise-level Java development practices with a focus on maintainability, testability, and scalability.
- Architecture Overview
- Technology Stack
- Project Structure
- Design Patterns & Principles
- Getting Started
- API Documentation
- Database Management
- Security
- Development Guidelines
This project follows Clean Architecture with DDD tactical patterns, organized into distinct layers:
┌─────────────────────────────────────────────────────────┐
│ Interfaces Layer │
│ (REST Controllers, DTOs) │
└──────────────────┬──────────────────────────────────────┘
│
┌──────────────────▼──────────────────────────────────────┐
│ Application Layer │
│ (Use Cases, Application Services) │
└──────────────────┬──────────────────────────────────────┘
│
┌──────────────────▼──────────────────────────────────────┐
│ Domain Layer │
│ (Entities, Value Objects, Business Logic) │
│ ◄── No dependencies on outer layers │
└──────────────────▲──────────────────────────────────────┘
│
┌──────────────────┴──────────────────────────────────────┐
│ Infrastructure Layer │
│ (JPA Entities, Repositories, Mappers, Security) │
└─────────────────────────────────────────────────────────┘
- Domain Layer Independence: Domain entities contain business logic and have zero dependencies on frameworks
- Repository Pattern: Domain repositories (interfaces) are implemented by infrastructure adapters
- Mapper Pattern: Clean separation between domain entities and persistence entities (JPA)
- Use Case Pattern: Each business operation is a single-purpose use case class
- Value Objects: Immutable objects for domain concepts (ISBN, Email, Role, etc.)
- Spring Boot 3.3.3
- Java 17
- Maven 3
- Spring Data JPA (Hibernate 6)
- PostgreSQL 15
- Flyway (Database migrations)
- Spring Security 6
- JWT (JWT token-based authentication)
- BCrypt (Password encryption)
- Lombok (Boilerplate reduction)
- Jakarta Validation (Input validation)
src/main/java/com/kane/librarymanagement/
│
├── domain/ # Domain Layer (Business Logic)
│ ├── book/
│ │ ├── Book.java # Domain Entity (rich model)
│ │ ├── ISBN.java # Value Object
│ │ ├── BookId.java # Value Object
│ │ └── BookRepository.java # Domain Interface
│ ├── user/
│ │ ├── User.java # Domain Entity
│ │ ├── Role.java # Value Object (immutable)
│ │ ├── Email.java # Value Object
│ │ ├── UserId.java # Value Object
│ │ └── UserRepository.java # Domain Interface
│ ├── enums/
│ │ ├── RoleType.java
│ │ └── BorrowStatus.java
│ └── shared/
│ └── exceptions/
│ └── BusinessException.java
│
├── application/ # Application Layer (Use Cases)
│ ├── auth/
│ │ └── usecases/
│ │ └── SignInUseCase.java
│ ├── book/
│ │ ├── dto/ # Request/Response DTOs
│ │ │ ├── CreateBookRequest.java
│ │ │ ├── UpdateBookRequest.java
│ │ │ └── BookResponse.java
│ │ └── usecases/
│ │ ├── CreateBookUseCase.java
│ │ ├── UpdateBookUseCase.java
│ │ ├── DeleteBookUseCase.java
│ │ ├── GetOneBookUseCase.java
│ │ └── ListBookUseCase.java
│ ├── user/
│ │ ├── dto/
│ │ └── usecases/
│ └── common/
│ └── services/
│ └── JwtService.java
│
├── infrastructure/ # Infrastructure Layer (Adapters)
│ ├── persistence/
│ │ ├── repositories/ # Repository Implementations (Adapters)
│ │ │ ├── BookRepositoryImpl.java
│ │ │ └── UserRepositoryImpl.java
│ │ └── jpa/
│ │ ├── entities/ # JPA Entities (Persistence Models)
│ │ │ ├── Book.java
│ │ │ ├── User.java
│ │ │ └── Borrowing.java
│ │ ├── repositories/ # Spring Data JPA Interfaces
│ │ │ ├── BookJpaRepository.java
│ │ │ └── UserJpaRepository.java
│ │ └── mappers/ # Domain ↔ JPA Mappers
│ │ ├── BookMapper.java
│ │ └── UserMapper.java
│ ├── security/
│ │ └── SecurityConfig.java
│ └── intercepts/
│ └── JwtRequestFilter.java
│
├── interfaces/ # Interface Layer (API)
│ └── rest/
│ └── controllers/
│ ├── AuthController.java
│ ├── BookController.java
│ └── UserController.java
│
└── config/ # Configuration
└── ApplicationConfig.java
src/main/resources/
├── application.properties
└── db/migration/ # Flyway migrations
├── V2__create_member_table.sql
├── V3__create_book_table.sql
└── V4__create_book_history_table.sql
-
Repository Pattern
- Domain repositories define contracts
- Infrastructure provides JPA implementations
- Example:
BookRepository(domain) ←BookRepositoryImpl(infrastructure)
-
Mapper Pattern
- Separates domain models from persistence models
- Prevents JPA annotations polluting domain layer
- Example:
BookMapper.toDomain(),BookMapper.toJpa()
-
Value Object Pattern
- Immutable objects representing domain concepts
- Built-in validation
- Examples:
ISBN,Email,Role,BookId
-
Use Case Pattern
- Single Responsibility - one use case per operation
- Example:
CreateBookUseCase,UpdateBookUseCase
-
Builder Pattern
- Fluent API for constructing complex domain entities
- Validates invariants at build time
- Example:
User.builder().username("john").email(Email.of("john@example.com")).build()
- Single Responsibility: Each use case handles one business operation
- Open/Closed: Repository implementations can be swapped without changing domain
- Liskov Substitution: Domain interfaces can be implemented by any adapter
- Interface Segregation: Repositories expose only needed methods
- Dependency Inversion: Domain depends on abstractions, not implementations
- Entities:
Book,User(with identity and lifecycle) - Value Objects:
ISBN,Email,Role(immutable, compared by value) - Aggregates:
Useris the aggregate root for borrowed books - Repositories: Abstract data access for aggregates
- Domain Services: Business logic that doesn't belong to entities
- Java 17 or higher
- PostgreSQL 15 or higher
- Maven 3.8+
- Create PostgreSQL database:
CREATE DATABASE library_management_db;- Configure database connection:
Update src/main/resources/application.properties:
spring.datasource.url=jdbc:postgresql://localhost:5432/library_management_db
spring.datasource.username=postgres
spring.datasource.password=your_password- Install dependencies:
mvn clean install- Run Flyway migrations:
# Initialize Flyway (first time only)
mvn flyway:baseline
# Apply migrations
mvn flyway:migrate- Start the application:
mvn spring-boot:runThe application will start on http://localhost:8080
POST /api/auth/signin
Content-Type: application/json
{
"username": "admin",
"password": "password123"
}
Response: 200 OK
Set-Cookie: accessToken=<jwt_token>; HttpOnlyPOST /api/books
Authorization: Bearer <token>
Content-Type: application/json
{
"isbn": "978-0-596-52068-7",
"title": "Head First Design Patterns",
"author": "Eric Freeman",
"publisher": "O'Reilly Media",
"publishedYear": 2004,
"genre": "Computer Science",
"totalCopies": 10
}
Response: 201 CreatedGET /api/books
Authorization: Bearer <token>
Response: 200 OK
[
{
"id": 1,
"isbn": "978-0-596-52068-7",
"title": "Head First Design Patterns",
"author": "Eric Freeman",
"totalCopies": 10,
"availableCopies": 8,
"createdAt": "2024-03-13T10:30:00Z"
}
]GET /api/books/{isbn}
Authorization: Bearer <token>
Response: 200 OKPUT /api/books/{id}
Authorization: Bearer <token>
Content-Type: application/json
{
"title": "Updated Title",
"author": "Updated Author",
"totalCopies": 15
}
Response: 200 OKDELETE /api/books/{id}
Authorization: Bearer <token>
Response: 204 No ContentSimilar RESTful endpoints for user management at /api/users
Important Rules:
- Never modify existing migration files in
src/main/resources/db/migration/ - Always create new migration files for schema changes
- Naming Convention:
V{version}__{description}.sql Examples: V2__create_member_table.sql V3__create_book_table.sql V7__add_role_fields_to_user_table.sql
# Initialize Flyway (first time setup)
mvn flyway:baseline
# Apply pending migrations
mvn flyway:migrate
# Validate applied migrations
mvn flyway:validate
# View migration info
mvn flyway:infoCheck applied migrations in PostgreSQL:
SELECT * FROM flyway_schema_history ORDER BY installed_rank;- JWT-based authentication with HTTP-only cookies
- BCrypt password hashing (cost factor: 10)
- Role-based access control (RBAC):
ADMIN: Full access (CRUD on all resources)USER: Read access + borrow/return booksGUEST: Limited read access
Roles are implemented as Value Objects with denormalized permissions:
Role.admin() → maxBookNumber: 20, maxBorrowDuration: 60 days
Role.user() → maxBookNumber: 5, maxBorrowDuration: 14 days
Role.guest() → maxBookNumber: 2, maxBorrowDuration: 7 daysControllers use @PreAuthorize for method-level security:
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<BookResponse> createBook(...)
@PreAuthorize("hasAnyRole('ADMIN', 'USER')")
public ResponseEntity<List<BookResponse>> listBooks(...)- Domain First: Create domain entities, value objects, and repository interfaces
- Use Cases: Implement application use cases with business logic
- Infrastructure: Add JPA entities, mappers, and repository implementations
- Interface: Create REST controllers and DTOs
- Migration: Add Flyway migration if database changes are needed
- Business logic belongs in domain entities/value objects
- Use case classes should be thin orchestrators
- Validation happens at multiple layers:
- Domain: Business invariants (e.g.,
ISBNformat) - Application: Use case preconditions
- Interface: Input validation with Jakarta Validation
- Domain: Business invariants (e.g.,
- Mappers must be used to convert between layers (no JPA entities in domain)
- Domain Layer: Unit tests for business logic
- Use Cases: Integration tests with mocked repositories
- Controllers: Spring MockMvc tests
- Repositories: Spring Data JPA tests with test database
- Testability: Domain logic testable without framework dependencies
- Maintainability: Clear separation of concerns across layers
- Flexibility: Easy to swap infrastructure (e.g., PostgreSQL → MongoDB)
- Scalability: Use cases can be independently optimized
- Team Collaboration: Different teams can work on different layers
- Business Focus: Domain layer reflects business requirements clearly
- Complexity: More layers = more code (justified for long-term projects)
- Learning Curve: Team needs DDD knowledge
- Performance: Mapping overhead (negligible in most cases)
When contributing, ensure:
- Domain logic stays in the domain layer
- All new features include tests
- Database changes include Flyway migrations
- API changes are documented
- Follow existing naming conventions
- Domain-Driven Design by Eric Evans
- Clean Architecture by Robert C. Martin
- Spring Data JPA Documentation
- Flyway Documentation
MIT License