Review: westside-admin#4 (board 1092) — Players list (v2) — 2026-05-04 APPROVED
Verdict: APPROVED
Re-review of
forgejo_admin/westside-admin#4 (board item 1092) after v2 body edits. The three v1 schema contradictions are resolved; new 10-column allowlist verified end-to-end against the live public.players table. No further refinements required — clear to advance from todo to next_up.Headline
v2 reconciliation is complete. All ten allowlist column names exist on the live schema with the data types the ticket claims;
monthly_fee rendering is corrected to whole-dollar; the explicit "Columns NOT in v1" callout closes the loop on the v1 mistakes.Live DB Verification (2026-05-04, post-NP fix)
Queried
information_schema.columns via kubectl -n basketball-api exec postgres-9b5b87b5-5nccx -- psql -U basketball -d basketball. Result: public.players has 37 columns; SELECT COUNT(*) = 58 rows. The 10 v2 allowlist columns matched as follows:| # | Column | Live data_type | Live is_nullable | Ticket claim | Match |
|---|---|---|---|---|---|
| 1 | <code>id</code> | integer | NO | integer, NOT NULL | OK |
| 2 | <code>name</code> | character varying | NO | varchar, NOT NULL | OK |
| 3 | <code>division</code> | USER-DEFINED | YES | USER-DEFINED enum, nullable | OK |
| 4 | <code>position</code> | character varying | YES | varchar, nullable | OK |
| 5 | <code>jersey_number</code> | character varying | YES | varchar, nullable | OK |
| 6 | <code>jersey_size</code> | USER-DEFINED | YES | USER-DEFINED enum, nullable | OK |
| 7 | <code>contract_status</code> | USER-DEFINED | NO | USER-DEFINED enum, NOT NULL | OK |
| 8 | <code>subscription_status</code> | USER-DEFINED | NO | USER-DEFINED enum, NOT NULL | OK |
| 9 | <code>monthly_fee</code> | integer | YES | integer DOLLARS, nullable | OK |
| 10 | <code>created_at</code> | timestamp without time zone | NO | timestamp without time zone, NOT NULL | OK |
Every name, type, and nullability matches the live schema. The three previously-broken columns (
email, team_name, updated_at) are confirmed absent from public.players and correctly relocated to the "Columns NOT in v1" section with the right rationale (parents.email, player_teams M2M, only created_at exists).Template Completeness (Feature)
- [x] Type — Feature
- [x] Lineage — hard deps documented (#6, #1, #2, #3) plus indirect platform deps (#301, #302)
- [x] Repo —
forgejo_admin/westside-admin - [x] User Story —
story-westside-admin-admin-row-crud - [x] Context — first end-to-end seam, justifies players-first scope
- [x] v1 Column Allowlist — 10 cols, all schema-verified, with explicit NOT-in-v1 callout
- [x] File Targets — Create + Modify + Do NOT Create lists
- [x] Acceptance Criteria — 11 items, each verifiable
- [x] Test Expectations — integration + unit + manual
- [x] Constraints — scopedDb only, SSR only, pure CSS, allowlist inline, 10 cols, no JOINs
- [x] Checklist — PR / screenshot / Lighthouse
- [x] Related — project page, arch notes, dependency / blocks links
- [x] Edit Log — v1 → v2 transition documented in body
Traceability
- [x]
story:admin-row-crudlabel — present on board item 1092 - [x] Story note verified —
story-westside-admin-admin-row-crudexists, AC #1 ("Index page lists all visible tables...") and AC #4 ("paginated, type-aware grid... 50/page, filter inputs, enums as badges, dates formatted") are exactly the surface this ticket implements (READ half of the story) - [x] Story listed on
project-westside-adminuser-stories section (table-4000) - [x]
arch:page-serverlabel — present on board item 1092 - [~] Arch note — no standalone
arch-page-servernote exists, but this is consistent with the rest of board-westside-admin (no per-componentarch-Xnotes forscoped-db,hooks-server,keycloak,harboreither). Thearch:page-serverlabel references the page-server component withinarch-dataflow-westside-adminFlow 1 (cited in the issue body's Related section). Inherited acceptable from v1 review per project convention. - [x] Forgejo issue —
forgejo_admin/westside-admin#4, state OPEN, valid URL
File Targets
- [x] Create
src/routes/players/+page.server.ts— parentsrc/routes/exists;players/subdir does not yet, will be created by the agent. OK. - [x] Create
src/routes/players/+page.svelte— same, OK. - [x] Create
src/lib/components/EnumBadge.svelte— parentsrc/lib/components/exists (currently empty). OK. - [x] Create
src/lib/components/DateCell.svelte— same, OK. - [x] Create
src/lib/components/JsonbCell.svelte— same, OK. (Ticket explicitly notes JsonbCell is shipped now for parity with #29 even though v1 allowlist doesn't include a jsonb column.) - [x] Modify
src/routes/+layout.svelte— file exists at expected path. OK.
Repo Placement
Issue is filed on
forgejo_admin/westside-admin; all file targets are inside that repo. No cross-repo work. OK.Dependencies
Hard deps: #6 (qa), #1 (todo), #2 (qa), #3 (todo). Of these, #1 and #3 are still in
todo — both belong to arch:scoped-db, which is the helper this ticket consumes (scopedDb.select(allowlistedColumns).from(players)). The dev agent for #4 cannot start until #1 and #3 land. This blocker chain is correctly documented in the body's Lineage section ("Hard depends on #6, #1, #2, #3"); it does not invalidate scope but does mean #4 cannot advance to in_progress until #1 + #3 reach at minimum qa. Indirect platform deps (#301 done, #302 qa) are also tracked.Blocks: #29 (edit page) — correctly noted.
Acceptance Criteria
11 AC. Each has an objective verification path: AC1 (50 rows, id ASC) is a count + ordering assert; AC2 (10 columns) is a snapshot or column-count test; AC3 (pagination) is a URL test; AC4 (name filter) is a query-param test; AC5 (4 enum badges) is a render assert; AC6 (DateCell) is a render assert; AC7 (
$NN) is a string-format test; AC8 (no contract_token in HTML) is a body-grep assert; AC9–10 (auth) inherit from #2's already-tested handlers; AC11 (58 rows live) is a manual visual confirm against the production DB. All testable.Blast Radius
This is a NEW route (
/players) on a NEW app (westside-admin) with no existing UI users beyond Lucas + Marcus. Risk is contained. Sensitive-column exclusion (contract_token) is enforced both at the allowlist level AND by integration test grep (AC8) — defense in depth. The ticket explicitly forbids JOINs to parents or teams in v1, which keeps the auth/scoping seam single-table and matches the scoped-db design (#1, #3). No similar routes exist elsewhere to drift from.Decomposition Assessment
6 file targets, 11 AC, ~15-25 min of agent work. Slightly over the 5-minute rule, but: (a) already split — #4 list / #28 inputs / #29 edit; (b) further splitting fragments the load→render seam; (c) v1 review already accepted this. No further decomposition needed.
Recommendation
APPROVED — no action needed. v2 body resolves every
[BODY] recommendation from the v1 review. Ticket is ready to advance from todo to next_up once its hard-dep chain (#1, #3) clears.Related
- Prior review:
review-1092-2026-05-04(NEEDS_REFINEMENT, v1) - Forgejo issue:
forgejo_admin/westside-admin#4(state: open) - Board item: 1092 on
board-westside-admin(column: todo) - Story:
story-westside-admin-admin-row-crud - Project:
project-westside-admin