diff --git a/README.md b/README.md index 619bce2..5835873 100644 --- a/README.md +++ b/README.md @@ -392,4 +392,8 @@ docker build -t label-backend:latest . - Service 统一放在 `service/`,不拆 `service/impl` - 业务规则优先放在 Service,Controller 只负责 HTTP 协议层 - 新增接口需同步补齐 Swagger 注解与测试 +- 所有对外接口参数必须在 Swagger 中明确体现名称、类型和含义 +- 固定结构请求体禁止继续使用匿名 `Map` 或 `Map`,必须定义 DTO 并补齐 `@Schema` 字段说明 +- 固定结构响应应优先使用明确 DTO,或至少为 Swagger 暴露对象补齐字段级 `@Schema` 注解 +- 路径参数、查询参数、请求体、分页包装和通用返回体都必须维护可读的 OpenAPI 文档说明 - 目录、配置、打包方式变化后,README、设计文档和部署说明必须同步更新 diff --git a/docs/superpowers/specs/2026-04-15-label-backend-swagger-annotations-design.md b/docs/superpowers/specs/2026-04-15-label-backend-swagger-annotations-design.md new file mode 100644 index 0000000..4625f37 --- /dev/null +++ b/docs/superpowers/specs/2026-04-15-label-backend-swagger-annotations-design.md @@ -0,0 +1,301 @@ +# label_backend Swagger 参数注解与 DTO 化设计 + +> 日期:2026-04-15 +> 范围:`label_backend` 对外 REST API 的 Swagger/OpenAPI 文档增强 + +## 1. 背景 + +当前 `label_backend` 已经在 Controller 层使用了 `@Tag` 和 `@Operation`,少量 DTO 也已有 `@Schema` 注解,因此 Swagger 页面可以展示基础接口列表和部分对象结构。 + +但现状仍存在几个明显问题: + +- 很多路径参数、查询参数、表单参数缺少名称、类型、取值和含义说明 +- 多个接口仍使用 `Map` 或 `Map` 作为请求体,Swagger 无法准确展示字段名、字段类型和字段说明 +- 一些固定结构响应仍以 `Map` 返回,Swagger 只能显示匿名对象 +- 部分接口直接暴露实体类,而实体字段尚未补齐 Swagger 字段描述 +- 通用返回包装 `Result`、`PageResult` 没有字段级别文档说明 + +用户目标很明确:在 Swagger 中看到所有接口参数的名称、类型和含义。 + +## 2. 目标 + +本次改造完成后,`label_backend` 的 Swagger 页面应满足以下目标: + +- 所有公开接口都能展示清晰的路径参数、查询参数、请求头参数、表单参数说明 +- 所有固定结构的请求体都使用 DTO 建模,并为每个字段提供名称、类型、必填性和含义说明 +- 所有固定结构的主要响应对象都能展示字段说明 +- 所有分页与统一返回包装的字段含义清晰可见 +- 不改变现有接口路径、HTTP 方法和字段名称,尽量保持对现有调用方兼容 + +## 3. 非目标 + +本次不做以下事情: + +- 不重构整体业务流程 +- 不调整接口 URL、HTTP 方法和权限策略 +- 不强制把所有实体类都替换成专门的 Response DTO +- 不把完全动态的业务 JSON 全量重建成复杂深层对象,只对固定边界做显式包装 +- 不顺手做无关的代码整理或目录重构 + +## 4. 设计原则 + +### 4.1 DTO-first + +凡是 Swagger 需要清楚展示字段名、字段类型和字段说明的固定结构请求体,都应优先使用 DTO,而不是 `Map`。 + +### 4.2 文档增强优先,行为保持不变 + +本次的核心是 API 契约可读性增强,因此: + +- Controller 仍调用原有 Service +- 参数字段名保持不变 +- 业务语义、状态流转、权限校验保持不变 + +### 4.3 固定结构显式化,动态结构边界化 + +如果接口返回的是稳定字段集合,应使用明确 DTO 或明确对象字段注解。 + +如果业务内部结果本身仍是动态 JSON,则至少提供一个固定外层 DTO,把最外层字段含义说明清楚,避免 Swagger 展示匿名 `Map`。 + +### 4.4 最小可控改动 + +优先修改 Controller 入口、DTO 定义和 Swagger 展示对象,尽量不侵入 Service 深层逻辑。 + +## 5. 目标改造范围 + +### 5.1 Controller + +本次覆盖以下 10 个 Controller: + +- `AuthController` +- `CompanyController` +- `ExportController` +- `ExtractionController` +- `QaController` +- `SourceController` +- `SysConfigController` +- `TaskController` +- `UserController` +- `VideoController` + +### 5.2 通用返回模型 + +- `Result` +- `PageResult` + +### 5.3 现有 DTO + +- `LoginRequest` +- `LoginResponse` +- `SourceResponse` +- `TaskResponse` +- `UserInfoResponse` + +### 5.4 当前直接暴露给 Swagger 的实体 + +- `SysUser` +- `SysCompany` +- `SysConfig` +- `TrainingDataset` +- `ExportBatch` +- `VideoProcessJob` + +## 6. DTO 改造策略 + +### 6.1 必须从 Map 重构为 DTO 的请求体 + +以下接口应从匿名请求体改为明确 DTO: + +- `TaskController#createTask` + - 新增 `CreateTaskRequest` +- `TaskController#reassign` + - 新增 `TaskReassignRequest` +- `VideoController#createJob` + - 新增 `VideoProcessCreateRequest` +- `VideoController#handleCallback` + - 新增 `VideoProcessCallbackRequest` +- `CompanyController#update` + - 新增明确请求 DTO +- `CompanyController#updateStatus` + - 新增明确请求 DTO +- `ExportController#createBatch` + - 新增明确请求 DTO +- `UserController` 中如仍存在匿名请求体,也统一改成 DTO + +### 6.2 固定结构响应优先改为 DTO + +以下返回如果当前为 `Map` 但字段稳定,应收敛为 DTO: + +- 导出与微调相关状态响应 +- 视频回调相关固定结构响应 +- 系统配置项列表响应 + +### 6.3 动态结果场景 + +`ExtractionController` 和 `QaController` 可能仍涉及结构化 JSON 结果。处理原则如下: + +- 如果最外层字段稳定,则增加外层 DTO 说明 +- 如果内部 `items` 仍允许动态内容,则在 DTO 字段级别说明该字段承载的业务 JSON 结构 + +## 7. Swagger 注解标准 + +### 7.1 Controller 方法 + +每个接口方法统一遵循: + +- `@Tag` +- `@Operation(summary = "...", description = "...")` +- 对路径参数、查询参数、请求头参数、表单参数补 `@Parameter` +- 对请求体补 `@io.swagger.v3.oas.annotations.parameters.RequestBody` + +参数描述至少包含: + +- 参数业务含义 +- 是否必填 +- 枚举值范围或典型值 +- 分页默认值或限制条件 + +### 7.2 DTO 字段 + +所有公开请求/响应 DTO 字段统一使用: + +- `@Schema(description = "...", example = "...")` + +必要时增加: + +- `@NotNull` +- `@NotBlank` +- `@Valid` + +### 7.3 通用包装类 + +`Result` 应说明: + +- `code`:业务状态码 +- `data`:接口返回主体 +- `message`:失败或补充说明 + +`PageResult` 应说明: + +- `items`:当前页数据列表 +- `total`:总记录数 +- `page`:当前页码,从 1 开始 +- `pageSize`:每页条数 + +### 7.4 直接暴露实体 + +对于当前直接暴露给 Swagger 的实体类,给字段补齐 `@Schema` 说明,但不在本次强制转换为 Response DTO。 + +## 8. 代码组织方案 + +建议在 `dto/` 下继续保持扁平化风格,新增与接口语义一致的请求和响应类,命名以业务动作为中心,例如: + +- `CreateTaskRequest` +- `TaskReassignRequest` +- `VideoProcessCreateRequest` +- `VideoProcessCallbackRequest` +- `CompanyUpdateRequest` +- `CompanyStatusUpdateRequest` +- `ExportBatchCreateRequest` + +如果某个响应只在单个 Controller 使用,但字段固定,也放在 `dto/` 下,而不是内联 `Map`。 + +## 9. 兼容性要求 + +为了避免影响现有调用方,本次必须满足: + +- 接口 URL 不变 +- HTTP 方法不变 +- JSON 字段名称不变 +- Multipart 参数名不变 +- 路径参数名和查询参数名不变 + +DTO 只是显式建模现有契约,不是重新设计契约。 + +## 9.1 README 约束同步 + +本次设计不仅要求代码层落地,还要求将 Swagger/DTO 约束写入项目 `README.md` 的开发规范中,作为后续接口开发的长期规则。 + +README 中至少应明确以下要求: + +- 所有对外接口参数必须在 Swagger 中清楚展示名称、类型和含义 +- 固定结构请求体禁止继续使用匿名 `Map`,必须定义 DTO +- 固定结构响应应优先显式建模,避免 Swagger 展示匿名对象 +- 通用返回体和分页包装也必须维护字段说明 + +## 10. 测试策略 + +由于本次会把匿名请求体改为 DTO,需要用测试确认请求绑定行为没有被改坏。 + +测试策略如下: + +- 优先补或更新 Controller 测试 +- 覆盖 DTO 替换后的 JSON 反序列化 +- 验证关键接口的请求字段名保持不变 +- 验证原有成功路径和主要失败路径仍成立 + +至少应覆盖: + +- 创建任务 +- 重指派任务 +- 创建视频处理任务 +- 接收视频回调 +- 创建导出批次 +- 公司更新和状态更新 + +## 11. 风险与处理 + +### 11.1 风险:字段名不一致导致请求绑定失败 + +处理方式: + +- DTO 字段严格对齐当前请求 JSON 的既有字段名 +- 使用 Controller 测试验证兼容性 + +### 11.2 风险:动态 JSON 过度 DTO 化,导致业务边界变复杂 + +处理方式: + +- 只对固定边界建模 +- 动态业务内容保留为受控字段,不做过度深挖 + +### 11.3 风险:实体类字段太多,注解工作量大 + +处理方式: + +- 只处理当前实际暴露到 Swagger 的实体 +- 优先处理高频接口涉及对象 + +## 12. 实施顺序 + +推荐按以下顺序实施: + +1. 给 `Result`、`PageResult` 补齐字段说明 +2. 给已有公开 DTO 补齐 `@Schema` +3. 将匿名请求体改造成 DTO,并更新对应 Controller +4. 将固定结构的 `Map` 响应改造成 DTO +5. 为直接暴露的实体补齐 `@Schema` +6. 统一补齐 Controller 参数 `@Parameter` 注解 +7. 更新或新增相关测试并执行验证 + +## 13. 验收标准 + +验收通过应满足以下条件: + +- Swagger 页面中所有公开接口参数都能看到名称、类型和含义 +- 所有固定结构请求体不再以匿名 `Map` 展示 +- 主要响应对象字段说明齐全 +- 通用返回体字段说明齐全 +- `README.md` 已写入 Swagger/DTO 文档约束 +- Controller 相关测试通过 +- 未引入接口路径或字段名兼容性破坏 + +## 14. 决策总结 + +本次采用“DTO-first API 文档化”方案: + +- 请求体优先 DTO 化 +- 固定结构响应优先显式建模 +- Controller 参数注释统一化 +- 通用返回体和当前暴露实体补齐 Swagger 字段说明 +- 在不改变业务语义的前提下,最大化提升 Swagger 可读性和接口契约清晰度