# Coding Conventions

**Analysis Date:** 2026-03-27

## Naming Patterns

**Files:**
- Go 源码使用 `snake_case.go` 或按领域拆分的普通小写命名；路由文件按模块命名放在 `internal/routes/*.go`，Handler 按域放在 `internal/handler/admin/*.go`、`internal/handler/auth/*.go`、`internal/handler/app/*.go`。
- OpenAPI 与规范文档使用明确用途命名，例如 `docs/api-documentation-guide.md`、`docs/admin-openapi.yaml`、`cmd/api/docs.go`、`cmd/gendocs/main.go`。
- 规范脚本使用动词前缀命名，例如 `scripts/check-all.sh`、`scripts/check-service-errors.sh`、`scripts/check-comment-paths.sh`、`scripts/verify_migration/main.go`。

**Functions:**
- 导出函数/方法使用 Go 的 `PascalCase`，例如 `NewAccountHandler()`、`Create()`、`Success()`、`RedisOrderIdempotencyKey()`，证据见 `internal/handler/admin/account.go`、`pkg/response/response.go`、`pkg/constants/redis.go`。
- 未导出帮助函数使用 `camelCase`，例如 `generateOpenAPIDocs()`、`generateAdminDocs()`、`handleError()`、`safeLogWithLevel()`，证据见 `cmd/api/docs.go`、`cmd/gendocs/main.go`、`pkg/errors/handler.go`。

**Variables:**
- 局部变量使用英文 `camelCase`，例如 `outputPath`、`httpStatus`、`roleID`、`groupPath`，证据见 `cmd/api/docs.go`、`pkg/errors/handler.go`、`internal/handler/admin/account.go`。
- 错误变量统一使用 `err`，成功返回数据常用业务名，例如 `account`、`accounts`、`roles`，证据见 `internal/handler/admin/account.go`。

**Types:**
- 结构体和接口使用 `PascalCase`，接口语义化命名，配合 `-er` 后缀规则；项目规范明确要求接口名使用 `-er`，见 `AGENTS.md`。
- 路由文档元数据类型使用语义名，如 `RouteSpec`、`FileUploadField`，证据见 `internal/routes/registry.go`。

## Code Style

**Formatting:**
- 使用 `gofmt`；项目在 `AGENTS.md` 明确要求“使用 gofmt 格式化”。
- 代码风格遵循 Go 惯用法，避免 Java 式过度抽象；证据见 `AGENTS.md` 的“Go 惯用法 vs Java 风格”。

**Linting / Scripted Checks:**
- 仓库未检测到 `.golangci.yml`、`golangci-lint`、`eslint`、`prettier` 之类自动 lint 配置；当前质量门主要依赖 shell 脚本和人工审查。
- `scripts/check-service-errors.sh`：扫描 `internal/service/**/*.go` 中的 `fmt.Errorf`，要求改用 `errors.New()` / `errors.Wrap()`。
- `scripts/check-comment-paths.sh`：扫描 `internal/handler/` 中残留的 `/api/v1` 注释，要求改成真实路径 `/api/admin`、`/api/h5`、`/api/c/v1`。
- `scripts/check-all.sh`：串行执行以上两个检查。
- 当前仓库与脚本规则存在冲突：`internal/service/polling/alert_service.go` 仍存在 4 处 `fmt.Errorf(...)`，按 `scripts/check-service-errors.sh` 的规则属于违规现状。

## Language & Comment Requirements

**语言要求：**
- 用户可见内容、日志、注释、文档、提交信息都使用中文；变量名、函数名、类型名使用英文，证据见 `AGENTS.md` 的“语言要求”。

**注释要求：**
- 导出包、结构体、接口、函数、方法、常量、变量必须有中文文档注释，证据见 `AGENTS.md`。
- Handler 方法注释必须包含 HTTP 方法与真实路径；实际示例见 `internal/handler/admin/account.go`、`internal/handler/callback/payment.go`。
- 注释解释“为什么”，不要复述代码；复杂逻辑必须有实现注释，证据见 `AGENTS.md`。
- 常量必须带中文注释；实际示例见 `pkg/constants/constants.go`、`pkg/constants/redis.go`。

## Import Organization

**Order:**
1. Go 标准库，例如 `strconv`、`time`、`regexp`。
2. 第三方库，例如 `github.com/gofiber/fiber/v2`、`go.uber.org/zap`。
3. 项目内包，例如 `github.com/break/junhong_cmp_fiber/pkg/errors`、`internal/service/account`。

**Pattern:**
- 多数组件按“标准库 → 项目包/第三方包”分组，并保留空行分隔，证据见 `internal/handler/admin/account.go`、`pkg/errors/handler.go`、`cmd/gendocs/main.go`。
- 项目使用完整 module import path，未体现短别名路径；必要时用语义别名，例如 `apphandler`、`accountService`，证据见 `cmd/gendocs/main.go`、`internal/handler/admin/account.go`。

**Path Aliases:**
- 未检测到 TS/JS 式路径别名；Go 代码通过 module path `github.com/break/junhong_cmp_fiber/...` 引用。

## Layering Rules

**Required Architecture:**
- 必须遵循 `Handler → Service → Store → Model`，证据见 `AGENTS.md` 与 `README.md`。

**How to apply it:**
- Handler 只做参数解析、上下文读取、调用 service、返回统一响应；示例见 `internal/handler/admin/account.go`。
- Service 承载业务逻辑，并向下调用 Store；项目规范在 `AGENTS.md` 明确禁止在 Handler 中写业务逻辑。
- Store 负责数据访问和事务；规范说明见 `AGENTS.md`、`README.md`。
- Model/DTO 定义请求、响应和持久化结构；OpenAPI 文档也依赖 DTO 元数据，证据见 `docs/api-documentation-guide.md`。

## Error Handling

**Centralized package:**
- 所有错误码与应用错误类型集中在 `pkg/errors/`，证据见 `pkg/errors/codes.go`、`pkg/errors/errors.go`、`pkg/errors/handler.go`、`AGENTS.md`。

**Rules to follow:**
- Handler 层不要把底层错误直接暴露给客户端；参数校验失败统一返回 `errors.New(errors.CodeInvalidParam)` 或其中文变体，证据见 `AGENTS.md`、`internal/handler/admin/account.go`。
- Service 层对外不要返回 `fmt.Errorf(...)`，要返回 `errors.New(...)` 或 `errors.Wrap(...)`；脚本 `scripts/check-service-errors.sh` 专门检查这一点。
- 全局错误处理使用 `pkg/errors/handler.go` 的 `SafeErrorHandler()` / `handleError()`，统一输出 `{code, data, msg, timestamp}`，并按错误码映射 HTTP 状态码与日志级别。
- 5xx 响应统一走通用中文消息，避免泄露敏感信息，证据见 `pkg/errors/handler.go`。

**Error code system:**
- `pkg/errors/codes.go` 定义 1000-1999 客户端错误、2000-2999 服务端错误。
- `pkg/errors/codes.go` 在 `init()` 校验全部错误码都必须映射消息，新增错误码时要同步维护 `allErrorCodes` 和 `errorMessages`。

## Response Format

**Envelope:**
- 所有 API 成功响应统一使用 `pkg/response/response.go`：`{code, data, msg, timestamp}`。
- `Success()` 返回 `msg: "success"`；`SuccessWithMessage()` 允许覆盖消息；`SuccessWithPagination()` 将分页数据包进 `PaginationData`。

**How handlers should respond:**
- Handler 成功路径直接调用 `response.Success()` / `response.SuccessWithPagination()`；实际示例见 `internal/handler/admin/account.go`、`internal/handler/admin/iot_card.go`、`internal/handler/admin/shop.go`。
- 错误路径直接 `return err` 交给全局 ErrorHandler，不在 Handler 内手动拼接 JSON，证据见 `internal/handler/admin/account.go`、`pkg/errors/handler.go`。

## Constant Management

**Location:**
- 所有常量统一放在 `pkg/constants/`，证据见 `AGENTS.md` 与 `pkg/constants/constants.go`、`pkg/constants/redis.go`。

**Rules to follow:**
- 禁止硬编码字符串与 magic numbers；公共业务值放进 `pkg/constants/constants.go`。
- Redis Key 必须通过函数生成，而不是手写字符串，命名格式使用 `Redis{Module}{Purpose}Key(...)`，证据见 `pkg/constants/redis.go` 与 `AGENTS.md`。
- 常量要配中文注释；`pkg/constants/constants.go` 中的用户类型、任务类型、分页上限、默认管理员信息都按此方式组织。

## API / OpenAPI Conventions

**Route registration:**
- 所有 HTTP 路由都应在 `internal/routes/*.go` 中通过 `Register()` 注册，不要直接 `router.Get/Post/...`，证据见 `docs/api-documentation-guide.md`、`internal/routes/registry.go`。
- `Register()` 同时负责 Fiber 路由注册和 OpenAPI 生成；当 `doc != nil` 时，会把 `/:id` 转为 OpenAPI 的 `/{id}`，证据见 `internal/routes/registry.go`。

**RouteSpec requirements:**
- 每个接口需要提供中文 `Summary`，可选 Markdown `Description`，并声明 `Input`、`Output`、`Tags`、`Auth`；证据见 `internal/routes/registry.go`、`docs/api-documentation-guide.md`。
- DTO 字段必须使用 `description` 标签，不依赖行尾注释；枚举字段要在 `description` 中列出可选值，证据见 `docs/api-documentation-guide.md`。

**Handler + docs generator sync:**
- 新增 Handler 时，除业务接线外，还必须同步更新 `internal/bootstrap/types.go`、`internal/bootstrap/handlers.go`、`internal/routes/admin.go`、`cmd/api/docs.go`、`cmd/gendocs/main.go`，证据见 `docs/api-documentation-guide.md` 与 `AGENTS.md`。
- 文档生成命令使用 `go run cmd/gendocs/main.go` 或 `make docs`；代码证据见 `cmd/gendocs/main.go`、`Makefile`。

## Documentation Expectations

**Required docs workflow:**
- 每个功能应在 `docs/{feature-id}/` 创建总结文档，并同步更新 `README.md`，证据见 `AGENTS.md`。
- 文档和说明统一使用中文。
- API 文档规范集中在 `docs/api-documentation-guide.md`；开发总规范集中在 `AGENTS.md`。

**Repository reality:**
- `README.md` 仍保留旧的自动化测试与覆盖率章节、旧项目结构中的 `tests/` 目录描述、以及“CI/CD 自动执行检查”的表述。
- 当前仓库未发现任何 `*_test.go` 文件，也未发现 `tests/` 目录内容；因此后续文档和执行应优先遵循 `AGENTS.md` 的现行规则，而不是 `README.md` 中这些过期段落。

## Operational Scripts

**Quality / convention scripts:**
- `bash scripts/check-service-errors.sh`：检查 Service 层是否违规使用 `fmt.Errorf`。
- `bash scripts/check-comment-paths.sh`：检查 Handler 注释路径是否残留 `/api/v1`。
- `bash scripts/check-all.sh`：运行上述两个检查。

**Documentation script:**
- `make docs` → `go run cmd/gendocs/main.go`，用于生成 `docs/admin-openapi.yaml`，证据见 `Makefile`、`cmd/gendocs/main.go`。

**Migration verification helper:**
- `go run scripts/verify_migration/main.go`：这是一个面向数据库迁移结果的人工验证脚本，会直接连接数据库并查询字段，不是自动测试框架，证据见 `scripts/verify_migration/main.go`。

**Caution:**
- `Makefile` 的 `test` 目标仍定义为 `go test -v ./...`，但这反映的是旧工具入口，不代表当前团队允许自动化测试。

## Module Design

**Exports:**
- 构造函数使用 `NewXxx...`，例如 `NewAccountHandler()`、`NewGenerator()`。
- Handler、response、errors、constants 都以小包单职责方式导出少量明确入口，证据见 `internal/handler/admin/account.go`、`pkg/response/response.go`、`pkg/errors/errors.go`。

**Barrel Files:**
- 未检测到 JS/TS 式 barrel file；Go 通过包目录与导出符号组织模块。

## Prescriptive Summary

- 写新 Handler 时：在 `internal/handler/...` 保持中文注释 + 英文标识符，只解析请求并调用 Service，成功统一走 `pkg/response/response.go`，失败直接返回 `error`。
- 写新业务错误时：先在 `pkg/errors/codes.go` 注册错误码与中文消息，再用 `errors.New()` / `errors.Wrap()`。
- 写新常量或 Redis Key 时：放入 `pkg/constants/`，并补中文注释与 Key 生成函数。
- 写新 API 时：在 `internal/routes/*.go` 用 `Register()` + `RouteSpec` 注册，并同步更新 `cmd/api/docs.go` 与 `cmd/gendocs/main.go` 的文档 Handler 装配。
- 运行规范检查时：优先使用 `scripts/check-*.sh` 与 `make docs`；不要把 `README.md` 中的测试/覆盖率描述当成当前执行标准。

---

*Convention analysis: 2026-03-27*
