Review: Admin queue view for Marcus
Verdict: NEEDS_REFINEMENT
Template Completeness
- [x] Type — Feature
- [x] Lineage — Standalone
- [x] Repo — forgejo_admin/twitch-2k-wager
- [x] User Story — As Marcus (operator), wants to see paid challengers + gamertags
- [x] Context — adequate operator motivation, ADMIN_SECRET auth decision stated
- [x] File Targets — 3 new files specified
- [x] Acceptance Criteria — 7 items
- [x] Test Expectations — 3 items
- [x] Constraints — present (auth pattern, dark theme, minimal)
- [x] Checklist — present
- [x] Related — references #12, story note, arch note
Traceability
- [x] story:game-status label — present on board item
- [x] story note exists — story-twitch-2k-wager-game-status (id 1159) found in pal-e-docs
- [ ] story mismatch — [SCOPE] The story
story-twitch-2k-wager-game-statusis written from the Challenger perspective ("As a challenger, I want to see on the website that my payment was received"). This ticket is from the Operator (Marcus) perspective ("As Marcus, I want to see a list of people who have paid"). These are different user roles with different needs. Recommend creatingstory-twitch-2k-wager-operator-queueand re-labeling the board itemstory:operator-queue. - [x] arch:dataflow-twitch-2k-wager label — present on board item
- [x] arch note verified — arch-dataflow-twitch-2k-wager (id 1155) exists. Diagram includes "Operator declares winner" flow which directly aligns with this ticket.
- [x] Forgejo issue — forgejo_admin/twitch-2k-wager#40, open
File Targets
- [x]
src/routes/admin/+page.svelte— NEW file. Parentsrc/routes/exists. No existingadmin/directory. Correct placement for SvelteKit page route. - [x]
src/routes/admin/+page.server.ts— NEW file. Server load function to fetch games from DB. Correct SvelteKit pattern. - [x]
src/routes/admin/+layout.server.ts— NEW file. Auth guard for admin routes. Correct SvelteKit pattern. - [ ] MISSING target — [BODY]
src/lib/db.tsmust be added to File Targets. The admin page needs a new query function (e.g.listAllGamesWithChallengers()) that joins thegameandchallengertables. Current DB functions are insufficient:listQueuedGames()returns only queued games with no challenger join;listGamesByChallenger()filters to a single challenger. The admin page needs all games (across all statuses) with challenger info.
Repo Placement
OK. Issue filed on forgejo_admin/twitch-2k-wager, all file targets are in this repo. Single-repo change. No cross-repo concerns.
Dependencies
- [x] #12 (Stripe Connect payout + admin result) —
validationcolumn, Forgejo issue closed. The admin page calls/api/admin/resultwhich exists atsrc/routes/api/admin/result/+server.ts. Satisfied. - [x] #9 (Postgres schema + db.ts) —
donecolumn. DB layer and types exist. Satisfied. - [x] #13 (Game status UI + email receipts) —
validationcolumn. Challenger-facing, independent from admin view. No dependency.
No unresolved dependencies that block execution.
Acceptance Criteria
- [x] "
/admin?key=ADMIN_SECRETshows the queue" — testable, clear - [ ] "Each game shows: gamertag, email, tier amount, pot amount, status, timestamp" — [BODY] gamertag data gap. The
Challengertype (src/lib/types.ts) hastwitch_usernameandemailbut nogamertagfield. The frontend (+page.svelte,play/+page.svelte) collects gamertag input but the checkout API (/api/checkout/+server.ts) callsupsertChallenger(twitchId, twitchUsername, email)— gamertag is never persisted. Either: (a) clarify thattwitch_usernameserves as the display identifier (update AC wording), or (b) add a gamertag column (separate prerequisite ticket touching schema + checkout API). - [x] "Challenger Wins / Marcus Wins buttons on each active game" — testable, clear
- [x] "Clicking a result button calls /api/admin/result" — testable, existing endpoint
- [x] "Completed games show result + payout status" — testable
- [x] "Auto-refreshes (poll every 5s)" — testable
- [x] "Mobile-friendly" — testable visually
Blast Radius
- Auth pattern divergence: The existing admin result endpoint (
src/routes/api/admin/result/+server.ts) authenticates viaAuthorization: Bearer ADMIN_SECRETheader. This ticket proposes query-param auth (?key=ADMIN_SECRET) for the admin page. Two different auth mechanisms for the same admin surface. The agent needs guidance on how the page JS should authenticate calls to/api/admin/result— either include a Bearer header from client-side JS, or have the layout guard set a cookie that the API also accepts. [BODY] Add a note in Constraints clarifying how admin page authenticates API calls. - No external blast radius. Admin page is internal operator tooling. No downstream consumers affected.
- Rollback is straightforward — delete the 3 new files and the DB function.
Decomposition Assessment
3 new file targets + 1 DB function modification, all in 1 repo. 7 AC items but they describe a single cohesive page. Estimated agent time: 3-4 minutes for a standard SvelteKit CRUD page with server load + auth guard + polling.
No decomposition needed — fits the three-thing limit (3 new routes + 1 db function = one coherent feature) and five-minute rule. No independent subtasks worth parallelizing.
Prerequisite: the gamertag data gap must be resolved before dispatching. If it requires a schema migration, that becomes a separate prerequisite ticket.
Recommendation
- [SCOPE] Create user story
story-twitch-2k-wager-operator-queue("As an operator, I want to see paid challengers and their gamertags so I can invite them and declare results"). Add to project-twitch-2k-wager user-stories table. Update board item #814 label fromstory:game-statustostory:operator-queue. - [BODY] Add
src/lib/db.tsto File Targets: "AddlistAllGamesWithChallengers()function joining game + challenger tables for the admin view." - [BODY] Resolve gamertag data gap: clarify in AC whether
twitch_usernameis the display identifier (rename "gamertag" to "twitch username" in AC), or scope a prerequisite ticket to add a gamertag column to the challenger table and update the checkout flow. - [BODY] Add to Constraints: "Admin page JS must include
Authorization: Bearer ADMIN_SECRETheader when calling/api/admin/result, matching the existing endpoint's auth pattern. The layout guard validates the query param on initial page load and stores the secret client-side for subsequent API calls."