Deliver Spring Boot code that conforms to the existing project architecture, interface contracts, and quality requirements. First identify the actual conventions of the current repository, then decide whether to follow them, gradually migrate, or explicitly refactor; do not treat examples or preferences as a global transformation the user did not request.
Applicable Boundaries
- Use the project conventions of this file in
youlai-boot. - In other Spring Boot projects, adopt only the general principles; directories, naming, response wrappers, and permission expressions are subject to the target repository.
- User instructions take precedence. Before modifying, check
AGENTS.md, build files, related modules, and uncommitted changes to avoid overwriting the user's work. - Ordinary feature development is not automatically expanded into a security audit, repository-wide renaming, framework upgrade, or multi-module split.
Project Baseline
| Layer | Selection |
|---|---|
| JDK | Java 17+ |
| Base Framework | Spring Boot 4.x |
| ORM | MyBatis-Plus |
| Database | MySQL 8.x |
| Cache | Redis 7.x |
| Authentication | Spring Security + JWT / Redis Token |
| API Documentation | Springdoc OpenAPI + Knife4j |
| Object Mapping | MapStruct; for complex joined queries, Mapper may project directly to VO |
The target repository's pom.xml and configuration classes are the final source of truth; verify official compatibility before upgrading dependencies or changing the compatibility baseline.
Architecture Boundaries
The target structure adopts a monolithic architecture of "package by business domain, layered within the domain":
com.youlai.boot
├── common/ # 纯共享类型:基础对象、结果、常量、通用异常
├── framework/ # Web、Security、MyBatis、缓存、切面等基础设施
├── config/ # 应用装配;不承载业务规则
├── support/ # file、mail、sms、sse 等外部能力
├── auth/ # 认证业务
├── system/ # 用户、角色、菜单、部门、字典等
├── form/ # 动态表单
├── workflow/ # 工作流
└── codegen/ # 代码生成
During migration, module/form、module/workflowmay be temporarily retained, but new code should not continue to create two top-level directory languages.
Observe the following boundaries:
commondoes not depend onframework、configor any business domain.frameworkdoes not depend on specific business domains; obtain business capabilities through Ports or callback interfaces.configmay serve as a composition root to assemble Beans such as framework, auth, and system.- Cross-business-domain calls use explicitly intentional Facades, Ports, or Commands, and do not pass another domain's Entity.
- Business Service interfaces do not extend MyBatis-Plus
IService<Entity>; implementation classes may internally reuseServiceImpl。 - Avoid bidirectional package dependencies. When necessary, prefer introducing project-owned command objects or domain events rather than moving Entity to
common。 - For a monolithic project, first use package boundaries and ArchUnit to enforce dependency direction; do not proactively split into microservices without an independent deployment requirement.
Determining the ownership of configuration classes and property classes:
@ConfigurationFor assembly classes, look at the Bean consumer: Beans consumed only by a single business domain or support component are placed with the domain (e.g.,auth/config/CaptchaConfig、support/mail/MailConfig); only cross-domain or framework-level Beans remain in the globalconfig/. Test method: if after deleting a business domain the Bean has no references, the assembly class should move with that domain.@ConfigurationPropertiesFor property classes, look at the package root shape: packages that already have sibling classes at the root (support/mail、support/sms、framework/web/ratelimit) are placed flat at the root; collection roots that contain only subdirectories under the root (auth、codegen、framework/security、support/file) get aproperty/subpackage.- Property classes are annotated only with
@ConfigurationProperties, not stacked with@Configuration; registration is uniformly delegated to@ConfigurationPropertiesScan, avoiding dual registration by component scanning and property scanning.
Model Responsibilities and Improvement Directions
| Type | Suggested Definition | Current Project Improvement Focus |
|---|---|---|
Entity |
Used only by the persistence layer | Basically reasonable, but SysUser/SysLog and Role/Dept/Menu 's Sys prefixes are inconsistent |
Form |
Write request input | Create/update may share; within Body, id duplicates the Path ID, and validation at some entry points is incomplete |
Query |
query conditions; paginated classes use XxxPageQuery |
UserQuery is actually a paginated query,DeptQuery is again a non-paginated query, so the semantics are inconsistent |
VO |
external responses or read-only projections | overall fairly standardized; having the Mapper directly project a VO for complex joins can be retained |
DTO |
intra-module or inter-module transfer | already converged: push payloads are sent by DictChangeDTO into dto/, and event semantics are carried by topic constants |
New code converges according to the following rules; for historical code, unless the user requests it, do not perform unprofitable batch renaming:
- Entity uses the domain name, e.g.,
User、Role; the table prefix is expressed by@TableName("sys_user"). Keep the existingSysUser、SysLogas a migration compatibility item. - Write models use
XxxForm. When create and update fields or validations differ, split intoXxxCreateForm、XxxUpdateForm。 - When the resource ID is already present in the Path, the Path is the single source of truth, and the Form does not carry the ID redundantly.
- Paginated queries use
XxxPageQuery, and non-paginated filtering usesXxxQuery. For time ranges, prefercreatedFrom、createdToand other explicit time types. - Do not stuff execution contexts such as permission scopes, the current user, or tenants into external Query objects; pass them through independent context parameters or security components.
- VO is only used for output and is not reused as a write model. The Mapper may directly return a VO for complex joins, but does not accept Controller Forms.
- DTOs must have clear internal transfer semantics. SSE/message push payloads are cross-layer transfer carriers; name them according to
XxxDTOand place them intodto/, with event semantics carried by topic constants (e.g.,SseTopics); put session or process state incontext. Only create theevent/package for genuine Spring domain events, and do not open a new category package for a single payload. - The auth module and other business domains uniformly use
Form/Query/VO, and no longer have bothreq/respsuffix sets coexist.
Input validation
@RequestBodyinputs use@Valid; when a Controller class needs to validate Path/Query scalars, use@Validated。- pagination parameter constraints
pageNum >= 1, and set a reasonable upper limit forpageSize. - Sort fields must map to a server-side whitelist; sort directions use enums or explicit allowed values, and directly concatenating arbitrary SQL fields is prohibited.
- For finite sets such as status and type, prefer enums; when compatible with database integers, complete conversion and validation at the boundary.
- Dynamic forms'
Map<String, Object>cannot be covered by Bean Validation alone and must enforce field whitelisting, type, length, and business rule validation. - Do not validate only in create APIs; write entry points such as updates, status changes, and password resets must also validate.
API and responses
- Resource paths use plural nouns, e.g.,
/api/v1/users; action endpoints are used only when they cannot be naturally expressed as a resource state. - Controller returns
Result<T>orPageResult<T>; when there is no response data, useResult<Void>, avoidingResult<?>。 - Controller is responsible for protocol adaptation; Service does not return
Result, and Mapper does not returnResultorPageResult。 - Existing modules may temporarily have Service return
IPage<VO>, with Controller callingPageResult.success(page); do not mix within the same modulePage、IPage、PageResultthree types of service contracts. - For create success, return the resource ID first; for update and delete success, return
Result<Void>。 - Keep the existing business code
A****、B****、C****system, and use appropriate HTTP statuses to express protocol errors, such as 400, 401, 403, 404, 409, 429, 500. - Use for create/update APIs according to actual idempotency risk
@RepeatSubmit; add for create, delete, update, and key actions according to audit needs@Log, and do not mechanically annotate all queries.
Persistence and Object Mapping
- Entities are not returned directly from Controllers, nor are they used as cross-module contracts.
- Prefer MapStruct for simple single-table mapping; for complex joined queries, Mappers may directly project VOs.
- Do not use
BeanUtils.copyPropertiesor JSON serialization for routine object mapping; handwritten mapping for a small number of explicit fields is acceptable. - Entity primary key strategy and logical deletion method shall follow the project-wide MyBatis-Plus configuration. Do not simultaneously invent a conflicting set of
@TableLogicor ID strategies.
Implementation Process
- Read the target module, adjacent modules, database mappings, configurations, and tests to confirm the real contract.
- Determine whether the change belongs to an input Form, query Query, output VO, or internal DTO/Event/Context.
- Define validation, authorization, transaction boundaries, and failure semantics first, then implement the Mapper, Service, and Controller.
- Check cross-domain dependencies; if data or actions from another domain are needed, call a narrow interface instead of depending on its Entity or general-purpose
IService。 - Compile and run tests related to the change; when an external database, Redis, or third-party service is unavailable, clearly state the unverified parts.
- Only modify files within the task scope, and report compatibility impacts and remaining migration items.
Comment Principles
- Comments explain constraints, reasons, side effects, threading/transaction requirements, and easily missed behaviors; they do not repeat class names, annotations, or the surface meaning of code.
- Public extension points, cross-module interfaces, and methods with non-obvious constraints should have Javadoc; simple internal POJOs and obvious getters/setters do not require item-by-item comments.
- When a stable Javadoc summary needs to be generated, prefer
{@summary ...}。 @authorUse the project's existing author convention, and do not invent values;@sincewrite the project's current version number, consistent withpom.xmlof theversion; update it synchronously when upgrading the version, and do not write dates.- API fields should preferably be described by
@Schemafor protocol meaning; Javadoc supplements domain constraints, avoiding copying the same sentence in two places. - Update comments synchronously when code changes; historical explanations that may no longer hold should be deleted or verified and rewritten.
For detailed rules, see references/comments.md。
Read references as needed
- For authentication, whitelists, tokens, or permissions: read references/authentication.md。
- For transaction boundaries or transaction invalidation: read references/transaction.md。
- For MapStruct or query projection: read references/mapstruct.md。
- For log levels, exception logs, or masking: read references/logging.md。
- For adding business resources or modules: read references/new-module.md。
- For dedicated comment or Javadoc cleanup: read references/comments.md。