--- name: spring-boot-data-ddd description: Spring Boot 4 data layer implementation for Domain-Driven Design. Use when implementing JPA or JDBC aggregates, Spring Data repositories, transactional services, projections, or entity auditing. Covers aggregate roots with AbstractAggregateRoot, value object mapping, EntityGraph for N+1 prevention, and Spring Boot 4 specifics (JSpecify null-safety, AOT repositories). For DDD concepts and design decisions, see the domain-driven-design skill. spring-boot-version: "4.0" --- # Spring Boot Data Layer for DDD Implements DDD tactical patterns with Spring Data JPA and Spring Data JDBC in Spring Boot 4. ## Technology Selection | Choose | When | |--------|------| | **Spring Data JPA** | Complex queries, existing Hibernate expertise, need lazy loading | | **Spring Data JDBC** | DDD-first design, simpler mapping, aggregate-per-table, no lazy loading | Spring Data JDBC enforces aggregate boundaries naturally—recommended for new DDD projects. ## Core Workflow 1. Define aggregate root → 2. Map value objects → 3. Create repository → 4. Implement service layer → 5. Add projections See [WORKFLOW.md](WORKFLOW.md) for detailed step-by-step instructions with code examples. ## Quick Patterns See [EXAMPLES.md](EXAMPLES.md) for complete working examples including: - **Aggregate Root** with AbstractAggregateRoot and domain events (Java + Kotlin) - **Repository with EntityGraph** for N+1 prevention - **Transactional Service** with proper boundaries - **Value Objects** (Strongly-typed IDs, Money pattern) - **Projections** for efficient read operations - **Auditing** with automatic timestamps ## Spring Boot 4 Specifics - **JSpecify null-safety**: `@NullMarked` and `@Nullable` annotations - **AOT Repository Compilation**: Enabled by default for faster startup - **Jakarta EE 11**: All imports use `jakarta.*` namespace - **ListCrudRepository**: New interface returning `List` instead of `Iterable` ## ListCrudRepository (Spring Data 3.1+) New repository interface returning `List` for better API ergonomics: ```java // OLD: CrudRepository returns Iterable public interface UserRepository extends CrudRepository { Iterable findAll(); // Requires conversion to List } // NEW: ListCrudRepository returns List public interface UserRepository extends ListCrudRepository { List findAll(); // Direct List return List findAllById(Iterable ids); // Also List } // Can also extend both for full functionality public interface UserRepository extends ListCrudRepository, ListPagingAndSortingRepository { } ``` **Benefits**: No more `StreamSupport.stream(iterable.spliterator(), false).toList()` conversions. ## Detailed References - **Workflow**: See [WORKFLOW.md](WORKFLOW.md) for detailed step-by-step data layer implementation - **Examples**: See [EXAMPLES.md](EXAMPLES.md) for complete working code examples - **Troubleshooting**: See [TROUBLESHOOTING.md](TROUBLESHOOTING.md) for common issues and Boot 4 migration - **Aggregates & Entities**: See [references/AGGREGATES.md](references/AGGREGATES.md) for complete patterns with value objects, typed IDs, auditing - **Repositories & Queries**: See [references/REPOSITORIES.md](references/REPOSITORIES.md) for custom queries, projections, specifications - **Transactions**: See [references/TRANSACTIONS.md](references/TRANSACTIONS.md) for propagation, isolation, cross-aggregate consistency ## Related Skills | Need | Skill | |------|-------| | DDD concepts and design | `domain-driven-design` | | REST API for aggregates | `spring-boot-web-api` | | Module boundaries | `spring-boot-modulith` | | Repository testing | `spring-boot-testing` | ## Anti-Pattern Checklist | Anti-Pattern | Fix | |--------------|-----| | `FetchType.EAGER` on associations | Use `LAZY` + `@EntityGraph` when needed | | Returning entities from controllers | Convert to DTOs in service layer | | `@Transactional` on private methods | Use public methods (proxy limitation) | | Missing `readOnly = true` on queries | Add for read operations (performance) | | Direct aggregate-to-aggregate references | Reference by ID only | | Multiple aggregates in one transaction | Use domain events for eventual consistency | ## Critical Reminders 1. **One aggregate per transaction** — Cross-aggregate changes via domain events 2. **Repository per aggregate root** — Never for child entities 3. **Value objects are immutable** — No setters, return new instances 4. **Flush before events** — Call `repository.save()` before events dispatch 5. **Test with `@DataJpaTest`** — Use `TestEntityManager` for setup