Files
junhong_cmp_fiber/CLAUDE.md
huang a36e4a79c0 实现用户和组织模型(店铺、企业、个人客户)
核心功能:
- 实现 7 级店铺层级体系(Shop 模型 + 层级校验)
- 实现企业管理模型(Enterprise 模型)
- 实现个人客户管理模型(PersonalCustomer 模型)
- 重构 Account 模型关联关系(基于 EnterpriseID 而非 ParentID)
- 完整的 Store 层和 Service 层实现
- 递归查询下级店铺功能(含 Redis 缓存)
- 全面的单元测试覆盖(Shop/Enterprise/PersonalCustomer Store + Shop Service)

技术要点:
- 显式指定所有 GORM 模型的数据库字段名(column: 标签)
- 统一的字段命名规范(数据库用 snake_case,Go 用 PascalCase)
- 完整的中文字段注释和业务逻辑说明
- 100% 测试覆盖(20+ 测试用例全部通过)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-09 18:02:46 +08:00

455 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 Development Guidelines
Auto-generated from all feature plans. Last updated: 2025-11-10
## Active Technologies
- Go 1.25.4 + Fiber (HTTP 框架), GORM (ORM), Asynq (任务队列), Viper (配置), Zap (日志), golang-migrate (数据库迁移) (002-gorm-postgres-asynq)
- PostgreSQL 14+(主数据库), Redis 6.0+(任务队列存储) (002-gorm-postgres-asynq)
- Go 1.25.4 + Fiber (HTTP 框架), GORM (ORM), Asynq (任务队列), Viper (配置), Zap (日志), Redis, PostgreSQL (004-rbac-data-permission)
- PostgreSQL 14+ (主数据库), Redis 6.0+ (缓存和任务队列) (004-rbac-data-permission)
- Go 1.25.4 + Fiber v2.x (HTTP 框架), GORM v1.25.x (ORM), Viper (配置管理), Zap + Lumberjack.v2 (日志), sonic (JSON 序列化), Asynq v0.24.x (异步任务队列), golang-migrate (数据库迁移) (004-rbac-data-permission)
- PostgreSQL 14+ (主数据库), Redis 6.0+ (缓存和任务队列存储) (004-rbac-data-permission)
- Go 1.25.4 + Fiber v2.x (HTTP), GORM v1.25.x (ORM), Asynq v0.24.x (任务队列), Viper (配置), Zap + Lumberjack.v2 (日志), sonic (JSON), Validator (005-framework-cleanup-refactor)
- Go 1.25.4 (001-fiber-middleware-integration)
## Project Structure
```text
backend/
frontend/
tests/
```
## Commands
# Add commands for Go 1.25.1
---
## 核心开发原则
### 技术栈遵守
**必须遵守 (MUST):**
- 开发时严格遵守项目定义的技术栈Fiber + GORM + Viper + Zap + Lumberjack.v2 + Validator + sonic JSON + Asynq + PostgreSQL
- 禁止使用原生调用或绕过框架的快捷方式(禁止 `database/sql` 直接调用、禁止 `net/http` 替代 Fiber、禁止 `encoding/json` 替代 sonic
- 所有 HTTP 路由和中间件必须使用 Fiber 框架
- 所有数据库操作必须通过 GORM 进行
- 所有配置管理必须使用 Viper
- 所有日志记录必须使用 Zap + Lumberjack.v2
- 所有 JSON 序列化优先使用 sonic仅在必须使用标准库的场景才使用 `encoding/json`
- 所有异步任务必须使用 Asynq
- 必须使用 Go 官方工具链:`go fmt``go vet``golangci-lint`
- 必须使用 Go Modules 进行依赖管理
**理由:**
一致的技术栈使用确保代码可维护性、团队协作效率和长期技术债务可控。绕过框架的"快捷方式"会导致代码碎片化、难以调试、性能不一致和安全漏洞。
---
### 代码质量标准
**架构分层:**
- 代码必须遵循项目分层架构:`Handler → Service → Store → Model`
- Handler 层只能处理 HTTP 请求/响应,不得包含业务逻辑
- Service 层包含所有业务逻辑,支持跨模块调用
- Store 层统一管理所有数据访问,支持事务处理
- Model 层定义清晰的数据结构和 DTO
- 所有依赖通过结构体字段进行依赖注入(不使用构造函数模式)
**错误和响应处理:**
- 所有公共错误必须在 `pkg/errors/` 中定义,使用统一错误码
- 所有 API 响应必须使用 `pkg/response/` 的统一格式
- 所有常量必须在 `pkg/constants/` 中定义和管理
- 所有 Redis key 必须通过 `pkg/constants/` 中的 Key 生成函数统一管理
**代码注释和文档:**
- 必须为所有导出的函数、类型和常量编写 Go 风格的文档注释(`// FunctionName does something...`
- 代码注释implementation comments应该使用中文
- 日志消息应该使用中文
- 用户可见的错误消息必须使用中文(通过 `pkg/errors/` 的双语消息支持)
- Go 文档注释doc comments for exported APIs可以使用英文以保持生态兼容性但中文注释更佳
- 变量名、函数名、类型名必须使用英文(遵循 Go 命名规范)
**Go 代码风格要求:**
- 必须使用 `gofmt` 格式化所有代码
- 必须遵循 [Effective Go](https://go.dev/doc/effective_go) 和 [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments)
- 变量命名必须使用 Go 风格:`userID`(不是 `userId`)、`HTTPServer`(不是 `HttpServer`
- 缩写词必须全部大写或全部小写:`URL``ID``HTTP`(导出)或 `url``id``http`(未导出)
- 包名必须简短、小写、单数、无下划线:`user``order``pkg`(不是 `users``userService``user_service`
- 接口命名应该使用 `-er` 后缀:`Reader``Writer``Logger`(不是 `ILogger``LoggerInterface`
**常量管理规范:**
- 业务常量(状态码、类型枚举等)必须定义在 `pkg/constants/constants.go` 或按模块分文件
- Redis key 必须使用函数生成,不允许硬编码字符串拼接
- Redis key 生成函数必须遵循命名规范:`Redis{Module}{Purpose}Key(params...)`
- Redis key 格式必须使用冒号分隔:`{module}:{purpose}:{identifier}`
- 禁止在代码中直接使用 magic numbers未定义含义的数字字面量
- 禁止在代码中硬编码字符串字面量URL、状态码、配置值、业务规则等
- 当相同的字面量值在 3 个或以上位置使用时,必须提取为常量
- 已定义的常量必须被使用,禁止重复硬编码相同的值
**函数复杂度和职责分离:**
- 函数长度不得超过合理范围(通常 50-100 行,核心逻辑建议 ≤ 50 行)
- 超过 100 行的函数必须拆分为多个小函数,每个函数只负责一件事
- `main()` 函数只做编排orchestration不包含具体实现逻辑
- `main()` 函数中的每个初始化步骤应该提取为独立的辅助函数
- 编排函数必须清晰表达流程,避免嵌套的实现细节
- 必须遵循单一职责原则Single Responsibility Principle
---
### Go 语言惯用设计原则
**核心理念:写 Go 味道的代码,不要写 Java 味道的代码**
**包组织:**
- 包结构必须扁平化,避免深层嵌套(最多 2-3 层)
- 包必须按功能组织,不是按层次组织
- 包名必须描述功能,不是类型(`http` 不是 `httputils``handlers`
推荐的 Go 风格结构:
```
internal/
├── user/ # user 功能的所有代码
│ ├── handler.go # HTTP handlers
│ ├── service.go # 业务逻辑
│ ├── store.go # 数据访问
│ └── model.go # 数据模型
├── order/
└── sim/
```
**接口设计:**
- 接口必须小而专注1-3 个方法),不是大而全
- 接口应该在使用方定义,不是实现方(依赖倒置)
- 接口命名应该使用 `-er` 后缀:`Reader``Writer``Storer`
- 禁止使用 `I` 前缀或 `Interface` 后缀
- 禁止创建只有一个实现的接口(除非明确需要抽象)
**错误处理:**
- 错误必须显式返回和检查不使用异常panic/recover
- 错误处理必须紧跟错误产生的代码
- 必须使用 `errors.Is()``errors.As()` 检查错误类型
- 必须使用 `fmt.Errorf()` 包装错误,保留错误链
- 自定义错误应该实现 `error` 接口
- panic 只能用于不可恢复的程序错误
**结构体和方法:**
- 结构体必须简单直接不是类class的替代品
- 禁止为每个字段创建 getter/setter 方法
- 必须直接访问导出的字段(大写开头)
- 必须使用组合composition而不是继承inheritance
- 构造函数应该命名为 `New``NewXxx`,返回具体类型
- 禁止使用构造器模式Builder Pattern除非真正需要
**并发模式:**
- 必须使用 goroutines 和 channels不是线程和锁大多数情况
- 必须使用 `context.Context` 传递取消信号
- 必须遵循"通过通信共享内存,不要通过共享内存通信"
- 应该使用 `sync.WaitGroup` 等待 goroutines 完成
- 应该使用 `sync.Once` 确保只执行一次
- 禁止创建线程池类Go 运行时已处理)
**命名约定:**
- 变量名必须简短且符合上下文(短作用域用短名字:`i`, `j`, `k`;长作用域用描述性名字)
- 缩写词必须保持一致的大小写:`URL`, `HTTP`, `ID`(不是 `Url`, `Http`, `Id`
- 禁止使用匈牙利命名法或类型前缀:`strName`, `arrUsers`
- 禁止使用下划线连接(除了测试和包名)
- 方法接收者名称应该使用 1-2 个字母的缩写,全文件保持一致
**严格禁止的 Java 风格模式:**
1. ❌ 过度抽象(不需要的接口、工厂、构造器)
2. ❌ Getter/Setter直接访问导出字段
3. ❌ 继承层次(使用组合,不是嵌入)
4. ❌ 异常处理(使用错误返回,不是 panic/recover
5. ❌ 单例模式(使用包级别变量或 `sync.Once`
6. ❌ 线程池(直接使用 goroutines
7. ❌ 深层包嵌套(保持扁平结构)
8. ❌ 类型前缀(`IService`, `AbstractBase`, `ServiceImpl`
9. ❌ Bean 风格(不需要 POJO/JavaBean 模式)
10. ❌ 过度 DI 框架(简单直接的依赖注入)
---
### 测试标准
**测试要求:**
- 所有核心业务逻辑Service 层)必须有单元测试覆盖
- 所有 API 端点必须有集成测试覆盖
- 所有数据库操作应该有事务回滚测试
- 测试必须使用 Go 标准测试框架(`testing` 包)
- 测试文件必须与源文件同目录,命名为 `*_test.go`
- 测试函数必须使用 `Test` 前缀:`func TestUserCreate(t *testing.T)`
- 基准测试必须使用 `Benchmark` 前缀:`func BenchmarkUserCreate(b *testing.B)`
**测试性能要求:**
- 测试必须可独立运行,不依赖外部服务(使用 mock 或 testcontainers
- 单元测试必须在 100ms 内完成
- 集成测试应该在 1s 内完成
- 测试覆盖率应该达到 70% 以上(核心业务代码必须 90% 以上)
**测试最佳实践:**
- 测试必须使用 table-driven tests 处理多个测试用例
- 测试必须使用 `t.Helper()` 标记辅助函数
---
### API 设计规范
**统一响应格式:**
所有 API 响应必须使用统一的 JSON 格式:
```json
{
"code": 0,
"message": "success",
"data": {},
"timestamp": "2025-11-10T15:30:00Z"
}
```
**API 设计要求:**
- 所有错误响应必须包含明确的错误码和错误消息(中英文双语)
- 所有 API 端点必须遵循 RESTful 设计原则
- 所有分页 API 必须使用统一的分页参数:`page``page_size``total`
- 所有时间字段必须使用 ISO 8601 格式RFC3339
- 所有货币金额必须使用整数表示(分为单位),避免浮点精度问题
- 所有布尔字段必须使用 `true`/`false`,不使用 `0`/`1`
- API 版本必须通过 URL 路径管理(如 `/api/v1/...`
---
### 性能要求
**性能指标:**
- API 响应时间P95必须 < 200ms数据库查询 < 50ms
- API 响应时间P99必须 < 500ms
- 批量操作必须使用批量查询/插入,避免 N+1 查询问题
- 所有数据库查询必须有适当的索引支持
- 列表查询必须实现分页,默认 `page_size=20`,最大 `page_size=100`
- 异步任务必须用于非实时操作(批量同步、分佣计算等)
**资源限制:**
- 内存使用API 服务)应该 < 500MB正常负载
- 内存使用Worker 服务)应该 < 1GB正常负载
- 数据库连接池必须配置合理(`MaxOpenConns=25`, `MaxIdleConns=10`, `ConnMaxLifetime=5m`
- Redis 连接池必须配置合理(`PoolSize=10`, `MinIdleConns=5`
**并发处理:**
- 并发操作应该使用 goroutines 和 channels不是线程池模式
- 必须使用 `context.Context` 进行超时和取消控制
- 必须使用 `sync.Pool` 复用频繁分配的对象(如缓冲区)
---
### 数据库设计原则
**核心规则:**
- 数据库表之间禁止建立外键约束Foreign Key Constraints
- GORM 模型之间禁止使用 ORM 关联关系(`foreignKey``references``hasMany``belongsTo` 等标签)
- 表之间的关联必须通过存储关联 ID 字段手动维护
- 关联数据查询必须在代码层面显式执行,不依赖 ORM 的自动加载或预加载
- 模型结构体只能包含简单字段,不应包含其他模型的嵌套引用
- 数据库迁移脚本禁止包含外键约束定义
- 数据库迁移脚本禁止包含触发器用于维护关联数据
- 时间字段(`created_at``updated_at`)的更新必须由 GORM 自动处理,不使用数据库触发器
**GORM 模型字段规范:**
- 数据库字段名必须使用下划线命名法snake_case`user_id``email_address``created_at`
- Go 结构体字段名必须使用驼峰命名法PascalCase`UserID``EmailAddress``CreatedAt`
- **所有字段必须显式指定数据库列名**:使用 `gorm:"column:字段名"` 标签明确指定数据库字段名,不依赖 GORM 的自动转换
- 示例:`UserID uint gorm:"column:user_id;not null" json:"user_id"`
- 禁止省略 `column:` 标签,即使 GORM 能自动推断字段名
- 这确保了 Go 字段名和数据库字段名的映射关系清晰可见,避免命名歧义
- 字符串字段长度必须明确定义且保持一致性:
- 短文本(名称、标题等):`VARCHAR(255)``VARCHAR(100)`
- 中等文本(描述、备注等):`VARCHAR(500)``VARCHAR(1000)`
- 长文本(内容、详情等):`TEXT` 类型
- 数值字段精度必须明确定义:
- 货币金额:`DECIMAL(10, 2)``DECIMAL(18, 2)`(根据业务需求)
- 百分比:`DECIMAL(5, 2)``DECIMAL(5, 4)`
- 计数器:`INTEGER``BIGINT`
- 所有字段必须添加中文注释,说明字段用途和业务含义
- 必填字段必须在 GORM 标签中指定 `not null`
- 唯一字段必须在 GORM 标签中指定 `unique` 或通过数据库索引保证唯一性
- 枚举字段应该使用 `VARCHAR``INTEGER` 类型,并在代码中定义常量映射
**字段命名示例:**
```go
type User struct {
ID uint `gorm:"column:id;primaryKey;comment:用户 ID" json:"id"`
UserID string `gorm:"column:user_id;type:varchar(100);uniqueIndex;not null;comment:用户唯一标识" json:"user_id"`
Email string `gorm:"column:email;type:varchar(255);uniqueIndex;not null;comment:用户邮箱" json:"email"`
Phone string `gorm:"column:phone;type:varchar(20);comment:手机号码" json:"phone"`
Nickname string `gorm:"column:nickname;type:varchar(100);comment:用户昵称" json:"nickname"`
Balance int64 `gorm:"column:balance;type:bigint;default:0;comment:账户余额(分为单位)" json:"balance"`
Status int `gorm:"column:status;type:int;default:1;comment:用户状态 1-正常 2-禁用" json:"status"`
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;comment:创建时间" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime;comment:更新时间" json:"updated_at"`
}
```
**设计理由:**
1. **灵活性**:业务逻辑完全在代码中控制,不受数据库约束限制
2. **性能**:无外键约束意味着无数据库层面的引用完整性检查开销
3. **简单直接**:显式的关联数据查询使数据流向清晰可见
4. **可控性**:开发者完全掌控何时查询关联数据、查询哪些关联数据
5. **可维护性**:数据库 schema 更简单,迁移更容易
6. **分布式友好**:在微服务和分布式数据库场景下更容易扩展
7. **一致性**:统一的字段命名和类型定义提高代码可读性和可维护性
8. **可理解性**:中文注释让数据库结构一目了然,便于团队协作和新人上手
---
### 错误处理规范
**统一错误处理:**
- 所有 API 错误响应必须使用统一的 JSON 格式(通过 `pkg/errors/` 全局 ErrorHandler
- 所有 Handler 层错误必须通过返回 `error` 传递给全局 ErrorHandler禁止手动构造错误响应
- 所有业务错误必须使用 `pkg/errors.New()``pkg/errors.Wrap()` 创建 `AppError`,并指定错误码
- 所有错误码必须在 `pkg/errors/codes.go` 中统一定义和管理
**Panic 处理:**
- 所有 Panic 必须被 Recover 中间件自动捕获,转换为 500 错误响应
- 禁止在业务代码中主动 `panic`(除非遇到不可恢复的编程错误)
- 禁止在 Handler 中直接使用 `c.Status().JSON()` 返回错误响应
**错误日志:**
- 所有错误日志必须包含完整的请求上下文Request ID、路径、方法、参数等
- 5xx 服务端错误必须自动脱敏,只返回通用错误消息,原始错误仅记录到日志
- 4xx 客户端错误可以返回具体业务错误消息(如"用户名已存在"
**错误码分类:**
- `0`: 成功
- `1000-1999`: 客户端错误4xx HTTP 状态码,日志级别 Warn
- `2000-2999`: 服务端错误5xx HTTP 状态码,日志级别 Error
---
### 访问日志规范
**核心要求:**
- 所有 HTTP 请求必须被记录到 `access.log`,无例外
- 访问日志必须记录完整的请求参数query 参数 + request body
- 访问日志必须记录完整的响应参数response body
- 请求/响应 body 必须限制大小为 50KB超过部分截断并标注 `... (truncated)`
- 访问日志必须通过统一的 Logger 中间件(`pkg/logger/Middleware()`)记录
- 任何中间件的短路返回(认证失败、限流拒绝、参数验证失败等)禁止绕过访问日志
**必需字段:**
访问日志必须包含以下字段:
- `method`: HTTP 方法
- `path`: 请求路径
- `query`: Query 参数字符串
- `status`: HTTP 状态码
- `duration_ms`: 请求耗时(毫秒)
- `request_id`: 请求唯一 ID
- `ip`: 客户端 IP
- `user_agent`: 用户代理
- `user_id`: 用户 ID认证后有值否则为空
- `request_body`: 请求体(限制 50KB
- `response_body`: 响应体(限制 50KB
**日志配置:**
- 访问日志应该使用 JSON 格式,便于日志分析和监控
- 访问日志文件必须配置自动轮转(基于大小或时间)
**设计理由:**
完整的访问日志是系统可观测性的基础,对于问题排查、安全审计、性能分析、合规要求和用户行为分析至关重要。
---
### 文档规范
**文档结构要求:**
- 每个功能完成后必须在 `docs/` 目录创建总结文档
- 总结文档路径必须遵循规范:`docs/{feature-id}/` 对应 `specs/{feature-id}/`
- 总结文档文件名必须使用中文命名(例如:`功能总结.md``使用指南.md``架构说明.md`
- 总结文档内容必须使用中文编写
- 每次添加新功能总结文档时必须同步更新 `README.md`
**README.md 更新要求:**
- README.md 中的功能描述必须简短精炼,让首次接触项目的开发者能快速了解
- README.md 的功能描述应该控制在 2-3 句话以内
- 使用中文,便于中文开发者快速理解
- 提供到详细文档的链接
- 按功能模块分组(如"核心功能"、"中间件"、"业务模块"等)
文档结构示例:
```
specs/001-fiber-middleware-integration/ # 功能规划文档(设计阶段)
docs/001-fiber-middleware-integration/ # 功能总结文档(完成阶段)
├── 功能总结.md
├── 使用指南.md
└── 架构说明.md
```
---
## Recent Changes
- 005-framework-cleanup-refactor: Added Go 1.25.4 + Fiber v2.x (HTTP), GORM v1.25.x (ORM), Asynq v0.24.x (任务队列), Viper (配置), Zap + Lumberjack.v2 (日志), sonic (JSON), Validator
- 004-rbac-data-permission: Added Go 1.25.4 + Fiber v2.x (HTTP 框架), GORM v1.25.x (ORM), Viper (配置管理), Zap + Lumberjack.v2 (日志), sonic (JSON 序列化), Asynq v0.24.x (异步任务队列), golang-migrate (数据库迁移)
- 004-rbac-data-permission: Added [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
<!-- MANUAL ADDITIONS START -->
1.永远用中文交互,注释以及文档也要使用中文(必须)
<!-- MANUAL ADDITIONS END -->