# 框架使用规范

## GIN 框架

### 路由组织

#### 强制使用路由分组 (Router Group)

```go
func SetupRouter(r *gin.Engine) {
    // API 版本分组
    v1 := r.Group("/api/v1")
    {
        // 用户模块
        users := v1.Group("/users")
        {
            users.GET("/", userHandler.List)
            users.GET("/:id", userHandler.GetByID)
            users.POST("/", userHandler.Create)
            users.PUT("/:id", userHandler.Update)
            users.DELETE("/:id", userHandler.Delete)
        }

        // 订单模块
        orders := v1.Group("/orders")
        {
            orders.GET("/", orderHandler.List)
            orders.GET("/:id", orderHandler.GetByID)
            orders.POST("/", orderHandler.Create)
        }
    }
}
```

#### 禁止扁平路由

```go
// ❌ 错误：扁平路由，难以维护
r.GET("/api/v1/users", ...)
r.GET("/api/v1/users/:id", ...)
r.POST("/api/v1/users", ...)
r.GET("/api/v1/orders", ...)
```

### 中间件使用

#### 全局中间件

```go
func SetupMiddleware(r *gin.Engine) {
    // Recovery - 恢复 panic，防止程序崩溃
    r.Use(middleware.Recovery())

    // Logger - 请求日志记录
    r.Use(middleware.Logger())

    // CORS - 跨域处理
    r.Use(middleware.CORS())

    // TraceID - 请求追踪
    r.Use(middleware.TraceID())
}
```

#### 路由组中间件

```go
// 需要认证的路由组
authGroup := r.Group("/api/v1/admin")
authGroup.Use(middleware.Auth())
{
    authGroup.GET("/dashboard", adminHandler.Dashboard)
    authGroup.GET("/users", adminHandler.ListUsers)
}

// 需要特定权限的路由组
superAdmin := authGroup.Group("/super")
superAdmin.Use(middleware.RequireRole("super_admin"))
{
    superAdmin.DELETE("/users/:id", adminHandler.DeleteUser)
}
```

#### 常用中间件职责

| 中间件 | 职责 |
|--------|------|
| Recovery | 捕获 panic，返回 500 错误 |
| Logger | 记录请求日志（方法、路径、耗时等） |
| CORS | 处理跨域请求 |
| Auth | 验证用户身份（JWT/Session） |
| TraceID | 生成/传递请求追踪 ID |
| RateLimit | 请求频率限制 |

### 响应规范

#### 强制使用统一响应

```go
// ✅ 正确：使用统一响应函数
common.ResponseSuccess(c, data)
common.ResponseError(c, common.CodeParamError, "参数错误")

// ❌ 错误：直接使用 GIN 原生方法
c.JSON(200, data)
c.String(200, "success")
c.AbortWithStatusJSON(400, gin.H{"error": "bad request"})
```

---

## GORM 框架

### 操作位置规范

```
所有 GORM 操作必须在 dao 层实现
严禁在 service 层直接操作数据库
```

### 查询方式选择

#### 简单 CRUD - 链式调用

```go
// 单条查询
var user entity.User
db.Where("id = ?", userID).First(&user)

// 列表查询
var users []entity.User
db.Where("status = ?", 1).
    Order("created_at DESC").
    Limit(10).
    Offset(0).
    Find(&users)

// 创建
db.Create(&user)

// 更新
db.Model(&user).Updates(map[string]interface{}{
    "name":   "new name",
    "status": 1,
})

// 删除
db.Delete(&user, userID)
```

#### 复杂查询 - Raw/Exec

**推荐场景**：
- 多表 JOIN
- 子查询
- 复杂聚合
- 批量操作
- 性能敏感场景

```go
// 多表 JOIN 查询
type UserWithOrderCount struct {
    entity.User
    OrderCount int64 `json:"order_count"`
}

var results []UserWithOrderCount
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
    ORDER BY order_count DESC
    LIMIT ?
`, 1, 10).Scan(&results)

// 批量更新
db.Exec(`
    UPDATE orders
    SET status = ?
    WHERE user_id = ? AND status = ?
`, "completed", userID, "pending")

// 复杂子查询
db.Raw(`
    SELECT * FROM users
    WHERE id IN (
        SELECT user_id FROM orders
        WHERE amount > ?
        GROUP BY user_id
        HAVING COUNT(*) > ?
    )
`, 1000, 5).Scan(&users)
```

### 错误处理

#### 必须处理 ErrRecordNotFound

```go
// DAO 层
func (d *UserDAO) FindByID(ctx context.Context, id int64) (*entity.User, error) {
    var user entity.User
    if err := d.db.WithContext(ctx).First(&user, id).Error; err != nil {
        return nil, err  // 包含 ErrRecordNotFound
    }
    return &user, nil
}

// Handler 层
user, err := h.userService.GetUserByID(ctx, userID)
if err != nil {
    if errors.Is(err, gorm.ErrRecordNotFound) {
        common.ResponseError(c, common.CodeNotFound, "用户不存在")
        return
    }
    common.ResponseErrorWithDetail(c, common.CodeServerError, "查询失败", err)
    return
}
```

### 事务处理

```go
// Service 层事务
func (s *OrderService) CreateOrder(ctx context.Context, req *dto.CreateOrderRequest) error {
    return s.db.Transaction(func(tx *gorm.DB) error {
        // 1. 创建订单
        order := &entity.Order{...}
        if err := tx.Create(order).Error; err != nil {
            return fmt.Errorf("创建订单失败: %w", err)
        }

        // 2. 扣减库存
        if err := tx.Model(&entity.Product{}).
            Where("id = ? AND stock >= ?", req.ProductID, req.Quantity).
            Update("stock", gorm.Expr("stock - ?", req.Quantity)).Error; err != nil {
            return fmt.Errorf("扣减库存失败: %w", err)
        }

        // 3. 创建支付记录
        payment := &entity.Payment{...}
        if err := tx.Create(payment).Error; err != nil {
            return fmt.Errorf("创建支付记录失败: %w", err)
        }

        return nil
    })
}
```

### Context 传递

```go
// 必须使用 WithContext 传递上下文
db.WithContext(ctx).First(&user, id)
db.WithContext(ctx).Create(&order)

// 支持超时控制和取消
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
db.WithContext(ctx).Find(&users)
```
