Files
photography/.cursor/rules/backend/go-zero-framework.mdc
xujiang 010fe2a8c7
Some checks failed
部署后端服务 / 🧪 测试后端 (push) Failing after 5m8s
部署后端服务 / 🚀 构建并部署 (push) Has been skipped
部署后端服务 / 🔄 回滚部署 (push) Has been skipped
fix
2025-07-10 18:09:11 +08:00

493 lines
12 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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) 了解当前后端开发进度。