# Model / Request / Response 组织规范 ## 适用范围 - 判断项目中的 `vo`、实体、接口入参、接口出参应该落在哪一层时,使用本文。 - 新增或修改业务模块的 `model/`、`model//request`、`model//response` 时,使用本文。 - 判断某个 API 是直接复用实体,还是新增 `request/response` 结构时,使用本文。 ## 结论基线 - 本项目不单独维护顶层 `vo` 目录。 - 项目里的数据载体统一归到 `model` 体系,不额外拆一套平行 `vo` 层。 - 标准落点如下: | 场景 | 落点 | 说明 | |:---|:---|:---| | 数据库实体 / 业务实体 | `model/` | 承载表结构映射、业务实体字段 | | API 入参 | `model//request` | 承载查询条件、分页条件、保存参数等 | | API 出参 | `model//response` | 承载详情包装、列表项包装、聚合展示结构等 | | 跨模块通用入参 | `model/common/request` | 例如 `PageInfo`、`GetById`、`IdsReq` | | 跨模块通用出参 | `model/common/response` | 例如统一响应壳、分页结果 | ## 判定规则 - 请求参数如果就是业务实体本身,且不会引入多余字段、敏感字段或语义歧义,可以直接复用 `model/` 实体。 - 请求参数如果只是“分页 + 条件筛选 + 排序”这类接口 contract,应定义到 `model//request`。 - 返回结果如果只是直接返回实体本身,可以直接返回实体或列表,不强制为了“像 VO”再包一层空结构。 - 返回结果如果需要额外包装、聚合字段、嵌套结构、展示字段转换,应定义到 `model//response`。 - 多个 API 只要 contract 一致,可以共用同一个 `request` 或 `response` 结构;不是每个 API 都必须单独建一份。 ## 强制规则 - 新增业务模块时,实体统一放 `model/`;禁止把实体落到 `api`、`service`、`router`。 - `API` 层入参、出参需要独立结构时,统一放 `model//request`、`model//response`;禁止在 `API` 文件里长期维护临时匿名结构体当正式 contract。 - 跨模块都能稳定复用的分页、主键、统一响应、分页结果等结构,统一复用 `model/common/request`、`model/common/response`;不要每个模块各复制一份。 - 同一业务模块如果同时存在 `admin/app` 两套接口,实体仍统一放 `model/`;只有 `request/response` 按 `admin` / `app` 分文件区分。 - 新增 `request/response` 前,先检查同模块现有结构是否可复用;只有接口字段、校验语义、返回语义明显不同,才新增结构。 - 改实体字段时,必须同步检查 `service` 查询/写入、`API` 绑定/返回、`doc-sql` 是否仍一致。 - 改 `request/response` 时,必须同步检查 `API` 绑定、`Service` 方法签名、`doc-api` 是否仍一致。 ## 推荐做法 - `Create`、`Update` 这类保存接口,如果直接面向实体字段,可优先复用实体。 - `GetList`、搜索、筛选、排序接口,优先使用 `request` 结构,不要把分页筛选字段硬塞进实体。 - `Find`、详情、聚合展示、树结构、联表结果等返回,优先使用 `response` 结构,不要把纯展示字段反向塞进数据库实体。 - `response` 结构命名优先体现业务语义,例如 `BookDetailResponse`、`BookListItem`、`AuthorOption`;不要机械统一叫 `XxxVO`。 ## 禁止事项 - 禁止单独新建顶层 `vo` 目录,与 `model` 并行维护两套数据结构体系。 - 禁止为了“每个 API 都有专属 VO”而机械性给每个接口复制一份几乎相同的 `request/response`。 - 禁止把分页、排序、筛选字段直接加进数据库实体,只为了省掉 `request` 结构。 - 禁止把纯展示字段、聚合字段、临时返回字段长期塞进实体,只为了省掉 `response` 结构。 - 禁止 `API`、`Service` 长期返回 `map[string]interface{}`、`gin.H` 充当正式业务出参,导致 contract 漂移。