# Handoff: CRM Controller IO Conventions Implementation **Date:** 2026-08-10 **Branch:** master **Last commits:** `ae103a1` (ticket 01 main), `80bc063` (ticket 01 status update) --- ## 1. What This Project Is CRM 后端(Java 17 + Spring Boot 3 + MyBatis-Plus,Maven 多模块单体)。正在统一 Controller 出入参约定,由 ADR-0017 驱动,推翻旧的三类方案(SaveParam/PageParam/DTO),改为两类(Param/DTO)。 **核心工件(勿重复,引用即可):** - **ADR-0017:** `docs/adr/0017-controller-io-param-dto-conventions.md` - **Spec:** `.scratch/controller-io-conventions/spec.md` - **7 个 Ticket:** `.scratch/controller-io-conventions/issues/01-*.md` 至 `07-*.md` - **研究文档:** `docs/research/2026-08-10-dto-vo-param-conventions.md` --- ## 2. What's Done ### Ticket 01 — BaseDTO 重构 + IBaseService 清理(resolved) Commit `ae103a1`,15 files, +360/-62。 | 文件 | 改动 | |---|---| | `crm-base/.../domain/dto/BaseDTO.java` | `abstract`,仅 `id`/`createTime`/`updateTime`(`@JsonInclude NON_NULL`),移除 `creatorId`/`updaterId`/`deleted`/`toEntity(Supplier)` | | `crm-base/.../service/IBaseService.java` | 删除 `saveDTO`/`updateDTO` 死代码 | | `crm-base/.../utils/BeanCopyUtils.java` | javadoc 移除 `BaseDTO.toEntity` 引用 | | `README.md` | §3/§4/§10 同步更新 | | `crm-auth/.../ResourceController.java` | 修复预存 UTF-8 BOM | | `crm-auth/.../RoleController.java` | 修复预存 UTF-8 BOM | 验证:`mvn clean compile` 全 6 模块 SUCCESS;`mvn test` 45 tests, 0 failures, 0 errors。 --- ## 3. Key Technical Decisions(ADR-0017 摘要) 1. **两类对象**:`XxxParam`(查询/分页入参,extends `BaseParam`)+ `XxxDTO`(写入参+出参双向,Route A) 2. **BaseDTO**:abstract,仅 `id`/`createTime`/`updateTime`,`@JsonInclude(NON_NULL)`;统计/聚合类不继承 3. **Mass assignment 防御**:全局 `@ControllerAdvice` + `@InitBinder` + `setDisallowedFields`,strip 掉 `createTime`/`updateTime`/`creatorId`/`updaterId`/`deleted`/`builtin`(尚未实现 = ticket 02) 4. **硬约束**:Entity 不出现在 Controller 签名;`deleted`/`creatorId`/`updaterId` 不出现在 HTTP 响应 5. **封装阈值**:≥3 参数封 `XxxDTO`,≤2 保持 `@RequestParam`(纯参数个数) 6. **转换**:`fromEntity()`/`toEntity()` 写在各 DTO 类上,Service 层调用 7. **表单绑定**:隐式 `@ModelAttribute`(不加 `@RequestBody`),契合 `application/x-www-form-urlencoded` 契约 8. **全量回填**:所有存量违规代码全改(非仅新代码) 9. **命名**:`dto/` 包内 HTTP 出入参类一律 `XxxDTO` 后缀;存量 VO 已重命名 --- ## 4. Frontier — What's Next ### Ticket 02 — 全局 @InitBinder Mass Assignment 防御(无阻塞,可立即开始) **目标**:创建全局 `@ControllerAdvice` + `@InitBinder`,用 `setDisallowedFields` strip 掉服务端裁定的字段。 **strip 字段列表**:`createTime`, `updateTime`, `creatorId`, `updaterId`, `deleted`, `builtin` **实现位置**:`crm-base/src/main/java/com/crm/base/advice/` 包下新建类(已有 `GlobalExceptionHandler` 在同包) **验收标准**(见 `02-init-binder-mass-assignment.md`): - [ ] 创建 `@ControllerAdvice` 类,含 `@InitBinder` 方法 - [ ] 调用 `binder.setDisallowedFields(...)` 覆盖 6 个字段 - [ ] 不影响已有 `@ModelAttribute` 绑定的正常工作 - [ ] 编译通过 + 测试通过 ### Ticket 02 完成后解锁 Tickets 03/04/05/06 同时解锁: - **03** DictGroup Controller IO(blocked by 02) - **04** DictItem Controller IO(blocked by 02) - **05** ResourceNode 重命名为 ResourceDTO(blocked by 02) - **06** RoleController IO 改造(blocked by 02) Ticket 07(SystemController IO)blocked by 05。 ### 依赖图 ``` 01 (resolved) ──┐ ├─► 02 (ready) ──┬─► 03 │ ├─► 04 │ ├─► 05 ──► 07 │ └─► 06 └─────────────────────────────────► (done) ``` --- ## 5. Environment Notes - **Maven 路径**:`D:\apache-maven-3.9.9\bin\mvn.cmd`(不在系统 PATH 上,需用全路径调用) - **PowerShell**:不支持 `&&`,用 `;` 分隔 - **Java**:JDK 17 - **编译命令**:`cd d:\code\crm-backend-matt; D:\apache-maven-3.9.9\bin\mvn.cmd clean compile` - **测试命令**:`cd d:\code\crm-backend-matt; D:\apache-maven-3.9.9\bin\mvn.cmd test` --- ## 6. Suggested Skills | Skill | When to use | |---|---| | `/implement` | 实现 ticket 02-07,每次一个 ticket | | `/code-review` | 每个 ticket 实现后审查(Standards + Spec 双轴) | | `/diagnosing-bugs` | 如果编译或测试出现意外错误 | | `/tdd` | 如果想先写测试再实现(ticket 02 的 @InitBinder 适合 TDD) | --- ## 7. Conventions to Follow - 每个 ticket 完成后:编译 + 测试 + 提交 + 更新 ticket 状态为 `resolved` - 提交信息格式:`refactor: (ADR-0017 ticket 0N)` - 代码风格:匹配周围代码的注释密度、命名、惯用法 - 不要提交 `target/` 目录下的构建产物 - 不要提交 `.idea/` 目录下的 IDE 配置 - ADR + spec + tickets 已存在,勿重复创建,只更新