Weak ticket
Add coupon codes to checkout. Make sure invalid codes do not break payment.
This is the homepage example expanded into a full case: one vague request becomes a bounded spec, implementation slices, acceptance criteria, and evidence reviewers can check before merge.
Add coupon codes to checkout. Make sure invalid codes do not break payment.
Feature: Checkout coupon code Owner: Web Checkout Status: Ready for review Context: - Checkout UI lives in apps/web/routes/checkout. - Totals are computed in packages/billing/totals.ts. - Coupon table exists but is not wired into checkout. Goal: - Let signed-in users apply one valid coupon before payment. - Show invalid, expired, and already-used codes inline. Non-goals: - No coupon admin UI. - No coupon stacking. - No rewrite of billing totals.
- [ ] Add coupon lookup by code and user. - [ ] Validate expired, disabled, and reused codes. - [ ] Recompute checkout total with one discount. - [ ] Show inline errors without clearing payment form. - [ ] Add feature flag for rollback.
- Given a valid coupon When the user applies it before payment Then the discounted total is shown and used for payment. - Given an expired code When the user applies it Then an inline error appears and the original total remains.
Automated: - coupon validation unit test - checkout total integration test - reused coupon regression test Manual: - screenshot for valid code - screenshot for invalid code - rollback flag documented
Implement only coupon application at checkout. Do not add admin UI, stacking, price rules, or totals refactors. Every changed file must map to one task and one acceptance criterion.
The spec names the totals module and blocks unrelated refactors before an AI coding tool broadens the task.
Expired, reused, and invalid coupons become concrete acceptance paths rather than late QA discoveries.
The rollback flag and evidence list tell reviewers how to pause the change if checkout metrics move.
The first review question is not "can the model build coupons?" It is "can the model change checkout without touching unrelated money logic?" That is why the packet names the totals module, blocks coupon stacking, and keeps admin tooling out of scope. Those decisions make the work smaller and make the review sharper.
The second review question is about invalid states. Coupon features fail in boring ways: expired codes still discount totals, reused coupons pass a second time, payment forms clear after an error, or rollback removes the UI without restoring the old calculation path. A thin request does not surface those cases. A useful spec packet makes them acceptance criteria before implementation starts.
The diff should only touch checkout coupon lookup, validation, total display, and the rollback flag. Admin rules, stacking, pricing plans, and billing refactors need a separate spec.
Reviewers should see a valid-code path, invalid-code path, expired-code path, reused-code path, and a total calculation test that proves the payment amount matches the displayed amount.
The feature flag must be named in the packet, and support should know what metric or complaint pattern would trigger rollback during the first release window.
Use this case when the change touches a value that users can see or dispute: money, credits, limits, entitlements, seats, quotas, or usage. The exact coupon rules may not fit your product, but the review shape usually does. Start by naming the calculation source of truth, then list the states that must not corrupt it: invalid input, expired entitlement, replayed request, partial rollout, and rollback.
The important habit is to write the failure mode before implementation starts. If the team waits until QA to discover duplicate discounts or stale totals, the fix usually requires touching more code than the original feature. The spec packet moves those questions earlier, when changing the plan is still cheap.
When an AI coding assistant is involved, paste the non-goals directly above the implementation prompt. Ask the assistant to state which task each file change satisfies. If it proposes a totals refactor, admin UI, coupon stacking, or pricing model change, the answer should be a new spec, not a larger diff inside this one.
Reject these patterns during review even when the demo looks correct. Checkout bugs often hide in state transitions, rollback behavior, and mismatches between what the page displays and what the payment system charges.
The displayed discount and charged amount must come from the same source of truth, or support will see mismatched totals.
If stacking is not in the spec, the implementation should reject or replace a second code instead of inventing a rule.
A feature flag is not enough if applied coupons leave totals, orders, or analytics in an inconsistent state.
Checkout changes need a short observation window because payment problems can appear only after real coupons, retries, and support workflows touch the feature.
Watch for any gap between displayed totals, order totals, and payment processor amounts. One mismatch should pause rollout.
Track invalid and expired code errors separately from payment failures so support can tell UX confusion from billing risk.
If the coupon touches API responses, compare with the API error case; if it requires schema changes, use the database case.
Start with the generator, then paste the packet into the issue or PR before asking an AI coding assistant to implement it.
This case is intentionally small and concrete: the goal is to show the spec boundary that prevents AI-generated implementation drift.