--- globs: backend/*,backend/**/*.go alwaysApply: false --- # Go-Zero 框架开发规则 ## 🚀 架构规范 ### 核心概念 - **Handler**: HTTP请求处理层,只做参数验证和调用Logic - **Logic**: 业务逻辑层,包含核心业务代码 - **Model**: 数据访问层,处理数据库操作 - **Types**: 请求/响应类型定义 ### 文件结构 ``` backend/ ├── cmd/api/main.go # 服务启动入口 ├── etc/photography-api.yaml # 配置文件 ├── api/desc/ # API定义文件 ├── internal/ │ ├── handler/ # HTTP处理器 │ ├── logic/ # 业务逻辑 │ ├── model/ # 数据模型 │ ├── middleware/ # 中间件 │ ├── svc/ # 服务上下文 │ └── types/ # 类型定义 └── pkg/ # 工具包 ``` ## 🎯 开发流程 ### 1. API定义 在 `api/desc/` 目录下定义接口: ```api service photography-api { @handler uploadPhoto post /api/v1/photos (UploadPhotoRequest) returns (UploadPhotoResponse) } type UploadPhotoRequest { Title string `form:"title"` Description string `form:"description,optional"` File string `form:"file"` } type UploadPhotoResponse { Id string `json:"id"` Title string `json:"title"` Filename string `json:"filename"` Thumbnail string `json:"thumbnail"` } ``` ### 2. 代码生成 ```bash cd backend make api # 生成handler和logic骨架 ``` ### 3. Handler实现 ```go func (h *UploadPhotoHandler) UploadPhoto(w http.ResponseWriter, r *http.Request) { var req types.UploadPhotoRequest if err := httpx.Parse(r, &req); err != nil { httpx.ErrorCtx(r.Context(), w, err) return } l := logic.NewUploadPhotoLogic(r.Context(), h.svcCtx) resp, err := l.UploadPhoto(&req) response.Response(w, resp, err) } ``` ### 4. Logic实现 ```go func (l *UploadPhotoLogic) UploadPhoto(req *types.UploadPhotoRequest) (*types.UploadPhotoResponse, error) { // 1. 参数验证 if req.Title == "" { return nil, errorx.NewDefaultError("照片标题不能为空") } // 2. 业务逻辑 photoID := uuid.New().String() // 3. 数据持久化 photo := &model.Photo{ ID: photoID, Title: req.Title, // ... } err := l.svcCtx.PhotoModel.Insert(l.ctx, photo) if err != nil { return nil, err } return &types.UploadPhotoResponse{ Id: photoID, Title: req.Title, // ... }, nil } ``` ## 🔧 工具包使用 ### 文件处理 使用 [pkg/utils/file/file.go](mdc:backend/pkg/utils/file/file.go): ```go import "photography/pkg/utils/file" // 验证图片文件 if !file.IsImageFile(filename) { return errors.New("不支持的文件类型") } // 保存文件并生成缩略图 savedPath, thumbnail, err := file.SaveImage(fileData, filename) ``` ### JWT认证 使用 [pkg/utils/jwt/jwt.go](mdc:backend/pkg/utils/jwt/jwt.go): ```go import "photography/pkg/utils/jwt" // 生成token token, err := jwt.GenerateToken(userID, username) // 验证token userID, err := jwt.ParseToken(tokenString) ``` ### 错误处理 使用 [pkg/errorx/errorx.go](mdc:backend/pkg/errorx/errorx.go): ```go import "photography/pkg/errorx" // 业务错误 return nil, errorx.NewDefaultError("用户不存在") // 自定义错误码 return nil, errorx.NewCodeError(40001, "参数错误") ``` ## 🛡️ 中间件 ### JWT认证中间件 在 `internal/middleware/auth.go` 中实现: ```go func (m *AuthMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("Authorization") if token == "" { httpx.Error(w, errors.New("未提供认证token")) return } userID, err := jwt.ParseToken(strings.TrimPrefix(token, "Bearer ")) if err != nil { httpx.Error(w, errors.New("token无效")) return } // 将用户ID注入到context ctx := context.WithValue(r.Context(), "userID", userID) next(w, r.WithContext(ctx)) }) } ``` ## 📊 数据模型 ### 模型定义示例 ```go type Photo struct { ID string `db:"id" json:"id"` Title string `db:"title" json:"title"` Description string `db:"description" json:"description"` Filename string `db:"filename" json:"filename"` Thumbnail string `db:"thumbnail" json:"thumbnail"` CategoryID string `db:"category_id" json:"category_id"` UserID string `db:"user_id" json:"user_id"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` } ``` ### 数据库操作 ```go // 插入 err := l.svcCtx.PhotoModel.Insert(l.ctx, photo) // 查询 photo, err := l.svcCtx.PhotoModel.FindOne(l.ctx, photoID) // 更新 err := l.svcCtx.PhotoModel.Update(l.ctx, photo) // 删除 err := l.svcCtx.PhotoModel.Delete(l.ctx, photoID) ``` ## 🔄 配置管理 ### 配置文件: `etc/photography-api.yaml` ```yaml Name: photography-api Host: 0.0.0.0 Port: 8888 Auth: AccessSecret: your-secret-key AccessExpire: 86400 DataSource: photography.db Log: ServiceName: photography-api Mode: file Path: logs Level: info ``` ## 🧪 测试规范 ### 单元测试 ```go func TestUploadPhotoLogic(t *testing.T) { // 准备测试数据 req := &types.UploadPhotoRequest{ Title: "测试照片", File: "test.jpg", } // 执行测试 logic := NewUploadPhotoLogic(context.Background(), svcCtx) resp, err := logic.UploadPhoto(req) // 断言结果 assert.NoError(t, err) assert.NotEmpty(t, resp.Id) assert.Equal(t, "测试照片", resp.Title) } ``` 参考 [TASK_PROGRESS.md](mdc:TASK_PROGRESS.md) 了解当前后端开发进度。 # Go-Zero 框架开发规则 ## 🚀 架构规范 ### 核心概念 - **Handler**: HTTP请求处理层,只做参数验证和调用Logic - **Logic**: 业务逻辑层,包含核心业务代码 - **Model**: 数据访问层,处理数据库操作 - **Types**: 请求/响应类型定义 ### 文件结构 ``` backend/ ├── cmd/api/main.go # 服务启动入口 ├── etc/photography-api.yaml # 配置文件 ├── api/desc/ # API定义文件 ├── internal/ │ ├── handler/ # HTTP处理器 │ ├── logic/ # 业务逻辑 │ ├── model/ # 数据模型 │ ├── middleware/ # 中间件 │ ├── svc/ # 服务上下文 │ └── types/ # 类型定义 └── pkg/ # 工具包 ``` ## 🎯 开发流程 ### 1. API定义 在 `api/desc/` 目录下定义接口: ```api service photography-api { @handler uploadPhoto post /api/v1/photos (UploadPhotoRequest) returns (UploadPhotoResponse) } type UploadPhotoRequest { Title string `form:"title"` Description string `form:"description,optional"` File string `form:"file"` } type UploadPhotoResponse { Id string `json:"id"` Title string `json:"title"` Filename string `json:"filename"` Thumbnail string `json:"thumbnail"` } ``` ### 2. 代码生成 ```bash cd backend make api # 生成handler和logic骨架 ``` ### 3. Handler实现 ```go func (h *UploadPhotoHandler) UploadPhoto(w http.ResponseWriter, r *http.Request) { var req types.UploadPhotoRequest if err := httpx.Parse(r, &req); err != nil { httpx.ErrorCtx(r.Context(), w, err) return } l := logic.NewUploadPhotoLogic(r.Context(), h.svcCtx) resp, err := l.UploadPhoto(&req) response.Response(w, resp, err) } ``` ### 4. Logic实现 ```go func (l *UploadPhotoLogic) UploadPhoto(req *types.UploadPhotoRequest) (*types.UploadPhotoResponse, error) { // 1. 参数验证 if req.Title == "" { return nil, errorx.NewDefaultError("照片标题不能为空") } // 2. 业务逻辑 photoID := uuid.New().String() // 3. 数据持久化 photo := &model.Photo{ ID: photoID, Title: req.Title, // ... } err := l.svcCtx.PhotoModel.Insert(l.ctx, photo) if err != nil { return nil, err } return &types.UploadPhotoResponse{ Id: photoID, Title: req.Title, // ... }, nil } ``` ## 🔧 工具包使用 ### 文件处理 使用 [pkg/utils/file/file.go](mdc:backend/pkg/utils/file/file.go): ```go import "photography/pkg/utils/file" // 验证图片文件 if !file.IsImageFile(filename) { return errors.New("不支持的文件类型") } // 保存文件并生成缩略图 savedPath, thumbnail, err := file.SaveImage(fileData, filename) ``` ### JWT认证 使用 [pkg/utils/jwt/jwt.go](mdc:backend/pkg/utils/jwt/jwt.go): ```go import "photography/pkg/utils/jwt" // 生成token token, err := jwt.GenerateToken(userID, username) // 验证token userID, err := jwt.ParseToken(tokenString) ``` ### 错误处理 使用 [pkg/errorx/errorx.go](mdc:backend/pkg/errorx/errorx.go): ```go import "photography/pkg/errorx" // 业务错误 return nil, errorx.NewDefaultError("用户不存在") // 自定义错误码 return nil, errorx.NewCodeError(40001, "参数错误") ``` ## 🛡️ 中间件 ### JWT认证中间件 在 `internal/middleware/auth.go` 中实现: ```go func (m *AuthMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("Authorization") if token == "" { httpx.Error(w, errors.New("未提供认证token")) return } userID, err := jwt.ParseToken(strings.TrimPrefix(token, "Bearer ")) if err != nil { httpx.Error(w, errors.New("token无效")) return } // 将用户ID注入到context ctx := context.WithValue(r.Context(), "userID", userID) next(w, r.WithContext(ctx)) }) } ``` ## 📊 数据模型 ### 模型定义示例 ```go type Photo struct { ID string `db:"id" json:"id"` Title string `db:"title" json:"title"` Description string `db:"description" json:"description"` Filename string `db:"filename" json:"filename"` Thumbnail string `db:"thumbnail" json:"thumbnail"` CategoryID string `db:"category_id" json:"category_id"` UserID string `db:"user_id" json:"user_id"` CreatedAt time.Time `db:"created_at" json:"created_at"` UpdatedAt time.Time `db:"updated_at" json:"updated_at"` } ``` ### 数据库操作 ```go // 插入 err := l.svcCtx.PhotoModel.Insert(l.ctx, photo) // 查询 photo, err := l.svcCtx.PhotoModel.FindOne(l.ctx, photoID) // 更新 err := l.svcCtx.PhotoModel.Update(l.ctx, photo) // 删除 err := l.svcCtx.PhotoModel.Delete(l.ctx, photoID) ``` ## 🔄 配置管理 ### 配置文件: `etc/photography-api.yaml` ```yaml Name: photography-api Host: 0.0.0.0 Port: 8888 Auth: AccessSecret: your-secret-key AccessExpire: 86400 DataSource: photography.db Log: ServiceName: photography-api Mode: file Path: logs Level: info ``` ## 🧪 测试规范 ### 单元测试 ```go func TestUploadPhotoLogic(t *testing.T) { // 准备测试数据 req := &types.UploadPhotoRequest{ Title: "测试照片", File: "test.jpg", } // 执行测试 logic := NewUploadPhotoLogic(context.Background(), svcCtx) resp, err := logic.UploadPhoto(req) // 断言结果 assert.NoError(t, err) assert.NotEmpty(t, resp.Id) assert.Equal(t, "测试照片", resp.Title) } ``` 参考 [TASK_PROGRESS.md](mdc:TASK_PROGRESS.md) 了解当前后端开发进度。