---
name: backend-go-gin-gorm

description: >
  使用 Gin + GORM 生成、编写、修改、评审 production-ready 的 Go 后端代码（Generate & Review Go backend code with Gin/GORM）。
  强制分层架构 handler → service → dao/repository（避免业务逻辑堆在 handler；DAO/Repo 只做数据访问与查询组装），并统一 API 响应包装
  consistent response envelope（code/message/data + request_id/trace_id 等可观测字段）。接口风格默认推荐 POST + JSON RequestBody
  as default（必要时遵循 REST 语义与幂等约定），规范 DTO/VO/DO 命名与字段映射 conventions（入参 DTO、出参 VO、持久化 DO/Model）。
  代码注释使用中文（Chinese comments for maintainability），时间处理默认 Asia/Shanghai（time zone aware time handling），
  采用结构化日志 structured logging（携带 request_id/trace_id/user_id/path/latency 等上下文），并遵循 Gin/GORM 工程化最佳实践
  (transactions, context propagation, error wrapping, pagination, soft delete, optimistic locking when needed)。
  触发场景 Trigger: Go 后端开发 / Gin Handler 创建 / GORM DAO/Repository 实现 / 代码走查与 Review（refactor suggestions, bug fixes, performance tips）。

argument-hint: "<动作 action> <目标 target>" 例如/ e.g.:
  "create user-handler", "review service/order.go", "scaffold api/v1/product", "add repo for table/users", "optimize gorm query"

allowed-tools:
  - Read
  - Write
  - Edit
  - Glob
  - Grep
  - Bash

---

# Go GIN/GORM 开发规范 Skill

## 触发条件
- 用户请求创建/修改 Go 后端代码
- 用户请求代码审查
- 用户提及 API 开发、数据库操作、统一响应、日志、时间处理
- 用户请求设计 API 接口、DTO 结构

## 上下文收集

执行前先收集项目信息：

!`ls -la go.mod go.sum 2>/dev/null || echo "No go.mod found"`

!`head -20 go.mod 2>/dev/null || echo ""`

## $ARGUMENTS 解析

期望格式：`<action> <target>`

| action | 说明 |
|--------|------|
| `create` | 创建新文件（handler/service/dao/dto） |
| `review` | 审查现有代码 |
| `scaffold` | 生成完整模块骨架 |
| `fix` | 修复不符合规范的代码 |

---

## Plan 阶段

### 产物清单（按 action 确定）

| action | 产物 |
|--------|------|
| `create handler` | `/api/xxx_handler.go` 或 `/internal/handler/xxx.go` |
| `create service` | `/internal/service/xxx_service.go` |
| `create dao` | `/internal/dao/xxx_dao.go` |
| `create dto` | `/internal/model/dto/xxx_dto.go` |
| `scaffold` | 上述全部 + entity |

### 决策点

1. **目录风格**：检查项目是用 `/api` 还是 `/internal/handler`
2. **模块命名**：从 $ARGUMENTS 提取资源名（如 `user`、`order`）
3. **是否已存在**：先 Glob 检查目标文件

---

## Execute 阶段

### Handler 层编写规则

```
1. 仅做：参数解析 → 调用 service → 返回响应
2. 禁止：编写业务逻辑、直接操作数据库
3. 必须：使用 common.ResponseSuccess / common.ResponseError
4. 错误处理：gorm.ErrRecordNotFound → CodeNotFound
```

### Service 层编写规则

```
1. 编排 dao 层完成业务
2. 记录关键业务日志（Info 级别）
3. 错误包装：fmt.Errorf("xxx: %w", err)
4. 业务异常记录 Warning 级别日志
```

### DAO 层编写规则

```
1. 封装所有 GORM 操作
2. 禁止在 service 层写 SQL
3. 复杂查询用 Raw/Exec
4. 善用链式调用，但复杂场景优先原生 SQL
```

### 统一响应格式（强制）

```go
// 成功
common.ResponseSuccess(c, data)
common.ResponseSuccessWithMessage(c, data, "创建成功")

// 失败
common.ResponseError(c, common.CodeParamError, "参数错误")
common.ResponseErrorWithDetail(c, common.CodeServerError, "系统错误", err)
```

错误码定义 → 读取 `reference/error-codes.go`

### 注释规范（强制中文）

```go
// GetUserByID 根据用户ID获取用户信息
// @param ctx context.Context - 请求上下文
// @param userID int64 - 用户唯一ID
// @return *model.User - 用户信息,未找到返回nil
// @return error - 查询错误
func (s *UserService) GetUserByID(ctx context.Context, userID int64) (*model.User, error)
```

---

## API 设计规范（强制）

### 核心原则：POST + RequestBody

```
所有 API 优先使用 POST 方法，参数通过 RequestBody 传递
避免使用 PathVariables 和 RequestParams
```

### 禁止与推荐

| 禁止 | 推荐 |
|------|------|
| `GET /api/projects/{project_id}` | `POST /api/projects/detail` + RequestBody |
| `GET /api/users?role=admin&page=1` | `POST /api/users/list` + RequestBody |
| URL 中传递敏感信息 | RequestBody 传递所有参数 |

### API 路径命名规范

| 操作 | 后缀 | 示例 |
|------|------|------|
| 列表查询 | `/list` | `POST /api/projects/list` |
| 详情查询 | `/detail` | `POST /api/projects/detail` |
| 创建 | `/create` | `POST /api/projects/create` |
| 更新 | `/update` | `POST /api/projects/update` |
| 删除 | `/delete` | `POST /api/projects/delete` |
| 同步 | `/sync` | `POST /api/jenkins/organizations/sync` |
| 触发 | `/trigger` | `POST /api/builds/trigger` |

### DTO 命名规范

| 类型 | 命名格式 | 示例 |
|------|----------|------|
| 列表请求 | `List{资源}Request` | `ListBuildsRequest` |
| 详情请求 | `Get{资源}Request` | `GetBuildRequest` |
| 创建请求 | `Create{资源}Request` | `CreateProjectRequest` |
| 更新请求 | `Update{资源}Request` | `UpdateProjectRequest` |
| 删除请求 | `Delete{资源}Request` | `DeleteProjectRequest` |
| 列表响应 | `List{资源}Response` | `ListBuildsResponse` |
| 详情响应 | `{资源}DetailResponse` | `BuildDetailResponse` |

### 通用分页结构

```go
// 请求
type PageRequest struct {
    Page     int `json:"page" binding:"required,min=1"`
    PageSize int `json:"page_size" binding:"required,min=1,max=100"`
}

// 响应
type ListResponse struct {
    List     []interface{} `json:"list"`
    Total    int64         `json:"total"`
    Page     int           `json:"page"`
    PageSize int           `json:"page_size"`
}
```

### 模块错误码范围

| 范围 | 模块 |
|------|------|
| 0 | 成功 |
| 1000-1999 | 通用错误 |
| 2000-2999 | 用户/权限 |
| 3000-3999 | Jenkins |
| 4000-4999 | 项目管理 |
| 5000-5999 | Exchange-Hub |

详细规范 → 读取 `reference/api-design-spec.md`

---

## 日志规范（强制）

### 指定框架
项目统一使用 `rmdc-common/wdd_log/log_utils.go`

### 日志级别使用场景

| 级别 | 使用场景 | 示例 |
|------|----------|------|
| `Debug` | 开发调试，详细流程、变量值 | `log.Debug(ctx, "查询参数", map[string]interface{}{"userID": id})` |
| `Info` | 关键业务节点 | `log.Info(ctx, "用户登录成功", ...)` / `log.Info(ctx, "订单创建成功", ...)` |
| `Warning` | 可预期非致命异常，程序可继续 | `log.Warning(ctx, "外部API超时,启用备用方案", ...)` |
| `Error` | 严重错误，业务流程中断 | `log.Error(ctx, "数据库连接失败", ...)` 必须记录堆栈 |

### 日志内容要求
```
1. 简练、关键
2. 必须包含 TraceID、UserID 等追溯信息
3. Error 级别必须记录完整错误堆栈
```

### 日志记录位置

| 层级 | 记录内容 |
|------|----------|
| Handler | 使用 `ResponseErrorWithDetail` 自动记录 Error 日志 |
| Service | 关键业务操作记录 Info；业务异常记录 Warning |
| DAO | 一般不记录日志，错误向上抛出 |

---

## 时间处理（强制东八区）

### 核心规则
```
时区：Asia/Shanghai (UTC+8)
格式：RFC3339
```

### 禁止与必须

| 禁止 | 必须使用 |
|------|----------|
| `time.Now()` | `TimeUtils.Now()` |
| `time.Parse()` | `TimeUtils.Parse()` |
| 直接格式化 | `TimeUtils.Format()` |

### 工具库位置
- 后端：`rmdc-common/utils/TimeUtils.go`
- 前端：`TonyMask/src/utils/timeUtils.ts`

### 使用示例
```go
// ✅ 正确
now := TimeUtils.Now()
timestamp := TimeUtils.Now().Format(time.RFC3339)

// ❌ 错误
now := time.Now()  // 禁止直接使用
```

---

## 框架使用规范

### GIN 框架

#### 路由组织（强制分组）
```go
// ✅ 正确：使用路由分组
v1 := r.Group("/api/v1")
{
    users := v1.Group("/users")
    {
        users.GET("/:id", userHandler.GetByID)
        users.POST("/", userHandler.Create)
    }
}

// ❌ 错误：扁平路由
r.GET("/api/v1/users/:id", ...)
```

#### 中间件使用
```go
// 全局中间件
r.Use(middleware.Recovery())  // 恢复
r.Use(middleware.Logger())    // 日志
r.Use(middleware.CORS())      // 跨域

// 路由组中间件
authGroup := r.Group("/admin")
authGroup.Use(middleware.Auth())
```

#### 响应规范
```
所有 API 响应必须通过 pkg/common 统一响应函数
禁止直接使用 c.JSON()、c.String() 等
```

### GORM 框架

#### 操作位置
```
所有 GORM 操作必须在 dao 层
严禁在 service 层拼接查询
```

#### 链式调用 vs 原生 SQL

| 场景 | 推荐方式 |
|------|----------|
| 简单 CRUD | 链式调用 `db.Where().First()` |
| 复杂查询（多表 JOIN、子查询） | `Raw()` / `Exec()` 原生 SQL |
| 批量操作 | `Raw()` / `Exec()` 保证性能 |

```go
// 简单查询 - 链式调用
db.Where("status = ?", 1).Find(&users)

// 复杂查询 - 原生 SQL
db.Raw(`
    SELECT u.*, COUNT(o.id) as order_count
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
    WHERE u.status = ?
    GROUP BY u.id
`, 1).Scan(&results)
```

#### 错误处理
```go
// 必须处理 ErrRecordNotFound
if errors.Is(err, gorm.ErrRecordNotFound) {
    common.ResponseError(c, common.CodeNotFound, "资源不存在")
    return
}
```

---

## Verify 阶段 Checklist

### 结构检查
- [ ] 依赖方向正确：handler → service → dao（无反向引用）
- [ ] handler 层无业务逻辑
- [ ] dao 层无 service 引用
- [ ] 使用 internal 包保护私有代码

### 响应检查
- [ ] 所有 API 使用 `common.ResponseSuccess/Error`
- [ ] 错误码来自 `common.Code*` 常量
- [ ] 时间戳格式为 RFC3339
- [ ] 无直接 `c.JSON()` 调用

### 代码检查
- [ ] 公开函数/结构体有中文注释
- [ ] 注释格式：`// 函数名 功能描述`
- [ ] 无直接 `time.Now()` 调用
- [ ] 无丢弃的 error（`_ = err` 禁止）
- [ ] 包名小写无下划线

### 日志检查
- [ ] 使用项目统一日志库
- [ ] Error 日志包含完整堆栈
- [ ] 关键业务操作有 Info 日志
- [ ] 日志包含 TraceID 等追溯信息

### GORM 检查
- [ ] `gorm.ErrRecordNotFound` 已处理
- [ ] 复杂查询在 dao 层使用 Raw/Exec
- [ ] 无 service 层直接 DB 操作

### GIN 检查
- [ ] 使用路由分组组织 API
- [ ] 通用逻辑使用中间件处理
- [ ] 响应通过统一函数返回

### API 设计检查
- [ ] 使用 POST + RequestBody（非 GET + PathVariables）
- [ ] API 路径使用正确后缀（/list, /detail, /create 等）
- [ ] DTO 命名符合规范（List/Get/Create/Update/Delete + 资源 + Request/Response）
- [ ] 分页请求嵌入 PageRequest
- [ ] 分页响应包含 list/total/page/page_size
- [ ] 敏感信息不在 URL 中
- [ ] 请求体必须验证（ShouldBindJSON）

---

## 常见陷阱

| 陷阱 | 正确做法 |
|------|----------|
| handler 写业务逻辑 | 移到 service 层 |
| 直接 `c.JSON()` | 用 `common.ResponseSuccess()` |
| 忽略 `ErrRecordNotFound` | 转为 `CodeNotFound` 返回 |
| `time.Now()` | `TimeUtils.Now()` |
| 英文注释 | 改为中文 |
| dao 引用 service | 违反依赖原则，重构 |
| service 写 SQL | 移到 dao 层 |
| 扁平路由 | 使用 Router Group |
| 日志缺少上下文 | 添加 TraceID、UserID |
| Error 日志无堆栈 | 记录完整错误信息 |
| `GET /api/users/{id}` | `POST /api/users/detail` + RequestBody |
| URL 传参数 `?page=1` | RequestBody 传递 |
| DTO 命名不规范 | 使用 `List/Get/Create/Update/Delete` + 资源名 |
| 敏感信息在 URL | 移到 RequestBody |

---

## Reference 文件索引

| 场景 | 读取文件 |
|------|----------|
| 需要完整目录结构说明 | `reference/project-structure.md` |
| 需要响应结构体定义 | `reference/api-response-spec.md` |
| 需要错误码完整列表 | `reference/error-codes.go` |
| 需要编码规范细节 | `reference/coding-standards.md` |
| 需要日志使用详细说明 | `reference/logging-standards.md` |
| 需要时间处理详细说明 | `reference/time-handling.md` |
| 需要框架使用详细说明 | `reference/framework-usage.md` |
| 需要 API 设计详细说明 | `reference/api-design-spec.md` |
| 需要代码示例 | `examples/*.go` |

---

## 快速命令

验证项目结构：
```bash
./scripts/validate-structure.sh
```
