Files
junhong_cmp_fiber/AGENTS.md
huang cfac546f14 完善开发规范:新增 PostgreSQL MCP 数据库验证规范
- 在 AGENTS.md 中添加「数据库验证规范」章节
- 强制要求 AI 在测试接口时使用 PostgreSQL MCP 验证数据正确性
- 提供 4 个可用工具说明和 3 个典型验证场景示例
- 在 README.md 中添加规范文档链接,便于快速查阅
2026-01-21 11:00:14 +08:00

731 lines
20 KiB
Markdown
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.
<!-- OPENSPEC:START -->
# OpenSpec Instructions
These instructions are for AI assistants working in this project.
Always open `@/openspec/AGENTS.md` when the request:
- Mentions planning or proposals (words like proposal, spec, change, plan)
- Introduces new capabilities, breaking changes, architecture shifts, or big performance/security work
- Sounds ambiguous and you need the authoritative spec before coding
Use `@/openspec/AGENTS.md` to learn:
- How to create and apply change proposals
- Spec format and conventions
- Project structure and guidelines
Keep this managed block so 'openspec update' can refresh the instructions.
<!-- OPENSPEC:END -->
---
# junhong_cmp_fiber 项目开发规范
**重要提示**: 完整的开发规范和 OpenSpec 工作流详细说明请查看 `@/openspec/AGENTS.md`
## 语言要求
**必须遵守:**
- 永远用中文交互
- 注释必须使用中文
- 文档必须使用中文
- 日志消息必须使用中文
- 用户可见的错误消息必须使用中文
- 变量名、函数名、类型名必须使用英文(遵循 Go 命名规范)
- GIT提交的commit必须使用中文
## 技术栈
**必须严格遵守以下技术栈,禁止使用替代方案:**
- **HTTP 框架**: Fiber v2.x
- **ORM**: GORM v1.25.x
- **配置管理**: Viper
- **日志**: Zap + Lumberjack.v2
- **JSON 序列化**: sonic优先encoding/json必要时
- **验证**: Validator
- **任务队列**: Asynq v0.24.x
- **数据库**: PostgreSQL 14+
- **缓存**: Redis 6.0+
**禁止:**
- 直接使用 `database/sql`(必须通过 GORM
- 使用 `net/http` 替代 Fiber
- 使用 `encoding/json` 替代 sonic除非必要
## 架构分层
必须遵循以下分层架构:
```
Handler → Service → Store → Model
```
- **Handler**: 只处理 HTTP 请求/响应,不包含业务逻辑
- **Service**: 包含所有业务逻辑,支持跨模块调用
- **Store**: 统一管理所有数据访问,支持事务处理
- **Model**: 定义数据结构和 DTO
## 核心原则
### 错误处理
- 所有错误必须在 `pkg/errors/` 中定义
- 使用统一错误码系统
- Handler 层通过返回 `error` 传递给全局 ErrorHandler
### 响应格式
- 所有 API 响应使用 `pkg/response/` 的统一格式
- 格式: `{code, message, data, timestamp}`
### 常量管理
- 所有常量定义在 `pkg/constants/`
- Redis key 使用函数生成: `Redis{Module}{Purpose}Key(params...)`
- 格式: `{module}:{purpose}:{identifier}`
- 禁止硬编码字符串和 magic numbers
- **必须为所有常量添加中文注释**,参考 `pkg/constants/iot.go` 的注释风格
- 常量分组使用 `// ========` 分隔线和标题注释
- 每个常量值后必须添加行内注释说明含义
### Go 代码风格
- 使用 `gofmt` 格式化
- 遵循 [Effective Go](https://go.dev/doc/effective_go)
- 包名: 简短、小写、单数、无下划线
- 接口命名: 使用 `-er` 后缀Reader、Writer、Logger
- 缩写词: 全大写或全小写URL、ID、HTTP 或 url、id、http
## DTO 规范(重要!)
**所有 DTO 文件必须遵循以下规范,这是 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. 枚举字段必须列出所有可能值(中文)
**所有枚举类型字段必须在 `description` 中列出所有可能值和对应的中文含义**
```go
// 用户类型
UserType int `json:"user_type" description:"用户类型 (1:超级管理员, 2:平台用户, 3:代理账号, 4:企业账号)"`
// 角色类型
RoleType int `json:"role_type" description:"角色类型 (1:平台角色, 2:客户角色)"`
// 权限类型
PermType int `json:"perm_type" description:"权限类型 (1:菜单, 2:按钮)"`
// 状态字段
Status int `json:"status" description:"状态 (0:禁用, 1:启用)"`
// 适用端口
Platform string `json:"platform" description:"适用端口 (all:全部, web:Web后台, h5:H5端)"`
```
**禁止使用英文枚举值**
```go
UserType int `json:"user_type" description:"用户类型 (1:SuperAdmin, 2:Platform)"` // 错误!
```
#### 3. 验证标签与 OpenAPI 标签一致
**所有验证约束必须同时在 `validate` 和 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"` | 字符串长度 |
| `len=N` | `minLength:"N" maxLength:"N"` | 固定长度 |
| `oneof=A B C` | `description` 中说明 | 枚举值 |
#### 4. 请求参数类型标签
**Query 参数和 Path 参数必须添加对应标签**
```go
// Query 参数
type ListRequest struct {
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
UserType *int `json:"user_type" query:"user_type" 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"`
}
```
#### 5. 响应 DTO 完整性
**所有响应 DTO 的字段都必须有完整的 `description` 标签**
```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:启用)"`
CreatedAt string `json:"created_at" description:"创建时间"`
UpdatedAt string `json:"updated_at" description:"更新时间"`
}
```
### AI 助手必须执行的检查
**在创建或修改任何 DTO 文件后,必须执行以下检查:**
1. ✅ 检查所有字段是否有 `description` 标签
2. ✅ 检查枚举字段是否列出了所有可能值(中文)
3. ✅ 检查状态字段是否说明了 0 和 1 的含义
4. ✅ 检查 validate 标签与 OpenAPI 标签是否一致
5. ✅ 检查是否禁止使用行内注释替代 description
6. ✅ 检查枚举值是否使用中文而非英文
7. ✅ 重新生成 OpenAPI 文档验证:`go run cmd/gendocs/main.go`
**详细检查清单**: 参见 `docs/code-review-checklist.md`
### 常见枚举字段标准值
```go
// 用户类型
description:"用户类型 (1:超级管理员, 2:平台用户, 3:代理账号, 4:企业账号)"
// 角色类型
description:"角色类型 (1:平台角色, 2:客户角色)"
// 权限类型
description:"权限类型 (1:菜单, 2:按钮)"
// 适用端口
description:"适用端口 (all:全部, web:Web后台, h5:H5端)"
// 状态
description:"状态 (0:禁用, 1:启用)"
// 店铺层级
description:"店铺层级 (1-7级)"
```
## Model 模型规范
**必须遵守的模型结构:**
```go
// ModelName 模型名称模型
// 详细的业务说明2-3行
// 特殊说明(如果有)
type ModelName struct {
gorm.Model // 包含 ID、CreatedAt、UpdatedAt、DeletedAt
BaseModel `gorm:"embedded"` // 包含 Creator、Updater
Field1 string `gorm:"column:field1;type:varchar(50);not null;comment:字段1说明" json:"field1"`
// ... 其他字段
}
// TableName 指定表名
func (ModelName) TableName() string {
return "tb_model_name"
}
```
**关键要点:**
- ✅ **必须**嵌入 `gorm.Model``BaseModel`,不要手动定义 ID、CreatedAt、UpdatedAt、DeletedAt、Creator、Updater
- ✅ **必须**为模型添加中文注释,说明业务用途(参考 `internal/model/iot_card.go`
- ✅ **必须**在每个字段的 `comment` 标签中添加中文说明
- ✅ **必须**为导出的类型编写 godoc 格式的文档注释
- ✅ **必须**实现 `TableName()` 方法,表名使用 `tb_` 前缀
- ✅ 所有字段必须显式指定 `gorm:"column:field_name"` 标签
- ✅ 金额字段使用 `int64` 类型,单位为分
- ✅ 时间字段使用 `*time.Time`(可空)或 `time.Time`(必填)
- ✅ JSONB 字段需要实现 `driver.Valuer``sql.Scanner` 接口
## API 路由注册规范
**核心要求:所有 HTTP 接口必须使用统一的 `Register()` 函数注册,以自动加入 OpenAPI 文档生成。**
```go
// ✅ 正确
Register(router, doc, basePath, "POST", "/shops", handler.Create, RouteSpec{
Summary: "创建店铺",
Tags: []string{"店铺管理"},
Input: new(model.CreateShopRequest),
Output: new(model.ShopResponse),
Auth: true,
})
// ❌ 错误:直接注册不会生成文档
router.Post("/shops", handler.Create)
```
**RouteSpec 必填项:**
- `Summary` - 操作说明(中文,简短)
- `Tags` - 分类标签(用于文档分组)
- `Input` - 请求 DTO`nil` 表示无参数)
- `Output` - 响应 DTO`nil` 表示无返回)
- `Auth` - 是否需要认证
**完整指南**: 参见 [`docs/api-documentation-guide.md`](docs/api-documentation-guide.md)
## 数据库设计
**核心规则:**
- ❌ 禁止建立外键约束
- ❌ 禁止使用 GORM 关联关系标签foreignKey、hasMany、belongsTo
- ✅ 关联通过存储 ID 字段手动维护
- ✅ 关联数据在代码层面显式查询
**理由**: 灵活性、性能、可控性、分布式友好
## Go 惯用法 vs Java 风格
### ✅ Go 风格(推荐)
- 扁平化包结构(最多 2-3 层)
- 小而专注的接口1-3 个方法)
- 直接访问导出字段(不用 getter/setter
- 组合优于继承
- 显式错误返回和检查
- goroutines + channels不用线程池
### ❌ Java 风格(禁止)
- 过度抽象(不必要的接口、工厂)
- Getter/Setter 方法
- 深层继承层次
- 异常处理panic/recover
- 单例模式
- 类型前缀IService、AbstractBase、ServiceImpl
- Bean 风格
## 测试要求
- 核心业务逻辑Service 层)测试覆盖率 ≥ 90%
- 所有 API 端点必须有集成测试
- 使用 table-driven tests
- 单元测试 < 100ms集成测试 < 1s
## 数据库验证规范
**核心要求AI 在测试接口或验证业务逻辑时,必须使用 PostgreSQL MCP 工具直接查询数据库验证数据的正确性。**
### 何时使用 PostgreSQL MCP
**必须使用的场景**
- 测试 API 接口后验证数据是否正确写入数据库
- 检查数据库表结构是否符合 Model 定义
- 验证数据库迁移是否成功执行
- 调试业务逻辑时查看实际数据状态
- 验证事务是否正确提交或回滚
- 检查数据权限过滤是否生效
**不要**
- 仅依赖 API 响应判断数据是否正确(响应可能只是内存中的临时数据)
- 通过日志推测数据库状态
- 假设代码逻辑正确就认为数据正确
### 可用的 PostgreSQL MCP 工具
```
1. PostgresListSchemas - 列出所有数据库模式
2. PostgresListObjects - 列出指定模式下的表/视图/序列
3. PostgresGetObjectDetails - 查看表结构详情(字段、类型、约束、注释)
4. PostgresExecuteSql - 执行只读 SQL 查询SELECT
```
### 验证示例
**场景 1测试创建用户接口**
```
1. 调用 POST /api/v1/accounts 创建用户
→ 响应:{"code":0, "data":{"id":123, "username":"testuser"}}
2. ✅ 使用 PostgreSQL MCP 验证数据库
PostgresExecuteSql:
- sql: "SELECT id, username, user_type, status, created_at FROM tb_account WHERE id = 123"
3. 检查查询结果:
✅ 用户确实已创建
✅ 字段值与请求参数一致
✅ status = 1启用
✅ created_at 有值
```
**场景 2测试数据权限过滤**
```
1. 以代理用户登录,查询店铺列表
→ 响应:返回 5 个店铺
2. ✅ 使用 PostgreSQL MCP 验证过滤逻辑
PostgresExecuteSql:
- sql: "SELECT id, shop_name, parent_id FROM tb_shop WHERE deleted_at IS NULL"
3. 检查:
✅ 数据库实际有 10 个店铺
✅ API 只返回了当前用户及下级的 5 个店铺
✅ 数据权限过滤生效
```
**场景 3验证迁移执行**
```
1. 执行迁移make migrate-up
2. ✅ 验证表结构
PostgresGetObjectDetails:
- schema_name: "public"
- object_name: "tb_account"
- object_type: "table"
3. 检查:
✅ 新字段 enterprise_id 已添加
✅ 类型为 bigint
✅ 允许 NULL
✅ 注释为"企业ID"
```
### 注意事项
⚠️ **限制**
- PostgreSQL MCP 只支持只读查询SELECT不能执行 INSERT/UPDATE/DELETE
- 如需插入测试数据,使用 Go 脚本或迁移文件
⚠️ **安全**
- 避免在查询中暴露敏感数据(如密码哈希)
- 生产环境使用时需谨慎,避免查询大量数据
**最佳实践**
- 每次 API 测试后都验证数据库状态
- 使用 LIMIT 限制查询结果数量(如 `LIMIT 10`
- 验证完成后清理测试数据
## 性能要求
- API P95 响应时间 < 200ms
- API P99 响应时间 < 500ms
- 数据库查询 < 50ms
- 列表查询必须分页(默认 20最大 100
- 避免 N+1 查询,使用批量操作
## 文档要求
- 每个功能在 `docs/{feature-id}/` 创建总结文档
- 文档文件名和内容使用中文
- 同步更新 README.md
- 为导出的函数、类型编写文档注释
## 函数复杂度
- 函数长度 ≤ 100 行(核心逻辑建议 ≤ 50 行)
- `main()` 函数只做编排,不含具体实现
- 遵循单一职责原则
## 访问日志
- 所有 HTTP 请求记录到 `access.log`
- 记录完整的请求/响应(限制 50KB
- 包含: method, path, query, status, duration, request_id, ip, user_agent, user_id, bodies
- 使用 JSON 格式,配置自动轮转
## 数据库迁移
### 迁移工具
项目使用 **golang-migrate** 进行数据库迁移管理。
### 基本命令
```bash
# 查看当前迁移版本
make migrate-version
# 执行所有待迁移
make migrate-up
# 回滚上一次迁移
make migrate-down
# 创建新迁移文件
make migrate-create
# 然后输入迁移名称,例如: add_user_email
```
### 迁移文件规范
迁移文件位于 `migrations/` 目录:
```
migrations/
├── 000001_initial_schema.up.sql
├── 000001_initial_schema.down.sql
├── 000002_add_user_email.up.sql
├── 000002_add_user_email.down.sql
```
**命名规范**:
- 格式: `{序号}_{描述}.{up|down}.sql`
- 序号: 6位数字从 000001 开始
- 描述: 小写英文,用下划线分隔
- up: 应用迁移(向前)
- down: 回滚迁移(向后)
**编写规范**:
```sql
-- up.sql 示例
-- 添加字段时必须考虑向后兼容
ALTER TABLE tb_users
ADD COLUMN email VARCHAR(100);
-- 添加注释
COMMENT ON COLUMN tb_users.email IS '用户邮箱';
-- 为现有数据设置默认值(如果需要)
UPDATE tb_users SET email = '' WHERE email IS NULL;
-- down.sql 示例
ALTER TABLE tb_users
DROP COLUMN IF EXISTS email;
```
### 迁移执行流程(必须遵守)
当你创建迁移文件后,**必须**执行以下验证步骤:
1. **执行迁移**:
```bash
make migrate-up
```
2. **验证迁移状态**:
```bash
make migrate-version
# 确认版本号已更新且 dirty=false
```
3. **验证数据库结构**:
使用 PostgreSQL MCP 工具检查:
- 字段是否正确创建
- 类型是否符合预期
- 默认值是否正确
- 注释是否存在
4. **验证查询功能**:
编写临时脚本测试新字段的查询功能
5. **更新 Model**:
在 `internal/model/` 中添加对应字段
6. **清理测试数据**:
如果插入了测试数据,记得清理
### 迁移失败处理
如果迁移执行失败,数据库会被标记为 dirty 状态:
```bash
# 1. 检查错误原因
make migrate-version
# 如果显示 dirty=true说明迁移失败
# 2. 手动修复数据库状态
# 使用 PostgreSQL MCP 连接数据库
# 检查失败的迁移是否部分执行
# 手动清理或完成迁移
# 3. 清除 dirty 标记
UPDATE schema_migrations SET dirty = false WHERE version = {失败的版本号};
# 4. 修复迁移文件中的错误
# 5. 重新执行迁移
make migrate-up
```
### 使用 PostgreSQL MCP 访问数据库
项目配置了 PostgreSQL MCP 工具,用于直接访问和查询数据库。
**可用工具**:
1. **查看表结构**:
```
PostgresGetObjectDetails:
- schema_name: "public"
- object_name: "tb_permission"
- object_type: "table"
```
2. **列出所有表**:
```
PostgresListObjects:
- schema_name: "public"
- object_type: "table"
```
3. **执行查询**:
```
PostgresExecuteSql:
- sql: "SELECT * FROM tb_permission LIMIT 5"
```
**使用场景**:
- ✅ 验证迁移是否成功执行
- ✅ 检查字段类型、默认值、约束
- ✅ 查看现有数据
- ✅ 测试新增字段的查询功能
- ✅ 调试数据库问题
**注意事项**:
- ⚠️ MCP 工具只支持只读查询SELECT
- ⚠️ 不要直接修改数据,修改必须通过迁移文件
- ⚠️ 测试数据可以通过临时 Go 脚本插入
### 迁移最佳实践
1. **向后兼容**:
- 添加字段时使用 `DEFAULT` 或允许 NULL
- 删除字段前确保代码已不再使用
- 修改字段类型要考虑数据转换
2. **原子性**:
- 每个迁移文件只做一件事
- 复杂变更拆分成多个迁移
3. **可回滚**:
- down.sql 必须能完整回滚 up.sql 的所有变更
- 测试回滚功能: `make migrate-down && make migrate-up`
4. **注释完整**:
- 迁移文件顶部说明变更原因
- 关键 SQL 添加行内注释
- 数据库字段使用 COMMENT 添加说明
5. **测试数据**:
- 不要在迁移文件中插入业务数据
- 可以插入配置数据或枚举值
- 测试数据用临时脚本处理
## OpenSpec 工作流
创建提案前的检查清单:
1. ✅ 技术栈合规
2. ✅ 架构分层正确
3. ✅ 使用统一错误处理
4. ✅ 常量定义在 pkg/constants/
5. ✅ Go 惯用法(非 Java 风格)
6. ✅ 包含测试计划
7. ✅ 性能考虑
8. ✅ 文档更新计划
9. ✅ 中文优先
**详细规范和 OpenSpec 工作流请查看**: `@/openspec/AGENTS.md`
## 规范文档管理
### 添加新规范的流程
当你需要为项目添加新的开发规范时,必须遵循以下流程:
#### 1. 创建详细规范文档
在 `docs/` 目录下创建详细的规范文档Markdown 格式):
```
docs/
├── api-documentation-guide.md # API 文档生成规范
├── code-review-checklist.md # 代码审查清单
├── testing-guide.md # 测试规范
└── ...
```
**文档内容要求**
- ✅ 包含完整的规范说明、示例代码、常见问题
- ✅ 使用中文编写,代码示例使用英文
- ✅ 提供正确示例(✅)和错误示例(❌)的对比
- ✅ 包含故障排查和调试指南
#### 2. 在 AGENTS.md 中添加简短引导
在 `AGENTS.md` 的相关章节中添加**简短**的规范说明 + 引导链接:
```markdown
## XXX 规范
**核心要求:一句话说明最重要的规则。**
```go
// ✅ 正确示例3-5 行)
...
// ❌ 错误示例3-5 行)
...
```
**关键要点**
- 规则 1
- 规则 2
- 规则 3
**完整指南**: 参见 [`docs/xxx-guide.md`](docs/xxx-guide.md)
```
**注意**
- ⚠️ AGENTS.md 中的说明不超过 20 行
- ⚠️ 只保留最核心的规则和示例
- ⚠️ 必须包含引导链接到详细文档
#### 3. 在 README.md 中添加文档链接
在 `README.md` 的"## 文档"章节中添加链接:
```markdown
## 文档
### 开发规范
- **[API 文档生成规范](docs/api-documentation-guide.md)**路由注册规范、DTO 规范、OpenAPI 文档生成流程
- **[XXX 规范](docs/xxx-guide.md)**:简短的一句话说明
```
**分类规则**
- 开发规范代码规范、API 规范、测试规范
- 功能指南:功能使用指南、配置指南
- 架构设计:设计文档、技术选型
### 规范文档的维护
**更新规范时**
1. 优先更新 `docs/` 下的详细文档
2. 如果核心规则变化,同步更新 AGENTS.md 中的简短说明
3. 保持 AGENTS.md 简洁,避免冗余
**删除规范时**
1. 删除 `docs/` 下的详细文档
2. 删除 AGENTS.md 中的相关章节
3. 删除 README.md 中的链接
4. 说明删除原因(在 commit message 中)