--- name: clean-architecture-java description: Use when laying out or extending a Java / Spring Boot service built with Maven — which module a class belongs in, which module may depend on which, and how an endpoint reaches a use case. --- # Clean Architecture — Java / Spring Boot The layer rules are those of `architecture-patterns`. This skill maps them onto Maven and Spring. ## One Maven module per layer | Module | Holds | Only `` on | |---|---|---| | `-domain` | aggregates, value objects, domain events | nothing | | `-application` | use cases and the interfaces they call | `-domain` | | `-infrastructure` | implementations of those interfaces (JPA, HTTP clients, files) | `-application` | | `-api` | `@SpringBootApplication`, controllers, `@Configuration` wiring | `-infrastructure` | - Import types reached transitively; never add a `` to reach them. - Spring, Jakarta and JPA dependencies appear only in the `-infrastructure` and `-api` poms. - Tests live in the two test modules `clean-architecture-testing` defines, never in a layer module. ## Use cases - A use case is a `final` class named after the action (`BorrowBook`). The controller calls it directly: no interface in front of it, no `*Service` implementation. - A command method returns `void`; the caller creates the new id and passes it in. A query returns a `*ViewModel` record built in Application, never a domain object. - Application declares an interface only where it calls out (repository, gateway). A repository interface sits in Domain when it persists an aggregate, in Application otherwise. - Who may *read* a resource is checked in the use case. Who may *change* it is an aggregate rule: the mutation method takes the caller's id and throws. - Wire every class with `@Bean` methods in `-api`; Domain and Application classes carry no Spring annotation. - One transaction per use-case call, opened in `-api` (`TransactionTemplate` around the call, or `@Transactional` on the controller method). Never add an interface to a use case to decorate it. - Inside each module, one package per feature (`…application.loan`, `…infrastructure.loan`), never a technical one (`repository`, `service`, `persistence`). A use case imports no other feature's package; what two features use moves to a `shared` package of that module. - No `port`, `adapter`, `in` or `out` packages, and no "port" in type names or comments. ## Domain - An aggregate is created through a static factory over a `private` constructor, and identified by a typed id record (`OrderId`), never a raw `String` or `UUID`. ## Guard The module graph and the Spring-free core are enforced by the pom and ArchUnit tests of the `clean-architecture-testing` skill (its `references/examples-java.md`).