Review: Replace Connect with refund + payout portal

review-824-2026-04-03 Doc

review needs-refinement

Verdict: NEEDS_REFINEMENT

Template Completeness

  • [x] Type — Feature
  • [x] Lineage — Replaces Connect-based payout
  • [x] Repo — forgejo_admin/twitch-2k-wager
  • [x] User Story — clear who/want/so-that
  • [x] Context — explains Connect UX problem and new approach
  • [x] File Targets — 12 specific files listed with descriptions
  • [x] Acceptance Criteria — 8 testable conditions
  • [x] Test Expectations — 6 test items with CI pass requirement
  • [x] Constraints — 4 constraints documented
  • [x] Checklist — PR, tests, no unrelated changes
  • [x] Related — links to story notes, arch notes, domain model

Traceability

  • [x] story:winner-payout label — Winner Payout and Receipt (story note id 1160, verified on project-twitch-2k-wager user-stories table)
  • [x] story:operator-flow label — Marcus Operator Flow (story note id 1210 exists)
  • [ ] story:operator-flow MISSING from project page — [SCOPE] Add operator-flow row to project-twitch-2k-wager user-stories table
  • [x] arch:dataflow-twitch-2k-wager label — Data Flow: Twitch 2K Wager (arch note id 1155 exists)
  • [ ] arch note STALE — [SCOPE] arch-dataflow-twitch-2k-wager diagram still shows Stripe Connect Express flow (createConnectAccount, getOnboardingLink, createTransfer, account.updated webhook). Must be updated to reflect refund + payout portal flow.
  • [x] Forgejo issue — forgejo_admin/twitch-2k-wager#54, state: open

File Targets

Existing files to modify (all verified present on main):
  • [x] src/lib/stripe.ts — verified: createConnectAccount (L107), getOnboardingLink (L125), createTransfer (L143) all present for removal. createRefund to be added.
  • [x] src/routes/api/webhooks/stripe/+server.ts — verified: account.updated handler present via handleAccountUpdated function.
  • [x] src/routes/api/admin/result/+server.ts — verified: imports createConnectAccount, getOnboardingLink, createTransfer, updateConnectStatus. Connect logic confirmed.
  • [x] src/lib/schema.sql — verified: payout table exists with stripe_transfer_id, status CHECK includes 'onboarding'. Needs payout_token, payout_method, payout_handle columns.
  • [x] src/lib/db.ts — verified: exists with Payout type import. New functions needed.
  • [x] src/lib/types.ts — verified: Payout interface has stripe_transfer_id; PayoutStatus includes 'onboarding'. Challenger has stripe_connect_account_id and connect_onboarding_status.
  • [x] src/routes/admin/+page.svelte — verified: exists with game queue UI. Needs "Mark Paid" in completed section.
New files (parent directories verified or to be created):
  • [x] src/routes/payout/[token]/+page.svelte — NEW, parent dir exists (src/routes/payout/)
  • [x] src/routes/payout/[token]/+page.server.ts — NEW
  • [x] src/routes/api/payout/[token]/+server.ts — NEW
  • [x] src/routes/api/admin/mark-paid/+server.ts — NEW
Missing from file targets:
  • [ ] src/routes/payout/+page.svelte — ISSUE: old Connect onboarding status page exists but not mentioned for deletion. Will become dead code or conflict with new [token] route.
  • [ ] src/lib/__tests__/stripe.test.ts — ISSUE: existing tests likely cover Connect functions. Not listed for update.
  • [ ] src/lib/email.ts — ISSUE: AC mentions winner/loser emails but email.ts not in file targets. Unclear if templates change.
  • [ ] challenger table columns — ISSUE: stripe_connect_account_id and connect_onboarding_status become dead columns after Connect removal. Not mentioned for cleanup.

Repo Placement

OK. All work is in forgejo_admin/twitch-2k-wager. No cross-repo concerns. Schema changes, API endpoints, and UI are all in the same SvelteKit app.

Dependencies

  • [x] DB schema (issue #9, board #795) — done. Schema exists, payout table present.
  • [x] Stripe Checkout + webhook (issue #11, board #797) — validation. Payment flow working.
  • [ ] Board #798 (issue #12, "Stripe Connect payout + admin result") — in validation column. This is the OLD Connect implementation that #54 replaces. Should be marked superseded before this ticket proceeds.
  • [ ] Board #814 (issue #40, "Admin queue view for Marcus") — in needs_approval. Also touches admin page + operator-flow story. "Mark Paid" button in #54 overlaps with admin queue scope. Needs coordination.
  • [ ] Board #793 (issue #7, "SvelteKit app" umbrella) — in backlog. Parent ticket also carries story:winner-payout. #54 carves payout rework out of #7.

Acceptance Criteria

8 AC total. Assessment:
  • [x] "Challenger wins -> Stripe refund fires" — testable via Stripe mock.
  • [x] "Payout record created with unique token" — testable via DB query.
  • [x] "/payout/[token] page shows form" — testable via page render + DOM check.
  • [x] "Submitting payout form saves method + handle" — testable via POST + DB verify.
  • [x] "Admin queue shows pending payouts with handle" — testable via admin page render.
  • [x] "Mark Paid button marks payout as sent" — testable via button click + DB verify.
  • [x] "All Connect code removed" — testable via grep for removed function names.
  • [x] "Marcus wins flow unchanged" — testable by verifying existing revenue split logic still works.
All AC are testable. Two email-related AC ("winner gets email", "loser gets email") appear in the user story note but are not in this issue's AC — confirm whether email changes are in or out of scope.

Blast Radius

  • challenger table — stripe_connect_account_id and connect_onboarding_status columns become dead after Connect removal. Should be cleaned up to avoid confusion.
  • Existing tests — src/lib/__tests__/stripe.test.ts likely tests createConnectAccount, getOnboardingLink, createTransfer. Will break after removal.
  • Old payout page — src/routes/payout/+page.svelte references Connect onboarding UX. Dead page after this change.
  • Webhook handler — removing account.updated is safe since no other flow depends on it. checkout.session.completed stays.
  • Rollback — schema migration (adding columns) is forward-only but non-destructive. Connect removal is a code change, rollback via git revert.

Decomposition Assessment

NEEDS DECOMPOSITION.
  • File count: 12 file targets (7 modify + 4 new + 1 delete) — exceeds 3-thing limit.
  • AC count: 8 acceptance criteria — exceeds 5 AC threshold.
  • Test count: 6 test expectations.
  • Estimated time: Well over 5 minutes — touches DB schema, Stripe API integration, 3 new routes, 2 existing endpoint refactors, admin UI, and test updates.
  • Independent subtasks exist: Yes. Connect removal, payout portal, admin result refactor, and mark-paid endpoint are largely independent.
Recommended split into 3-4 sub-tickets via skill-decompose-ticket:
  • Remove Connect + add refund — stripe.ts cleanup, webhook cleanup, schema migration, types.ts, db.ts new functions, challenger table cleanup
  • Payout portal UI + API — new payout/[token] routes (3 files), delete old payout page
  • Admin result endpoint refactor — update result/+server.ts to fire refund + create payout token
  • Admin Mark Paid — new mark-paid endpoint + admin page UI update

Recommendation

  • [SCOPE] Add operator-flow row to project-twitch-2k-wager user-stories table. Story note exists (id 1210) but is not listed on the project page.
  • [SCOPE] Update arch-dataflow-twitch-2k-wager diagram to reflect refund + payout portal flow. Current diagram shows stale Connect Express flow.
  • [BODY] Add src/routes/payout/+page.svelte to file targets as "DELETE — old Connect onboarding status page."
  • [BODY] Add src/lib/__tests__/stripe.test.ts to file targets — existing Connect tests need removal/update.
  • [BODY] Clarify email scope: add src/lib/email.ts to file targets if email content changes, or note that existing email logic is reused unchanged.
  • [BODY] Add note about removing stripe_connect_account_id and connect_onboarding_status from challenger table schema + Challenger type.
  • [DECOMPOSE] 12 file targets, 8 AC across DB/API/UI/Stripe layers. Route to skill-decompose-ticket for sub-board creation with 3-4 sub-tickets.