工程规范
Go 单仓库工程纪律 · 本地开发 · 代码规范 · 安全基线 · Runbook
文档目的
这份文档约束未来业务应用仓库的工程方式。当前技术主线是 Go 模块化单体,不采用 Rust 后端、K8s 微服务或 gRPC 服务网格。
仓库结构
text
dingwei/
├── cmd/
│ ├── api-server/main.go
│ ├── admin-api/main.go
│ └── worker/main.go
├── internal/
│ ├── auth/
│ ├── user/
│ ├── catalog/
│ ├── inventory/
│ ├── order/
│ ├── payment/
│ ├── coupon/
│ ├── delivery/
│ ├── asset/
│ └── shared/
├── pkg/
│ └── wechat/
├── migrations/
├── deploy/
│ ├── docker-compose.yml
│ └── nginx.conf
├── tests/
│ ├── integration/
│ └── fixtures/
├── docs/
│ └── adr/
├── Makefile
├── Dockerfile
└── go.modcmd/* 只组装依赖和启动进程;业务逻辑全部在 internal/*。
工具链
| 工具 | 版本/要求 |
|---|---|
| Go | 1.22+ |
| PostgreSQL | 16 |
| Valkey | 8 |
| Docker / Compose | 本地依赖和生产部署一致 |
| Migration | golang-migrate/migrate |
| 测试 | Go testing + testcontainers-go(集成测试) |
| 漏洞扫描 | govulncheck |
建议锁定版本:
text
.go-version
1.22.xMakefile 入口
makefile
.PHONY: init dev test lint build migrate-up migrate-down smoke
init:
go mod download
dev:
docker compose -f deploy/docker-compose.dev.yml up -d postgres valkey
go run ./cmd/api-server
test:
go test ./...
lint:
gofmt -w .
go vet ./...
govulncheck ./...
build:
docker build -t dingwei/api-server:dev .
migrate-up:
migrate -path migrations -database "$(DATABASE_URL)" up
migrate-down:
migrate -path migrations -database "$(DATABASE_URL)" down 1
smoke:
go test ./tests/smoke -count=1生产不使用 migrate-down 回滚;它只服务本地开发。
本地开发
text
# 第一次
make init
cp .env.example .env.local
docker compose -f deploy/docker-compose.dev.yml up -d postgres valkey
make migrate-up
# 日常
make test
make lint
go run ./cmd/api-server本地只启动依赖服务,业务进程用 go run 或 IDE 启动,便于调试。
分支与提交
| 规则 | 说明 |
|---|---|
| 主干 | main 始终可部署 |
| 任务分支 | task/TASK-xxx |
| 文档分支 | docs/xxx |
| 提交格式 | Conventional Commits |
| PR 粒度 | 一个垂直切片,普通 PR <= 500 行核心 diff,交易核心 <= 300 行 |
提交示例:
text
feat(payment): implement wechat notify idempotency
fix(order): prevent timeout cancellation after payment paid
docs(tech): unify backend architecture to go modular monolith编码规范
分层
| 层 | 允许做 | 禁止做 |
|---|---|---|
| handler | 参数绑定、校验、调用 service、错误映射 | 写业务逻辑、直接访问 DB |
| service | 业务规则、状态机、跨模块编排 | 拼 SQL、写 HTTP response |
| repo | SQL、事务、RowsAffected 检查 | 调其他模块 service |
| domain | 类型、状态、纯业务规则 | 依赖 DB、HTTP、外部 SDK |
错误处理
go
if err != nil {
return nil, fmt.Errorf("inventory lock: %w", err)
}要求:
- 每层保留错误上下文。
- handler 层把 domain error 映射为统一错误码。
- 禁止吞掉错误。
- 日志不得输出手机号、地址、openid、支付原文等敏感信息。
数据库
| 规则 | 说明 |
|---|---|
| 参数化查询 | 禁止字符串拼接 SQL |
| 写操作检查 RowsAffected | 状态机更新必须确认影响行数 |
| 事务边界明确 | service 决定事务范围,repo 执行 SQL |
| owner 写入 | 非 owner 模块不能直接写别的模块表 |
| 金额 | 使用 amount_fen BIGINT,禁止 float |
| 时间 | 使用 time.Time,数据库统一 TIMESTAMPTZ |
测试规范
| 层级 | 覆盖对象 | 要求 |
|---|---|---|
| Unit | domain、状态机、金额计算 | 快、无数据库 |
| Repo | SQL 查询、事务、唯一约束 | 临时 PostgreSQL |
| Integration | 下单、支付、库存、退款 | 跑完整模块 |
| Adapter | 微信签名、验签、回调解密 | 黄金样例,不打真实外部服务 |
| Smoke | staging/production 核心接口 | 每次发布后跑 |
核心异常场景必须覆盖:重复支付回调、库存不足、支付成功时订单已取消、超时取消与支付并发、退款失败、worker 重复消费、Valkey 不可用降级。
日志与 Trace
日志使用结构化 JSON,所有请求和 worker 事件必须带 trace_id。
json
{
"level": "info",
"ts": "2026-05-22T10:00:00+08:00",
"trace_id": "01J...",
"module": "order",
"event": "order_created",
"order_no": "DW202605220001"
}日志级别:
| 级别 | 使用场景 |
|---|---|
| debug | 本地调试,生产默认关闭 |
| info | 关键业务事件和生命周期 |
| warn | 可恢复异常、重试、降级 |
| error | 请求失败、任务失败、支付/退款异常 |
安全基线
| 项目 | 要求 |
|---|---|
| JWT | 短有效期 + token version + blacklist |
| 密码 | argon2id 或 bcrypt |
| 支付 | 微信验签、回调解密、原文留存、重复通知幂等 |
| 隐私 | 手机号/地址加密存储,日志脱敏 |
| 后台权限 | RBAC,敏感操作写 audit_logs |
| 限流 | 登录、下单、支付、退款接口必须限流 |
| 配置 | 密钥只走环境变量或部署机 secret 文件,不提交仓库 |
| 文件上传 | 校验 content-type、大小、路径前缀 |
ADR 规范
需要写 ADR 的情况:
- 新增核心依赖。
- 修改订单、支付、库存状态机。
- 改变数据库 ownership。
- 引入新的基础设施。
- 计划拆分进程或服务边界。
模板:
markdown
# ADR-0001: 标题
## 状态
Proposed / Accepted / Rejected / Superseded
## 背景
为什么需要决策。
## 决策
做什么,不做什么。
## 备选方案
列出至少一个替代方案。
## 后果
收益、成本、风险、回滚方式。Runbook
常用命令
bash
# 启动依赖
docker compose -f deploy/docker-compose.dev.yml up -d postgres valkey
# 跑测试
go test ./...
# 迁移数据库
migrate -path migrations -database "$DATABASE_URL" up
# 构建镜像
docker build -t dingwei/api-server:dev .
# 生产日志
docker compose logs -f --tail=200 api-server worker
# 查看 outbox 堆积
psql "$DATABASE_URL" -c "select status, count(*) from outbox_events group by status;"故障速查
| 症状 | 优先检查 |
|---|---|
| 下单失败 | api-server 日志、库存锁定、订单状态机、DB 事务错误 |
| 支付成功但订单未更新 | payment_notifications、payments、outbox_events、worker 日志 |
| 库存不准 | inventory_movements、inventory_locks、最近后台调整审计 |
| worker 堆积 | outbox_events failed/pending、worker 日志、DB 连接池 |
| 后台操作争议 | audit_logs、operator、before/after、reason |