弱工单
给 checkout 加优惠码。 无效码不要影响付款。
这是首页示例的完整版本:一个模糊需求被整理成范围清楚的 spec、实现切片、验收标准和可检查证据。
给 checkout 加优惠码。 无效码不要影响付款。
Feature: Checkout coupon code Owner: Web Checkout Status: Ready for review Context: - Checkout UI 位于 apps/web/routes/checkout。 - Totals 由 packages/billing/totals.ts 计算。 - Coupon 表已存在,但还没有接入 checkout。 Goal: - 允许登录用户在付款前应用一个有效优惠码。 - 对无效、过期、已使用的 code 显示内联错误。 Non-goals: - 不做优惠码后台管理。 - 不支持优惠叠加。 - 不重写 billing totals。
- [ ] 按 code 和用户查询 coupon。 - [ ] 校验过期、禁用和已使用状态。 - [ ] 用一个折扣重新计算 checkout total。 - [ ] 不清空付款表单地显示内联错误。 - [ ] 加 feature flag 作为回滚开关。
- Given 一个有效优惠码 When 用户在付款前应用它 Then 页面展示折扣后总价,并用它发起付款。 - Given 一个过期码 When 用户应用它 Then 页面显示内联错误,原始总价保持不变。
自动化: - 优惠码校验单元测试 - checkout total 集成测试 - 已使用优惠码回归测试 手工: - 有效码截图 - 无效码截图 - 回滚开关说明
只实现 checkout 优惠码应用。 不要新增后台管理、叠加规则、价格规则或 totals 重构。 每个改动文件都必须对应一个任务和一条验收标准。
spec 指明 totals 模块,也明确禁止无关重构,避免 AI 编码把任务做大。
过期、已使用、无效优惠码都变成具体验收路径,而不是 QA 后期才发现的问题。
回滚开关和证据清单让评审者知道指标异常时如何暂停变更。
第一轮评审不要先问“模型能不能做优惠码”,而是问“它能不能在不动无关金额逻辑的情况下改 checkout”。所以规格包会点名 totals 模块、禁止优惠叠加,并把后台管理排除在外。这些决定让任务变小,也让评审更明确。
第二轮评审要看无效状态。优惠码功能最常见的问题并不花哨:过期码仍然影响总价、已使用优惠码第二次通过、错误后付款表单被清空、回滚时 UI 消失但旧计算路径没有恢复。薄需求不会暴露这些情况;可用的规格包会在实现前把它们写成验收标准。
diff 应该只触及 checkout 优惠码查询、校验、总价展示和回滚开关。后台规则、叠加、价格计划和 billing 重构都需要单独规格。
评审者需要看到有效码、无效码、过期码、已使用码路径,以及证明付款金额和展示金额一致的 total 计算测试。
规格包里要写明功能开关,并说明第一轮发布时哪个指标或投诉模式会触发回滚。
当改动触及用户能看到或可能争议的数值时,可以套用这个案例:金额、积分、额度、权益、席位、配额或用量。具体优惠规则不一定适合你的产品,但评审结构通常适用。先命名计算的事实来源,再列出不能破坏它的状态:无效输入、过期权益、重复请求、部分灰度和回滚。
关键习惯是在实现前写出失败模式。如果团队等到 QA 才发现重复折扣或过期总价,修复通常会比原功能触及更多代码。规格包把这些问题前移到计划阶段,这时改方案成本最低。
如果使用 AI 编码助手,把非目标直接放在实现提示词上方,并要求它说明每个文件改动对应哪一个任务。如果它提出 totals 重构、后台管理、优惠叠加或价格模型调整,这应该变成新的规格,而不是塞进当前 diff。
即使 demo 看起来正确,也要在评审中拒绝这些模式。Checkout 问题经常藏在状态转换、回滚行为,以及页面展示金额和支付系统实际扣款不一致的地方。
展示折扣和实际扣款必须来自同一个事实来源,否则客服会看到不一致总价。
如果规格没写叠加,实现就应该拒绝或替换第二个 code,而不是发明规则。
功能开关不等于安全回滚;已应用优惠不能让订单、总价或分析数据处于不一致状态。
把这个案例用于自己的 checkout 前,先确认优惠逻辑的事实来源在哪里:后端服务、billing 包、数据库规则,还是支付渠道返回值。规格里必须明确页面展示金额和实际扣款金额如何保持一致,否则 UI 看起来正确也不能证明功能安全。
还要补上失败后的用户体验。无效码、过期码、已使用码、网络重试和灰度回滚,都应该保留原始总价并避免清空付款状态。这个检查能防止页面只在 happy path 演示中成立,实际发布后却在边界状态里制造客服工单。
这也是 checkout 类规格必须写证据的原因。
优惠码规格不能只给工程看。真正出问题时,QA 会先看到复现路径,客服会先听到用户投诉,所以规格里要提前写清他们要验证什么、如何判断严重程度。
Review note QA fixture: - valid_20_percent_coupon - expired_coupon - reused_coupon_for_same_user - disabled_coupon - second_coupon_attempt 客服处理: - 无效码:说明原始总价未改变。 - 过期码:记录活动来源和用户输入的 code。 - 总价不一致:立即升级给 billing owner。 回滚触发: - 页面展示金额、订单金额、支付渠道扣款任一不一致。 - 首轮发布窗口内出现 5 个以上总价不一致工单。
这段记录让案例更接近真实上线流程。优惠码不是一个孤立的表单校验,而是会进入支付、客服和账务对账的金额路径。
Checkout 变更需要短观察窗口,因为真实优惠码、支付重试和客服流程接触功能后,才会暴露演示里看不到的问题。
观察页面展示金额、订单金额和支付渠道扣款是否一致。任何不一致都应该暂停 rollout。
把无效、过期、已使用错误和支付失败分开记录,避免把 UX 困惑误判为计费故障。
如果优惠码影响 API 响应,继续看 API 错误分类案例;如果要改表结构,参考 数据库变更案例。
观察结束后,再决定是否扩展到叠加、后台管理或更复杂价格规则;这些都应该进入新的规格,而不是追加到当前 diff。
这个案例故意保持小而具体:重点是展示怎样用规格边界阻止 AI 生成实现偏离需求。