--- name: clean-architecture description: Design and review hexagonal or clean-architecture Java 25 / Spring Boot 4 modules - dependency direction, ports and adapters, use-case wiring, aggregates, value objects, Notification validation, sealed lifecycle states, domain events and outbox, transactions at the edge, SOLID decisions, strategy/observer/mediator patterns, scoped values, flexible constructors, Spring 7 resilience and HTTP service clients, and role-level tests. Use when a module declares architecture roles or its documents describe domain/application/infrastructure (or ports/adapters) layers. --- # Clean and hexagonal architecture rules 1. Read [project context](../java-spring-updates/references/project-context.md), then the affected module's architecture documents. Repository documents and architecture tests override these rules ([existing boundaries](../springboot-best-practices/rules/architecture-existing-boundaries.md)). 2. Map the change to roles with [role mapping](references/roles.md). If `.springboot-agent/project.json` declares `architecture.roles`, use them; otherwise infer roles from package names and say so in the summary. 3. Select the rules whose trigger matches the task or diff, highest impact first. For a new feature, follow the [vertical slice](references/vertical-slice.md) order: domain, port, use case, adapter, configuration, tests. 4. After editing, run `node /dist/cli.mjs boundaries --root ` when roles are configured, then finish through `spring-verify`. ## Rule categories by priority | Priority | Category | Impact | Prefix | | --- | --- | --- | --- | | 1 | Architecture boundaries | CRITICAL | `arch-` | | 2 | Domain model | HIGH | `domain-` | | 3 | Use cases | HIGH | `usecase-` | | 4 | SOLID decisions | MEDIUM | `solid-` | | 5 | Design patterns | MEDIUM | `pattern-` | | 6 | Java 25 / Spring 7 idioms | MEDIUM | `modern-` | | 7 | Tests by role | MEDIUM | `test-` | ## Quick reference | Trigger | Rule | | --- | --- | | New import, field type, or signature in domain/application code | [Point dependencies inward](rules/arch-dependency-direction.md) | | New persistence, messaging, HTTP, clock, or ID dependency for the core | [Ports owned by the core](rules/arch-ports-owned-by-core.md) | | New use case, `@Service` in application code, or bean wiring | [Wire in configuration](rules/arch-use-case-wiring.md) | | Controller, listener, repository, or client crossing a boundary | [Translate at the adapter](rules/arch-adapter-translation.md) | | New exception type or error response | [Map errors in one adapter](rules/arch-error-translation.md) | | Saving several aggregates, events, or `@Transactional` on a use case | [Transactions at the edge](rules/arch-transaction-edge.md) | | New aggregate, constructor, or rehydration mapping | [Creation vs rehydration](rules/domain-aggregate-factories.md) | | Setters, mutable getters, or state checks outside the aggregate | [Behavior, not setters](rules/domain-aggregate-encapsulation.md) | | Primitive IDs, money, or quantities in signatures | [Typed values](rules/domain-typed-values.md) | | Several inputs validated in one operation | [Collect errors, fail once](rules/domain-notification-validation.md) | | Status field, lifecycle, or transition logic | [Sealed states](rules/domain-state-transitions.md) | | Notifying other aggregates, services, or brokers | [Events through an outbox](rules/domain-events-outbox.md) | | New operation exposed to adapters | [One intent per use case](rules/usecase-single-intent.md) | | Business conditionals or calculations in a use case | [Orchestration only](rules/usecase-orchestration-only.md) | | A class with rules from different stakeholders | [Single responsibility](rules/solid-single-responsibility.md) | | New port implementation, fake, or `UnsupportedOperationException` | [Substitutable implementations](rules/solid-substitutable-implementations.md) | | A port growing methods for one consumer | [Role-specific ports](rules/solid-role-specific-ports.md) | | Field injection, `Instant.now()`, `getBean`, or new collaborators | [Explicit dependencies](rules/solid-explicit-dependencies.md) | | Branching on type, provider, or channel | [Sealed switch or strategy](rules/pattern-variation-choice.md) | | Flows across use cases, event fan-out, webhooks | [Observer and mediator](rules/pattern-observer-mediator.md) | | Validation before `super(...)` in entity constructors | [Flexible constructors](rules/modern-flexible-constructors.md) | | Correlation, tenant, or caller context via `ThreadLocal` | [Scoped context](rules/modern-scoped-context.md) | | Retries or concurrency limits on remote calls | [Resilient adapters](rules/modern-resilient-adapters.md) | | `@HttpExchange` clients for external APIs | [HTTP service adapters](rules/modern-http-service-adapters.md) | | New or changed tests | [Test each role at its level](rules/test-by-role.md) | Related rules owned by other skills: [records](../springboot-best-practices/rules/java-record-data-models.md), [exhaustive switches](../springboot-best-practices/rules/java-sealed-exhaustive-switch.md), [validation boundaries](../springboot-best-practices/rules/domain-validation-boundaries.md), [purposeful abstraction](../springboot-best-practices/rules/design-purposeful-abstraction.md), [proxy transactions](../springboot-best-practices/rules/tx-proxy-boundary.md), [null contracts](../java-spring-updates/rules/framework7-null-contracts.md). ## Applying a rule 1. Check its version bounds and exceptions against the module. Apply rules to new and changed code; do not restructure unrelated code without a task that asks for it. 2. During generation, prefer the repository's existing base types (`AggregateRoot`, `UseCase`, `Notification`, `*Gateway`) and naming over the examples here. 3. During review, cite the rule ID, file and line, the concrete consequence, and evidence. A pattern match alone is not a defect. `policy` rules apply when the module has adopted the architecture; `advisory` rules are design judgment.