| name | golang-constraints |
| description | Whole-lifecycle constraints for Go backend projects — spanning coding, docs, PRD, planning, design, and review; a unified three-layer architecture, no over-abstraction, no transitional schemes, tests subordinate to production design (no wrapping production vars or adding interfaces just for tests — when a mock is needed, prefer an existing low-level injection point). | Go 后端项目全生命周期规范约束:贯穿编码、文档、PRD、规划、设计、review;统一三层架构、禁过度抽象、禁过渡方案、测试服从生产设计(禁为测试包装 var 或新增 interface,需要 mock 时优先用已有低层注入点)。 Use when this capability is needed. |
| metadata | {"author":47915} |
Go 项目规范约束
适用于:Go 后端项目从需求到上线全生命周期内 AI 产出的所有产出物(代码 / 文档 / PRD / 规划 / 设计 / review)。
0. 触发与跳过
TRIGGER:编辑 .go / go.mod / go.sum;编写 Go 项目相关文档 / PRD / 规划 / 设计 / review。
SKIP:vendor/、代码生成物(*_gen.go、protobuf)、非 Go 项目。
一、核心原则
- 一致性 > 炫技 | 2. 可维护性 > 抽象性 | 3. 显式 > 灵活 | 4. 现有模式 > 新模式 | 5. 需求未明确时不引入额外设计
- 根源方案 > 过渡方案:禁止"保留旧 X 兼容""新旧并列""暂时保留"等过渡式写法。
- 一份推荐 > 并列多方案:任何场景只给一个推荐 + 理由。
通用禁止:擅自发明新分层 / 接口抽象 / 第三方依赖;为"优雅""通用性""未来扩展"提前抽象;顺手做未被要求的事。
默认策略:最简单直接的实现 / 当前仓库已有模式 / 最少抽象层 / 最少文件改动。
二、分层契约
2.1 允许的包
业务分层(受 §2.3 职责约束,构成 handler → service → repository 调用链):handler / service / repository / model(或 entity)/ dto
支撑包(不参与分层调用链,任何层可用):config / pkg
禁止擅自引入:manager / facade / adapter / domain / application / controller。usecase 一律禁止。
2.2 service 的两种形态
| 形态 | 定位 | 持有的依赖 | 命名倾向 |
|---|
| 领域 service | 单一领域业务规则 | 只持有本领域 repository | 名词:User / Order |
| 编排 service | 跨领域流程编排 + 事务一致性 | 多个领域 service + TxManager;不持有 repository | 动词:Checkout / Refund |
硬性规则:
- 领域 service 不得持有别领域的 repository 或别的 service
- 事务只能在 service 层发起;handler / repository 禁止
- 编排 service 必须用
TxManager.InTx(ctx, fn) 闭包;事务句柄通过 ctx 传递,不通过方法参数
- repository 方法签名禁止显式传
*sql.Tx 等事务句柄;从 ctx 取
- 禁止循环依赖:编排 → 领域单向
何时抽编排 service:修改 ≥ 2 个领域数据 / 需跨领域事务一致性 / 语义本身是动词流程。
2.3 各层职责
| 层 | 允许 | 禁止 |
|---|
| handler | 参数绑定、调用 service、响应转换 | 写业务逻辑、直接访问 repository |
| service(领域) | 本领域业务规则、调用本领域 repository | 持有别领域依赖、写 SQL、依赖框架对象 |
| service(编排) | 持有多个领域 service + TxManager、编排跨领域事务 | 持有 repository、写业务规则 |
| repository | 数据存取、从 ctx 取事务句柄 | 承载业务规则、返回 map[string]any |
2.4 目录结构与命名
优先遵守现有结构;若无则用扁平分层包:/internal/{handler,service,repository,config,dto,model,pkg},同包按领域拆文件(user.go / order.go)。不强制拆子包。
命名贯彻 avoid stuttering——包名已表达的语义不在标识符里重复:
| 包形态 | 类型名 | 构造函数 | 方法名 |
|---|
| 扁平分层包(多领域共存) | User / Checkout(不加 Handler/Service 后缀) | NewUser / NewCheckout | 保留领域词:CreateUser / DoCheckout |
独立单领域包(config 等) | Config | New(...) | 省略领域词:Load()(不是 LoadConfig) |
禁止:UserHandler / NewUserService / config.LoadConfig() / user_handler.go。
三、编码规则
3.1 interface
默认不创建。 仅允许:已有代码依赖 interface 注入 / 需要 mock 且已有低层注入点无法满足 / 仓库内已有 ≥ 2 个落地实现。新增前必须列出 ≥ 2 个已落地实现的文件路径。
3.2 构造函数与依赖注入
- 独立单领域包 →
New(...);扁平分层包 → NewXxx(...)(只写领域名)
- 入参 ≥ 3 个 / 含可选项 → 必须用 functional options
- 依赖注入默认注入具体类型
- 禁止公开字段后置赋值、多套 New 变体
3.3 context
请求链路方法必须以 context.Context 作为第一参数。禁止用 context.Background() 替代上游 ctx、把 Web 框架专属 context 传入 repository、把 ctx 存入 struct。
3.4 错误处理
必须显式处理;仅在补上下文时用 fmt.Errorf("...: %w", err)。禁止 _ 忽略、无意义包装、panic 处理业务错误、多层重复包装。
3.5 日志
只记录:关键业务节点 / 外部依赖失败 / 非预期错误。禁止每函数入口打印、正常流程刷屏、记录敏感信息、既返回错误又每层重复打印。
3.6 并发
没有明确性能需求时默认不用。优先级:errgroup > sync.Mutex > channel。禁止 handler 中裸起 goroutine。
3.7 数据库访问
所有 DB 访问收敛到 repository 层。禁止混入第二套访问风格、service 直接写 SQL。
3.8 第三方库
默认:标准库 → 项目已有依赖 → 不新增。官方库优先(database/sql、net/http 等);禁止第三方封装替代。确需新增第三方库时,必须先向用户说明理由(标准库 / 已有依赖为何不满足、候选库是什么)并获明确同意,才能写入 import 或 go.mod;用户主动点名的库视为已同意。涉及版本号遵循 version-policy skill。
3.9 测试
- 命名:
TestUser_CreateUser
- 测试服从生产设计,不得反向破坏生产。需要 mock 时按优先级:
- 利用已有低层接口注入点(repository 接口、
http.Client、外部 SDK 接口)
- 重构生产代码补依赖注入
- 仅当低层确有 ≥ 2 实现时才在低层加 interface
- 禁止:为上层包 interface / var monkey-patch(
var timeNow = time.Now)/ 无断言测试 / 只覆盖 happy path
3.10 代码风格
gofmt / 命名简洁明确 / 缩小作用域 / 提前 return 减少嵌套 / 单函数单职责。统一用 any 替代 interface{}。禁止过长函数、过深嵌套、魔法数字。
3.11 go mod tidy
每次改 import 后立即运行 go mod tidy。禁止手动编辑 go.mod 的 require 块。
四、数据库访问(Go 侧绑定)
4.1 UUIDv7 主键
应用层生成 UUIDv7:Go 层 uuid.UUID / 接口层 string。handler 层做双向转换,service/repository 只接受 uuid.UUID。
4.2 软删除
软删除标记用 time.Now().UTC().UnixMicro() 写入 deleted 列。常规查询必须带 WHERE deleted = 0。
4.3 时间戳
created_at / updated_at 由 DB 自动管理。禁止 INSERT/UPDATE 显式写、Service 层手动赋值。写入后必须回读获取 DB 生成值。
4.4 时区
MySQL DSN 固定 ?parseTime=true&loc=UTC&time_zone=%27%2B00:00%27。Go 用 time.Now().UTC(),SQL 用 UTC_TIMESTAMP(6)。
五、跨场景通用约束
以下规则不仅适用于编码,也适用于文档 / PRD / 规划 / 设计 / review:
- 文档 / 代码示例必须满足上述编码规则
- 分层词汇必须与 §二 一致,禁止描述未授权分层
- PRD 行为先行(可测试句式),禁止预指定实现细节
- 规划垂直切分,禁止"先框架后业务"
- 设计必须显式标注事务边界、错误模型;interface 必须列 ≥ 2 实现
- Review 每条建议必须是根源解;发现范围外违规只标注不扩大 diff
- 禁止文档描述未落地的设计、过渡式表述、无时间表的 TODO
Source: 0xBB2B/bb-spec — distributed by TomeVault.