面向开发团队的规格模板示例
模板真正有价值的地方,不是格式统一,而是让团队在高风险信息上别再漏写。
快速结论
至少写清 Goal、Non-goals、Acceptance Criteria、Edge Cases、Contract Impact 和 Rollout Plan。只要这些部分足够明确,模板就已经比大多数“完整文档”更实用。
你应该先看什么
- Feature Spec 负责业务行为、边界和验收。
- API Spec 负责契约、错误语义、兼容策略和幂等约束。
- DB Spec 负责字段、约束、迁移和回滚策略。
可直接复用的示例
# 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 的价值在于提前解决了"外键删除时怎么处理"、"谁有权限写这张表"、"回填数据的范围和风险"——这些问题如果留到迁移脚本里临时决策,代价很高。
如何为变更选择合适的模板
不是所有变更都适合同一张模板。选错模板会导致规格覆盖了不重要的内容,却遗漏了高风险的部分。以下决策树帮助判断应该用哪种模板,或是否需要组合使用。
- 纯业务行为变更(无 API 变更、无 DB 变更):使用 Feature Spec。重点写 Acceptance Criteria 和 Edge Cases。合规、权限、并发路径单独成条。
- 新增或修改 API 端点:使用 API Spec,并在 Feature Spec 中引用。API Spec 必须覆盖错误码、幂等性、向后兼容性和弃用窗口。Feature Spec 描述业务目的,API Spec 描述可执行契约。
- DB schema 变更(新表、新字段、修改约束):使用 DB Spec。必须覆盖迁移步骤、回滚策略、索引影响和权限模型。
- 跨服务集成或第三方 API 接入:同时写 API Spec(自己暴露的端点)和 Contract Spec(依赖方的行为假设)。明确写出"如果依赖方返回非预期响应,我方的降级行为"。
- 数据迁移或回填任务:单独写 Migration Spec,内容包括:受影响行数估算、回滚判断条件、锁表风险、幂等校验逻辑、执行时间窗口。
一次较大的功能发布通常需要 Feature Spec + API Spec + DB Spec 三份文档。将它们分开而不是合并到一份超长文档,好处是:每份规格的评审人不同,合并后 PM 会被迫审阅 DB 字段约束,而 DBA 会被迫审阅业务验收标准——双方都在浪费时间。
落地建议
选当前在做的一个功能,用这张模板里的字段从头填一遍。填不下去的地方,就是规格里还没回答的问题。提前发现比实现时发现便宜多了。
相关文章
编辑说明
本指南涵盖 面向开发团队的规格模板示例,面向 Spec-First 工程团队。示例为说明性场景,非生产代码。
- 作者详情: Daniel Marsh
- 编辑政策: 我们如何审核和更新文章
- 纠正: 联系编辑