From 242e0b1f40d08583792286394d8c04933c2adc0b Mon Sep 17 00:00:00 2001 From: huang Date: Mon, 16 Mar 2026 23:31:07 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=9B=B4=E6=96=B0=20AGENTS.md=20?= =?UTF-8?q?=E5=92=8C=20CLAUDE.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus --- AGENTS.md | 39 +++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index c7a0b92..8769946 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,6 +38,7 @@ handlers := &bootstrap.Handlers{ ## 语言要求 **必须遵守:** + - 永远用中文交互 - 注释必须使用中文 - 文档必须使用中文 @@ -63,6 +64,7 @@ handlers := &bootstrap.Handlers{ | 缓存 | Redis 6.0+ | **禁止:** + - 直接使用 `database/sql`(必须通过 GORM) - 使用 `net/http` 替代 Fiber - 使用 `encoding/json` 替代 sonic(除非必要) @@ -83,21 +85,25 @@ Handler → Service → Store → Model ## 核心原则 ### 错误处理 + - 所有错误必须在 `pkg/errors/` 中定义 - 使用统一错误码系统 - Handler 层通过返回 `error` 传递给全局 ErrorHandler #### 错误报错规范(必须遵守) + - Handler 层禁止直接返回/拼接底层错误信息给客户端(例如 `"参数验证失败: "+err.Error()`、`err.Error()`) - 参数校验失败:对外统一返回 `errors.New(errors.CodeInvalidParam)`(详细校验错误写日志) - Service 层禁止对外返回 `fmt.Errorf(...)`,必须返回 `errors.New(...)` 或 `errors.Wrap(...)` - 约定用法:`errors.New(code[, msg])`、`errors.Wrap(code, err[, msg])` ### 响应格式 + - 所有 API 响应使用 `pkg/response/` 的统一格式 - 格式: `{code, msg, data, timestamp}` ### 常量管理 + - 所有常量定义在 `pkg/constants/` - Redis key 使用函数生成: `Redis{Module}{Purpose}Key(params...)` - 禁止硬编码字符串和 magic numbers @@ -177,6 +183,7 @@ func (s *UsageService) ActivateByRealname(ctx context.Context, cardID uint) erro #### 未导出符号的注释 未导出(小写)的函数/方法: + - **简单逻辑**(< 15 行):可以不加注释 - **复杂逻辑**(≥ 15 行)或 **非显而易见的算法**:必须加注释 @@ -199,6 +206,7 @@ func (s *Service) buildPermissionTree(permissions []*model.Permission) []*dto.Pe | 临时方案/兼容逻辑 | 标注 TODO 或说明背景 | **✅ 好的内联注释(解释为什么)**: + ```go // 使用 Redis 分布式锁防止并发重复创建,锁超时 10 秒 if !s.acquireLock(ctx, lockKey, 10*time.Second) { @@ -212,6 +220,7 @@ if err := s.freezeCommission(ctx, tx, orderID); err != nil { ``` **❌ 废话注释(禁止)**: + ```go // 获取用户ID ← 禁止:代码本身已经很清楚 userID := middleware.GetUserIDFromContext(ctx) @@ -248,6 +257,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { ``` ### Go 代码风格 + - 使用 `gofmt` 格式化 - 遵循 [Effective Go](https://go.dev/doc/effective_go) - 包名: 简短、小写、单数、无下划线 @@ -256,6 +266,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { ## 数据库设计 **核心规则:** + - ❌ 禁止建立外键约束 - ❌ 禁止使用 GORM 关联关系标签(foreignKey、hasMany、belongsTo) - ✅ 关联通过存储 ID 字段手动维护 @@ -264,6 +275,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { ## Go 惯用法 vs Java 风格 ### ✅ Go 风格(推荐) + - 扁平化包结构(最多 2-3 层) - 小而专注的接口(1-3 个方法) - 直接访问导出字段(不用 getter/setter) @@ -271,6 +283,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { - 显式错误返回和检查 ### ❌ Java 风格(禁止) + - 过度抽象(不必要的接口、工厂) - Getter/Setter 方法 - 深层继承层次 @@ -282,6 +295,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { **本项目不使用任何形式的自动化测试代码。** **绝对禁止:** + - ❌ **禁止编写单元测试** - 无论任何场景 - ❌ **禁止编写集成测试** - 无论任何场景 - ❌ **禁止编写验收测试** - 无论任何场景 @@ -292,15 +306,18 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { - ❌ **禁止在文档中提及测试要求** - 规范、设计文档均不讨论测试 **唯一例外:** + - ✅ **仅当用户明确要求**时才编写测试代码 - ✅ 用户必须主动说明"请写测试"或"需要测试" **原因说明:** + - 业务系统的正确性通过人工验证和生产环境监控保证 - 测试代码的维护成本高于价值 - 快速迭代优先于测试覆盖率 **替代方案:** + - 使用 PostgreSQL MCP 工具手动验证数据 - 使用 Postman/curl 手动测试 API - 依赖生产环境日志和监控发现问题 @@ -349,23 +366,27 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { ## Code Review 检查清单 ### 错误处理 + - [ ] Service 层无 `fmt.Errorf` 对外返回 - [ ] Handler 层参数校验不泄露细节 - [ ] 错误码使用正确(4xx vs 5xx) - [ ] 错误日志完整(包含上下文) ### 代码质量 + - [ ] 遵循 Handler → Service → Store → Model 分层 - [ ] 函数长度 ≤ 100 行(核心逻辑 ≤ 50 行) - [ ] 常量定义在 `pkg/constants/` - [ ] 使用 Go 惯用法(非 Java 风格) ### 文档和注释 + - [ ] 所有注释使用中文 - [ ] 导出函数/类型有文档注释 - [ ] API 路径注释与真实路由一致 ### 幂等性 + - [ ] 创建类写操作有 Redis 业务键防重 - [ ] 状态变更使用条件更新(`WHERE status = expected`) - [ ] 余额/库存变更使用乐观锁(version 字段) @@ -381,6 +402,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { 1. **路由层中间件**(粗粒度拦截) - 用于明显的权限限制(如企业账号禁止访问账号管理) - 示例: + ```go group.Use(func(c *fiber.Ctx) error { userType := middleware.GetUserTypeFromContext(c.UserContext()) @@ -404,6 +426,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { - 无需手动调用 **统一错误返回**: + - 越权访问统一返回:`errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")` - 不区分"不存在"和"无权限",防止信息泄露 @@ -522,6 +545,7 @@ func RedisOrderCreateLockKey(carrierType string, carrierID uint) string **使用方式**: 1. **Service 层集成审计日志**: + ```go type Service struct { store *Store @@ -585,3 +609,18 @@ func RedisOrderCreateLockKey(carrierType string, carrierID uint) string > "任务 3.1 在当前实现中可能不需要,是否可以跳过?" **详细规范和 OpenSpec 工作流请查看**: `@/openspec/AGENTS.md` + +# English Learning Mode + + The user is learning English through practical use. Apply these rules in every conversation: + + 1. **Always respond in Chinese** — regardless of whether the user writes in English or Chinese. + + 2. **When the user writes in English**, append a one-line correction at the end of your response in this format: + → `[natural version of what they wrote]` + No explanation needed — just the corrected phrase. + + 3. **When the user mixes Chinese into English** (e.g., "I want to 实现 dark mode"), translate the Chinese word/phrase inline and continue naturally. Do not make a + big deal of it. + + 4. **Never interrupt the flow** to give grammar lessons. Corrections are silent and brief — the user's focus is on the task, not the language. diff --git a/CLAUDE.md b/CLAUDE.md index c7a0b92..8769946 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,6 +38,7 @@ handlers := &bootstrap.Handlers{ ## 语言要求 **必须遵守:** + - 永远用中文交互 - 注释必须使用中文 - 文档必须使用中文 @@ -63,6 +64,7 @@ handlers := &bootstrap.Handlers{ | 缓存 | Redis 6.0+ | **禁止:** + - 直接使用 `database/sql`(必须通过 GORM) - 使用 `net/http` 替代 Fiber - 使用 `encoding/json` 替代 sonic(除非必要) @@ -83,21 +85,25 @@ Handler → Service → Store → Model ## 核心原则 ### 错误处理 + - 所有错误必须在 `pkg/errors/` 中定义 - 使用统一错误码系统 - Handler 层通过返回 `error` 传递给全局 ErrorHandler #### 错误报错规范(必须遵守) + - Handler 层禁止直接返回/拼接底层错误信息给客户端(例如 `"参数验证失败: "+err.Error()`、`err.Error()`) - 参数校验失败:对外统一返回 `errors.New(errors.CodeInvalidParam)`(详细校验错误写日志) - Service 层禁止对外返回 `fmt.Errorf(...)`,必须返回 `errors.New(...)` 或 `errors.Wrap(...)` - 约定用法:`errors.New(code[, msg])`、`errors.Wrap(code, err[, msg])` ### 响应格式 + - 所有 API 响应使用 `pkg/response/` 的统一格式 - 格式: `{code, msg, data, timestamp}` ### 常量管理 + - 所有常量定义在 `pkg/constants/` - Redis key 使用函数生成: `Redis{Module}{Purpose}Key(params...)` - 禁止硬编码字符串和 magic numbers @@ -177,6 +183,7 @@ func (s *UsageService) ActivateByRealname(ctx context.Context, cardID uint) erro #### 未导出符号的注释 未导出(小写)的函数/方法: + - **简单逻辑**(< 15 行):可以不加注释 - **复杂逻辑**(≥ 15 行)或 **非显而易见的算法**:必须加注释 @@ -199,6 +206,7 @@ func (s *Service) buildPermissionTree(permissions []*model.Permission) []*dto.Pe | 临时方案/兼容逻辑 | 标注 TODO 或说明背景 | **✅ 好的内联注释(解释为什么)**: + ```go // 使用 Redis 分布式锁防止并发重复创建,锁超时 10 秒 if !s.acquireLock(ctx, lockKey, 10*time.Second) { @@ -212,6 +220,7 @@ if err := s.freezeCommission(ctx, tx, orderID); err != nil { ``` **❌ 废话注释(禁止)**: + ```go // 获取用户ID ← 禁止:代码本身已经很清楚 userID := middleware.GetUserIDFromContext(ctx) @@ -248,6 +257,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { ``` ### Go 代码风格 + - 使用 `gofmt` 格式化 - 遵循 [Effective Go](https://go.dev/doc/effective_go) - 包名: 简短、小写、单数、无下划线 @@ -256,6 +266,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { ## 数据库设计 **核心规则:** + - ❌ 禁止建立外键约束 - ❌ 禁止使用 GORM 关联关系标签(foreignKey、hasMany、belongsTo) - ✅ 关联通过存储 ID 字段手动维护 @@ -264,6 +275,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { ## Go 惯用法 vs Java 风格 ### ✅ Go 风格(推荐) + - 扁平化包结构(最多 2-3 层) - 小而专注的接口(1-3 个方法) - 直接访问导出字段(不用 getter/setter) @@ -271,6 +283,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { - 显式错误返回和检查 ### ❌ Java 风格(禁止) + - 过度抽象(不必要的接口、工厂) - Getter/Setter 方法 - 深层继承层次 @@ -282,6 +295,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { **本项目不使用任何形式的自动化测试代码。** **绝对禁止:** + - ❌ **禁止编写单元测试** - 无论任何场景 - ❌ **禁止编写集成测试** - 无论任何场景 - ❌ **禁止编写验收测试** - 无论任何场景 @@ -292,15 +306,18 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { - ❌ **禁止在文档中提及测试要求** - 规范、设计文档均不讨论测试 **唯一例外:** + - ✅ **仅当用户明确要求**时才编写测试代码 - ✅ 用户必须主动说明"请写测试"或"需要测试" **原因说明:** + - 业务系统的正确性通过人工验证和生产环境监控保证 - 测试代码的维护成本高于价值 - 快速迭代优先于测试覆盖率 **替代方案:** + - 使用 PostgreSQL MCP 工具手动验证数据 - 使用 Postman/curl 手动测试 API - 依赖生产环境日志和监控发现问题 @@ -349,23 +366,27 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { ## Code Review 检查清单 ### 错误处理 + - [ ] Service 层无 `fmt.Errorf` 对外返回 - [ ] Handler 层参数校验不泄露细节 - [ ] 错误码使用正确(4xx vs 5xx) - [ ] 错误日志完整(包含上下文) ### 代码质量 + - [ ] 遵循 Handler → Service → Store → Model 分层 - [ ] 函数长度 ≤ 100 行(核心逻辑 ≤ 50 行) - [ ] 常量定义在 `pkg/constants/` - [ ] 使用 Go 惯用法(非 Java 风格) ### 文档和注释 + - [ ] 所有注释使用中文 - [ ] 导出函数/类型有文档注释 - [ ] API 路径注释与真实路由一致 ### 幂等性 + - [ ] 创建类写操作有 Redis 业务键防重 - [ ] 状态变更使用条件更新(`WHERE status = expected`) - [ ] 余额/库存变更使用乐观锁(version 字段) @@ -381,6 +402,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { 1. **路由层中间件**(粗粒度拦截) - 用于明显的权限限制(如企业账号禁止访问账号管理) - 示例: + ```go group.Use(func(c *fiber.Ctx) error { userType := middleware.GetUserTypeFromContext(c.UserContext()) @@ -404,6 +426,7 @@ func (h *AccountHandler) Create(c *fiber.Ctx) error { - 无需手动调用 **统一错误返回**: + - 越权访问统一返回:`errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")` - 不区分"不存在"和"无权限",防止信息泄露 @@ -522,6 +545,7 @@ func RedisOrderCreateLockKey(carrierType string, carrierID uint) string **使用方式**: 1. **Service 层集成审计日志**: + ```go type Service struct { store *Store @@ -585,3 +609,18 @@ func RedisOrderCreateLockKey(carrierType string, carrierID uint) string > "任务 3.1 在当前实现中可能不需要,是否可以跳过?" **详细规范和 OpenSpec 工作流请查看**: `@/openspec/AGENTS.md` + +# English Learning Mode + + The user is learning English through practical use. Apply these rules in every conversation: + + 1. **Always respond in Chinese** — regardless of whether the user writes in English or Chinese. + + 2. **When the user writes in English**, append a one-line correction at the end of your response in this format: + → `[natural version of what they wrote]` + No explanation needed — just the corrected phrase. + + 3. **When the user mixes Chinese into English** (e.g., "I want to 实现 dark mode"), translate the Chinese word/phrase inline and continue naturally. Do not make a + big deal of it. + + 4. **Never interrupt the flow** to give grammar lessons. Corrections are silent and brief — the user's focus is on the task, not the language.