---
name: dto-standards
description: DTO 数据传输对象规范。创建或修改 DTO 文件、请求/响应结构时使用。包含 description 标签、枚举字段、验证标签等规范。
---

# DTO 规范

**所有 DTO 文件必须遵循以下规范，这是 API 文档生成的基础。**

## 触发条件

在以下情况下必须遵守本规范：
- 创建或修改 `internal/model/` 下的请求/响应 DTO
- 创建 `XXXRequest`、`XXXResponse`、`XXXReq`、`XXXResp` 结构体
- 添加或修改 API 接口的输入输出参数

---

## 必须项（MUST）

### 1. Description 标签规范

**所有字段必须使用 `description` 标签，禁止使用行内注释**

❌ **错误**：
```go
type CreateUserRequest struct {
    Username string `json:"username"` // 用户名
    Status   int    `json:"status"`   // 状态
}
```

✅ **正确**：
```go
type CreateUserRequest struct {
    Username string `json:"username" description:"用户名"`
    Status   int    `json:"status" description:"状态 (0:禁用, 1:启用)"`
}
```

### 2. 枚举字段：int vs string 选择

**必须按以下规则选择类型，禁止混用：**

| 场景 | 类型 | 示例 |
|------|------|------|
| 状态类（生命周期阶段） | `int` | 待支付→已完成→已关闭 |
| 布尔状态（启用/禁用） | `int` | `0=禁用, 1=启用` |
| 类型/方式类（种类） | `string` | `"wechat"`, `"single_card"` |
| 平台/标识符类 | `string` | `"web"`, `"h5"`, `"all"` |

```go
// ✅ 状态 → int
Status        int    `json:"status"`
PaymentStatus int    `json:"payment_status"`

// ✅ 类型/方式 → string
PaymentMethod string `json:"payment_method" validate:"required,oneof=wechat offline"`
OrderType     string `json:"order_type"     validate:"required,oneof=single_card device"`
```

### 3. Int 状态值约定

#### 3.1 通用禁用/启用

**必须用全局常量，禁止自定义（尤其禁止 1=启用 2=禁用 这种反向写法）**：

```go
// pkg/constants/constants.go 已定义，直接使用
StatusDisabled = 0 // 禁用
StatusEnabled  = 1 // 启用
```

✅ 正确：`description:"状态 (0:禁用, 1:启用)"`
❌ 禁止：`description:"状态 (1:启用, 2:禁用)"`

#### 3.2 生命周期状态

从 **1** 开始递增，0 不使用（避免与 Go 零值混淆）：

```go
const (
    RechargeStatusPending   = 1 // 待支付
    RechargeStatusPaid      = 2 // 已支付
    RechargeStatusCompleted = 3 // 已完成
    RechargeStatusClosed    = 4 // 已关闭
)
```

### 4. 枚举列表必须从 constants 原文抄写

**DTO description 的枚举列表必须与 `pkg/constants/` 定义完全一致，不可凭记忆填写。**

操作步骤：
1. 先查/定义 `pkg/constants/` 中的枚举常量
2. 将常量注释**原文抄写**到 description

```go
// constants.go 中：
RechargeStatusPending   = 1 // 待支付
RechargeStatusPaid      = 2 // 已支付
RechargeStatusCompleted = 3 // 已完成
RechargeStatusClosed    = 4 // 已关闭
RechargeStatusRefunded  = 5 // 已退款

// DTO description 从上面抄：
Status int `json:"status" description:"状态 (1:待支付, 2:已支付, 3:已完成, 4:已关闭, 5:已退款)"`
```

❌ 禁止（description 与 constants 不一致，是历史 bug 的根因）：
```go
// constants 说 3=已完成，description 却写 3:已取消
Status int `json:"status" description:"状态 (1:待支付, 2:已完成, 3:已取消)"`
```

### 5. description 格式标准

**统一格式**：`字段含义 (值1:中文含义1, 值2:中文含义2)`

- 值与含义之间用**冒号** `:`（禁止用等号 `=`）
- 多个值之间用**逗号加空格** `, `
- 含义必须是**中文**

```go
// ✅ 统一格式
Status       int    `description:"状态 (1:待支付, 2:已支付, 3:已完成)"`
Platform     string `description:"适用端口 (all:全部, web:Web后台, h5:H5端)"`

// ❌ 格式混乱
Status int `description:"状态 (0=禁用, 1=启用)"`     // 用等号
Status int `description:"0=禁用 1=启用"`             // 无括号无逗号
```

### 6. Response DTO 的状态字段必须同时返回 int 和 text

**所有 Response DTO 中的 int 状态字段，必须同时提供对应的 `_name` 文字字段。**

原因：防止前端维护映射表出错（历史上已有因此产生 bug 的案例）。

```go
// ✅ Response DTO 标准写法
type XxxResponse struct {
    Status     int    `json:"status"      description:"状态 (1:待支付, 2:已支付, 3:已完成, 4:已关闭, 5:已退款)"`
    StatusName string `json:"status_name" description:"状态名称（中文）"`
}

// toResponse 函数中赋值
func rechargeStatusName(status int) string {
    switch status {
    case constants.RechargeStatusPending:
        return "待支付"
    case constants.RechargeStatusCompleted:
        return "已完成"
    // ...
    default:
        return "未知"
    }
}
```

字段命名约定：`status` → `status_name`，`payment_status` → `payment_status_name`

**例外**：Request DTO（查询过滤、创建请求）不需要 `_name` 字段。

### 7. 验证标签与 OpenAPI 标签一致

```go
Username string `json:"username" validate:"required,min=3,max=50" required:"true" minLength:"3" maxLength:"50" description:"用户名"`
```

| validate 标签 | OpenAPI 标签 |
|--------------|--------------|
| `required` | `required:"true"` |
| `min=N,max=M`（数值） | `minimum:"N" maximum:"M"` |
| `min=N,max=M`（字符串） | `minLength:"N" maxLength:"M"` |
| `oneof=A B C` | description 中说明枚举值 |

### 8. 请求参数类型标签

```go
// Query 参数
type ListRequest struct {
    Page   int  `json:"page"  query:"page"  validate:"omitempty,min=1" minimum:"1" description:"页码"`
    Status *int `json:"status" query:"status" validate:"omitempty,min=1,max=4" minimum:"1" maximum:"4" description:"状态 (1:待支付, 2:已支付, 3:已完成, 4:已关闭)"`
}

// Path 参数
type IDReq struct {
    ID uint `path:"id" description:"ID" required:"true"`
}
```

### 9. 响应 DTO 完整性

```go
type AccountResponse struct {
    ID         uint   `json:"id"          description:"账号ID"`
    Username   string `json:"username"    description:"用户名"`
    UserType   int    `json:"user_type"   description:"用户类型 (1:超级管理员, 2:平台用户, 3:代理账号, 4:企业账号)"`
    Status     int    `json:"status"      description:"状态 (0:禁用, 1:启用)"`
    StatusName string `json:"status_name" description:"状态名称（中文）"`
    CreatedAt  string `json:"created_at"  description:"创建时间"`
    UpdatedAt  string `json:"updated_at"  description:"更新时间"`
}
```

---

## AI 助手必须执行的检查

**在创建或修改任何 DTO 文件后，必须执行以下检查：**

1. ✅ 所有字段有 `description` 标签（无行内注释）
2. ✅ 枚举类型选择正确（状态用 int，类型/方式用 string）
3. ✅ 禁用/启用使用 `0=禁用, 1=启用`（禁止 1=启用 2=禁用）
4. ✅ description 枚举列表已从 `pkg/constants/` 原文抄写，无遗漏
5. ✅ description 格式统一（冒号 `:`，括号，逗号）
6. ✅ Response DTO 有 `_name` 伴生字段
7. ✅ validate 标签与 OpenAPI 标签一致
8. ✅ 重新生成 OpenAPI 文档验证：`go run cmd/gendocs/main.go`

**完整枚举规范**: 参见 [`docs/enum-status-standards.md`](../../docs/enum-status-standards.md)

---

## 常见枚举字段标准值

```go
// 用户类型（从 constants.UserType* 抄）
description:"用户类型 (1:超级管理员, 2:平台用户, 3:代理账号, 4:企业账号)"

// 通用启用/禁用（从 constants.StatusEnabled/Disabled 抄）
description:"状态 (0:禁用, 1:启用)"

// 充值状态（从 constants.RechargeStatus* 抄）
description:"状态 (1:待支付, 2:已支付, 3:已完成, 4:已关闭, 5:已退款)"

// 权限类型
description:"权限类型 (1:菜单, 2:按钮)"

// 适用端口
description:"适用端口 (all:全部, web:Web后台, h5:H5端)"

// 店铺层级
description:"店铺层级 (1-7级)"
```
