# Golang Constraints

> 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.

- Skill: `tomevault-io/golang-constraints` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/golang-constraints`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/golang-constraints/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Product & Planning
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/golang-constraints

---


# Go 项目规范约束

适用于：Go 后端项目从需求到上线全生命周期内 AI 产出的**所有产出物**（代码 / 文档 / PRD / 规划 / 设计 / review）。

## 0. 触发与跳过

**TRIGGER**：编辑 `.go` / `go.mod` / `go.sum`；编写 Go 项目相关文档 / PRD / 规划 / 设计 / review。
**SKIP**：`vendor/`、代码生成物（`*_gen.go`、protobuf）、非 Go 项目。

---

## 一、核心原则

1. 一致性 > 炫技 ｜ 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` |

**硬性规则**：
1. 领域 service 不得持有别领域的 repository 或别的 service
2. 事务只能在 service 层发起；handler / repository 禁止
3. 编排 service 必须用 `TxManager.InTx(ctx, fn)` 闭包；事务句柄通过 `ctx` 传递，**不通过方法参数**
4. repository 方法签名禁止显式传 `*sql.Tx` 等事务句柄；从 `ctx` 取
5. 禁止循环依赖：编排 → 领域单向

**何时抽编排 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 时按优先级：
  1. 利用已有低层接口注入点（repository 接口、`http.Client`、外部 SDK 接口）
  2. 重构生产代码补依赖注入
  3. 仅当低层确有 ≥ 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](https://github.com/0xBB2B/bb-spec) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-06-15 -->

