Review: Replace Connect with refund + payout portal
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]Addsrc/routes/payout/+page.svelteto file targets as "DELETE — old Connect onboarding status page."[BODY]Addsrc/lib/__tests__/stripe.test.tsto file targets — existing Connect tests need removal/update.[BODY]Clarify email scope: addsrc/lib/email.tsto 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.