面向开发团队的规格模板示例

模板真正有价值的地方,不是格式统一,而是让团队在高风险信息上别再漏写。

快速结论

至少写清 Goal、Non-goals、Acceptance Criteria、Edge Cases、Contract Impact 和 Rollout Plan。只要这些部分足够明确,模板就已经比大多数“完整文档”更实用。

你应该先看什么

可直接复用的示例

# Feature Spec
- Goal: 同租户 email 唯一
- Non-goals: 本次不做人工作业界面
- Acceptance: 重复 email 只保留最新记录
- Edge Cases: 空 email、并发写入、重复重试
- Rollout: 先灰度导入任务,再放量

API Spec 示例:Webhook 接入端点

Feature Spec 用于描述业务行为,API Spec 用于描述服务间的可执行契约。以下是一个完整的 Webhook 接入端点规格示例,展示了一个 API Spec 需要覆盖的所有关键维度。

# API Spec: POST /api/v1/webhooks/inbound

Goal: 接收第三方系统推送的事件,校验签名后持久化并触发后续处理。
Non-goals: 本版本不做事件去重;不支持批量 payload。

Endpoint: POST /api/v1/webhooks/inbound
Auth: HMAC-SHA256 签名(X-Webhook-Signature 请求头)
Request Content-Type: application/json

Request Body:
  event_type: string, 必填,取值范围见事件注册表
  payload:    object, 必填,事件相关数据
  timestamp:  ISO 8601 字符串,必填,发送方时钟时间

Success Response:
  HTTP 200
  {"status": "accepted", "event_id": ""}

Error Responses:
  400 - 缺少必填字段或 JSON 格式非法
  401 - 签名验证失败或请求头缺失
  422 - event_type 不在注册表中
  500 - 持久化失败(不重试触发器;payload 已入死信队列)

Idempotency: 同一 payload 在 30 秒内重复投递时,返回原始 event_id,不重复写入。

Edge Cases:
- 签名正确但 timestamp 超出±5 分钟窗口 → 401 含 clock_skew 错误码
- payload 超过 256KB → 413 含明确大小提示
- 触发器入队失败但 payload 持久化成功 → 200 + 异步告警,不向投递方报错

Rollout:
- 灰度:先开放给 3 个内部集成测试方
- 监控:签名失败率、死信队列堆积、p95 延迟
- 回滚:关闭路由规则,存量 payload 等待人工重推

这份 API Spec 的关键在于:每个错误码都有语义,幂等行为有明确的时间窗口,边界情况包括时钟偏移和超大 payload。联调时,消费方不需要追问任何问题就能写出对端测试。

DB Spec 示例:用户审计日志表

数据库变更的 spec 与 feature spec 的区别在于:它必须覆盖迁移、回滚对现有数据的影响,以及字段约束的语义,而不只是"加一张表"。以下是一个用户审计日志表的完整 DB Spec。

# DB Spec: user_audit_logs 表

Goal: 记录所有对 users 表的状态变更,供合规审计和事故溯源。
Non-goals: 本次不做审计查询 API;不做跨租户数据聚合视图。

Table: user_audit_logs
Engine: PostgreSQL 15+

字段定义:
  id          UUID, PRIMARY KEY, 默认 gen_random_uuid()
  user_id     UUID, NOT NULL, 外键 → users.id ON DELETE SET NULL
  actor_id    UUID, NULLABLE(系统操作时为 NULL)
  action      VARCHAR(64), NOT NULL(枚举:created/updated/deleted/suspended)
  changed_at  TIMESTAMPTZ, NOT NULL, DEFAULT now()
  before_data JSONB, NULLABLE(变更前快照,deleted 时必填)
  after_data  JSONB, NULLABLE(变更后快照,deleted 时为 NULL)
  ip_address  INET, NULLABLE
  reason      TEXT, NULLABLE

索引:
  idx_ual_user_id ON (user_id, changed_at DESC)
  idx_ual_actor_id ON (actor_id) WHERE actor_id IS NOT NULL

约束语义:
- action 字段取值必须通过 CHECK 约束,不接受枚举外的值
- ON DELETE SET NULL 确保 users 删除后审计记录保留,user_id 置空
- before_data 在 action=deleted 时由应用层强制写入,DB 层不做校验

迁移计划:
  步骤 1: 创建表和索引(无停机,新表为空)
  步骤 2: 在 users 表 update/delete 触发器中写入审计日志(应用层,不用 DB 触发器)
  步骤 3: 回填历史数据(可选,来源为现有 changelog 表)

回滚策略:
  DROP TABLE user_audit_logs(无外键依赖方向性限制,安全)
  触发器逻辑在应用层,回滚 deploy 即可关闭写入

合规要求:
- 审计记录不得修改或删除(无 UPDATE/DELETE 权限授予应用用户)
- 保留期 7 年,通过 pg_partman 按月分区归档

DB Spec 的价值在于提前解决了"外键删除时怎么处理"、"谁有权限写这张表"、"回填数据的范围和风险"——这些问题如果留到迁移脚本里临时决策,代价很高。

如何为变更选择合适的模板

不是所有变更都适合同一张模板。选错模板会导致规格覆盖了不重要的内容,却遗漏了高风险的部分。以下决策树帮助判断应该用哪种模板,或是否需要组合使用。

一次较大的功能发布通常需要 Feature Spec + API Spec + DB Spec 三份文档。将它们分开而不是合并到一份超长文档,好处是:每份规格的评审人不同,合并后 PM 会被迫审阅 DB 字段约束,而 DBA 会被迫审阅业务验收标准——双方都在浪费时间。

落地建议

选当前在做的一个功能,用这张模板里的字段从头填一遍。填不下去的地方,就是规格里还没回答的问题。提前发现比实现时发现便宜多了。

更新日期:2026-03-10

相关文章

编辑说明

本指南涵盖 面向开发团队的规格模板示例,面向 Spec-First 工程团队。示例为说明性场景,非生产代码。