Review: SvelteKit app: Keycloak + Stripe + game state
Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type -- Feature
- [x] Lineage -- references #4 (playground), #1 (infra), #3 (kustomize)
- [x] Repo -- forgejo_admin/twitch-2k-wager
- [x] User Story -- well-formed, covers end-to-end challenger flow
- [x] Context -- thorough, lists all subsystems to wire up
- [x] File Targets -- 12 files to create
- [x] Acceptance Criteria -- 10 items
- [x] Test Expectations -- 4 items
- [x] Constraints -- no Tailwind, adapter-node, match playground
- [x] Checklist -- standard
- [x] Related -- lists all backing notes
All required feature template sections present. Template is complete.
Traceability
- [x] story:challenger-auth -- verified: story-twitch-2k-wager-challenger-auth exists in pal-e-docs
- [x] story:challenger-pay -- verified: story-twitch-2k-wager-challenger-pay exists in pal-e-docs
- [x] story:game-status -- verified: story-twitch-2k-wager-game-status exists in pal-e-docs
- [x] story:winner-payout -- verified: story-twitch-2k-wager-winner-payout exists in pal-e-docs
- [x] story notes verified -- all 4 stories listed in project-twitch-2k-wager user-stories section
- [x] arch:twitch-2k-wager-app -- label present. No exact arch note with slug "arch-twitch-2k-wager-app" exists, but arch-domain-twitch-2k-wager, arch-dataflow-twitch-2k-wager, and arch-deployment-twitch-2k-wager all exist and cover the app component. Acceptable -- the arch label refers to the app component described across the three architecture notes.
- [x] arch notes verified -- all three architecture notes exist in pal-e-docs
- [x] Forgejo issue -- forgejo_admin/twitch-2k-wager#7, state: open
Traceability is complete. All four story notes and all three architecture notes verified.
File Targets
- [x] All 12 files are creates in a repo that currently only has README.md -- no conflicts possible
- [x] src/routes/+page.svelte -- landing page from playground
- [x] src/routes/+layout.svelte -- app layout with auth state
- [x] src/routes/game/[id]/+page.svelte -- game status page
- [x] src/routes/auth/callback/+server.ts -- Keycloak OIDC callback
- [x] src/routes/api/webhooks/stripe/+server.ts -- Stripe webhook handler
- [x] src/routes/api/admin/result/+server.ts -- declare winner endpoint
- [x] src/routes/api/checkout/+server.ts -- create Checkout session
- [x] src/routes/payout/+page.svelte -- Connect onboarding redirect
- [x] src/lib/db.ts -- Postgres connection + queries
- [x] src/lib/stripe.ts -- Stripe client helpers
- [x] Dockerfile -- production container
- [x] svelte.config.js, package.json, vite.config.ts -- project config
File targets are valid. Greenfield repo -- all creates, parent directories will be created by SvelteKit scaffold.
Repo Placement
OK. Issue filed on forgejo_admin/twitch-2k-wager, which is the correct target repo for the SvelteKit app. Kustomize overlay work is correctly tracked as a separate ticket (#3) on pal-e-deployments.
Dependencies
- #1 Service onboarding (needs_approval) -- BLOCKER. Keycloak realm + Twitch IdP + CNPG + funnel must exist before this app can function.
- #3 Kustomize overlay (todo) -- BLOCKER for deployment. App can be built without it, but cannot deploy.
- #2 Stripe spike (next_up) -- SOFT BLOCKER. Spike findings should inform Stripe Checkout + Connect implementation. Risk of rework if spike discovers issues with Connect Express deferred onboarding or webhook patterns. Not documented as a dependency in Lineage.
- #4 Landing page prototype (needs_approval) -- Upstream. PR #13 merged. Playground HTML/CSS is the source for the SvelteKit promotion. Documented in Lineage.
Missing dependency: #2 (Stripe spike) is not listed in the Lineage section but its findings directly affect this ticket's Stripe implementation.
Acceptance Criteria
10 acceptance criteria covering 7 distinct subsystems:
- Keycloak OIDC auth (AC 1)
- Stripe Checkout session creation (AC 2)
- Stripe webhooks confirm payment + update DB (AC 3)
- Admin endpoint declares winner + triggers payout (AC 4)
- Stripe Connect first-time onboarding (AC 5)
- Stripe Connect repeat auto-transfer (AC 6)
- Revenue split DB tracking (AC 7)
- Email receipts to winner and loser (AC 8)
- Mobile-first dark theme matches playground (AC 9)
- Dockerfile builds and runs on port 3000 (AC 10)
Each AC is individually testable, but together they represent 7+ independent integration concerns. The Stripe Connect flow alone (deferred onboarding + account.updated webhook + transfer creation) is a multi-step integration. An agent cannot verify all of these in a single pass.
Blast Radius
Greenfield service -- no blast radius to existing services. The email sending pattern is new to this project; westside-contracts and basketball-api have their own email implementations that are unaffected. Rollback is trivial since this is a new service with no existing consumers.
Decomposition Assessment
NEEDS DECOMPOSITION -- route to skill-decompose-ticket.
Three-thing limit and five-minute rule assessment:
- File targets: 12+ files -- exceeds the 3-file guideline by 4x
- Acceptance criteria: 10 items -- exceeds the 5 AC guideline by 2x
- Distinct subsystems: 7 (Keycloak OIDC, Stripe Checkout, Stripe Connect, webhooks, Postgres schema, admin API, email)
- Estimated agent time: 30-60 minutes minimum -- 6-12x the 5-minute limit
- Independent subtasks that could be parallelized: After scaffold + DB schema, Keycloak auth and Stripe Checkout are independent. After both, admin endpoint and game status page are independent.
Recommended decomposition into 6 sub-tickets:
- SvelteKit scaffold + playground promotion -- package.json, svelte.config.js, vite.config.ts, Dockerfile, +layout.svelte, +page.svelte (from playground). Pure setup, no integrations. AC: builds, runs on port 3000, matches playground design.
- Postgres schema + db.ts -- src/lib/db.ts with connection pool + all table creation (challengers, games, payments, payouts, revenue_splits). AC: tables created on startup, queries exported.
- Keycloak OIDC auth flow -- src/routes/auth/callback/+server.ts, +layout.svelte auth state. AC: Twitch login via Keycloak works, session returned, username displayed.
- Stripe Checkout + webhook -- src/routes/api/checkout/+server.ts, src/routes/api/webhooks/stripe/+server.ts, src/lib/stripe.ts. AC: three tiers create sessions, webhook confirms payment, game status updated in DB.
- Admin result + payout flow -- src/routes/api/admin/result/+server.ts, src/routes/payout/+page.svelte. AC: admin declares winner, Connect onboarding for first-time winners, auto-transfer for repeat winners, revenue split when Marcus wins.
- Game status page + email receipts -- src/routes/game/[id]/+page.svelte, email sending. AC: game status page shows state transitions, winner/loser emails sent.
Each sub-ticket targets 2-3 files, 1-2 AC, and fits within the 5-minute agent window. Sequential dependency chain: 1 then 2, then 3 and 4 in parallel, then 5, then 6.
Recommendation
[DECOMPOSE]10 AC across 7 subsystems and 12+ files. Estimated 30-60 min agent time. Route to skill-decompose-ticket with the 6-ticket breakdown above.[BODY]Add #2 (Stripe spike) to the Lineage section as a dependency: "Depends on #2 (Stripe spike findings)."