Layering and dependency direction
app to domain to data/infra to common/config; the direction only points down and the build enforces it.
Layering is not decoration. It exists so that any person and any AI, given a requirement, can predict which layer the code belongs in.
Dependency direction
app ──▶ domain ──▶ data / infra ──▶ common / config ▲ │ └──────────── reverse is forbidden ───────┘
Warning: a reverse dependency is not "discouraged", it is a build failure: the assertion names the file and method.
What each layer owns
| Layer | Responsibility | Typical types |
|---|---|---|
app | Accept requests, validate input, convert DTO to VO, orchestrate calls | XxxController / XxxService / XxxDTO / XxxVO |
domain | Multi-step flows, cross-table consistency, rule orchestration | XxxHandler / XxxCmd / enums / exceptions |
infra | Touches the database and nothing else: entities, mappers, repositories | XxxDO / XxxMapper / XxxRepository |
data | Shared foundation for queries and writes | BaseRepository / PageQuery / PageQueries |
common / config | Context, threads, global exceptions, framework wiring | MiniMaoContextHolder / ResponseUtils |
Hard rules
appmust not importinfra.mapperdirectly — it goes through the Repository.- Controllers only bind parameters, validate, call and return. No business logic, no queries, no condition assembly.
domainmust not reference Spring Web types and must not return transport-layer objects.@Transactionalmust not appear in theRepositorylayer.- Field injection with
@Autowiredis banned; alwaysfinalplus a constructor. System.outandnew Date()are banned (there is a banned-pattern assertion).new Threadand self-built thread pools are banned; async work uses the framework executor.
What a violation looks like
Not a warning and not a review comment: the build fails and the output names the class, method and line. That is why nobody has to remember the conventions.
Transitional exceptions
Tip: a few legacy types still have reverse dependencies. They are transitional exceptions and must not spread. Write new code by the rules on this page; when you hit an exception, log it rather than copying it.
Last updated 2026-10-09Edit this page →