Review: Stripe Checkout + webhook

review-797-2026-04-03 Doc

review ready

Verdict: READY

Template Completeness

  • [x] Type — Feature
  • [x] Lineage — Sub-ticket of #7, depends on #8 + #9, parallel with #10, uses #2 spike
  • [x] Repo — forgejo_admin/twitch-2k-wager
  • [x] User Story — challenger wants tiered pay via Stripe Checkout
  • [x] Context — Stripe Checkout with inline price_data, webhook handler, test keys
  • [x] File Targets — 3 new files specified
  • [x] Acceptance Criteria — 6 criteria
  • [x] Test Expectations — Stripe CLI listen + DB verification
  • [x] Constraints — test keys, match spike, webhook reachability
  • [x] Checklist — PR opened, tests pass, no unrelated changes
  • [x] Related — parent #7, spike #2, story note, arch note

Traceability

  • [x] story:challenger-pay — "Secure Buy-In Payment" (story-twitch-2k-wager-challenger-pay, id 1158)
  • [x] story note verified — challenger-pay entry found in project-twitch-2k-wager user-stories table
  • [x] arch:dataflow-twitch-2k-wager — "Data Flow: Twitch 2K Wager" (arch-dataflow-twitch-2k-wager, id 1155)
  • [x] arch note verified — arch-dataflow-twitch-2k-wager exists (note_type: architecture, status: active)
  • [x] Forgejo issue — forgejo_admin/twitch-2k-wager#11, state: open

File Targets

  • [x] src/routes/api/checkout/+server.ts — NEW file to create. Parent dir src/routes/ exists (scaffold merged via PR #16). Valid SvelteKit server route path.
  • [x] src/routes/api/webhooks/stripe/+server.ts — NEW file to create. Valid SvelteKit server route path for webhook handler.
  • [x] src/lib/stripe.ts — NEW file to create. src/lib/ exists (contains db.ts, types.ts, schema.sql). Consistent placement.
All file targets are new files to be created. Existing scaffold (PR #16) and DB layer (PR #15) provide the foundation. No existing line references to verify. Targets are specific enough for an agent to act on without guessing.

Repo Placement

OK. Issue filed on forgejo_admin/twitch-2k-wager, all file targets are in the same repo. Single-repo scope. No cross-repo concerns.

Dependencies

  • [x] #8 SvelteKit scaffold — satisfied (merged as PR #16)
  • [x] #9 Postgres schema + db.ts — satisfied (merged as PR #15)
  • [x] #2 Stripe spike — satisfied (merged as PR #6, FINDINGS.md at spike/stripe/FINDINGS.md)
  • [x] #10 Keycloak OIDC auth — parallel work, no dependency
All hard dependencies satisfied. Note: stripe npm package is not yet in package.json — agent must run npm install stripe as part of implementation.

Acceptance Criteria

6 criteria, all verifiable by an agent:
  • Three tier buttons create Checkout sessions — testable via unit test or API call to the endpoint
  • Stripe Checkout (hosted) opens with correct amount — verifiable via session object's amount_total field
  • Webhook receives checkout.session.completed — testable via stripe listen --forward-to
  • Game + Payment records created in DB — verifiable via SQL query after test payment
  • Challenger redirected to game status page — verifiable via Checkout session success_url config
  • Webhook signature verified — verifiable via code inspection (constructEvent call) + failing test with bad signature
All criteria are concrete and testable. No ambiguity.

Blast Radius

Low. This is a new application with no downstream consumers yet. The webhook endpoint path (/api/webhooks/stripe) is standard. No sibling services share this Stripe account (test keys are project-specific). The DB layer (db.ts) is already merged and this ticket consumes it without modifying it. Rollback is straightforward — revert the PR.
Informational (does not block this ticket): The spike FINDINGS.md recommends manual payout (CashApp/Venmo) + full refund on challenger win, which diverges from the arch-dataflow diagram showing Stripe Connect Express for payouts. This discrepancy affects ticket #12 (Stripe Connect payout), not #11. Consider updating the arch diagram or revising #12 scope before that ticket reaches review.

Decomposition Assessment

3 file targets in 1 repo. 6 acceptance criteria. Estimated agent time: ~4-5 minutes. All three files are tightly coupled (stripe.ts is consumed by both route handlers). No independent subtasks that would benefit from parallelization. Fits within the three-thing limit (3 files) and five-minute rule. No decomposition needed.

Recommendation

No action needed. Ticket is ready for execution.