Review: Tenant-scoped Drizzle query helper

review-1091-2026-04-25 Review

review needs-refinement

Verdict: NEEDS_REFINEMENT

Note: Both READY and APPROVED are accepted as passing verdicts by the check-board-advance hook. This ticket needs minor refinement before todo.

Template Completeness

  • [x] Type — Feature
  • [x] Lineage — "Depends on Drizzle setup ticket" (issue #1)
  • [x] Repo — forgejo_admin/westside-admin
  • [x] User Story — story-westside-admin-admin-row-crud
  • [x] Context — clear motivation, swap-point design, lint enforcement rationale
  • [x] File Targets — Create + Modify + Do NOT modify lists present
  • [x] Acceptance Criteria — 6 ACs, behavioral + type-system + lint + comment
  • [x] Test Expectations — unit + integration described
  • [x] Constraints — no JWT-derived tenant_id (v1), Drizzle typed builders only
  • [x] Checklist — PR / ACs / lint verification
  • [x] Related — project page + arch note linked

Traceability

  • [x] story:admin-row-crud label — present
  • [x] story note verified — found in project-westside-admin user-stories table (story-westside-admin-admin-row-crud, Admin role, "Zero psql UPDATEs / zero fix-X texts over 30 days")
  • [x] arch:scopeddb-helper label — present
  • [ ] arch note MISSING — [SCOPE] No arch-scopeddb-helper note exists in pal-e-docs. The project page Architecture section lists three arch notes: arch-domain-westside-admin, arch-dataflow-westside-admin, arch-deployment-westside-admin. The issue body's Related section points to arch-dataflow-westside-admin — that is the actual backing arch note. Either (a) update the board label to arch:dataflow-westside-admin to match an existing arch note, or (b) create a dedicated arch-scopeddb-helper sub-component note. Recommend (a) since scopedDb is a layer in the data-flow diagram, not a standalone component.
  • [x] type:feature label — present
  • [x] Forgejo issue — https://forgejo.tail5b443a.ts.net/forgejo_admin/westside-admin/issues/3 — open

File Targets

Repo forgejo_admin/westside-admin currently contains only README.md on main — no src/ tree exists yet. This is expected: every File Target listed is part of the dependent ticket chain (scaffolding #6 → Drizzle setup #1 → this ticket #3). File Targets cannot be live-verified against the repo; they are scoped relative to the post-#1 tree.
  • [~] src/lib/server/tenant.ts (Create) — path well-formed, plausible after Drizzle setup
  • [~] src/lib/server/scopedDb.ts (Create) — path well-formed
  • [~] src/lib/server/db.ts (Modify) — issue #1 explicitly creates src/lib/server/db.ts; consistent
  • [~] package.json (Modify) — root path, will exist after scaffolding #6
No live grep possible. Dev agent must verify after #6 + #1 land. Acceptable for backlog→todo.

Repo Placement

OK. All file targets are in westside-admin; matches the issue's Repo header. No multi-repo fan-out needed.

Dependencies

  • Hard blocker: westside-admin issue #1 "Drizzle setup + drizzle-kit pull schema.ts" (board item #1089, also backlog) — creates src/lib/server/db.ts and schema.ts that this ticket modifies. Lineage line on issue body acknowledges this.
  • Implicit blocker: westside-admin issue #6 "scaffolding" (board item #1087, backlog) — must create the SvelteKit project shell before #1 can run.
  • Downstream: All arch:page-server tickets (#1092 issue #4, #1093 issue #5) consume scopedDb, plus the hooks-server ticket (#1090 issue #2). Shipping this ticket unblocks the entire admin row-crud surface.
  • Documented? Lineage section names "Drizzle setup ticket" but does not name issue #1 or scaffolding #6. [BODY] minor: pin Lineage to "Depends on #1 (Drizzle setup), which depends on #6 (scaffolding)."

Acceptance Criteria

All 6 ACs are agent-verifiable:
  • AC1–AC2: SQL output assertions — verifiable by snapshot test of the generated query.
  • AC3: TypeScript type error on system-table misuse — verifiable via expectTypeOf or tsc --noEmit on a negative-fixture file.
  • AC4: CI lint check fails on direct db import — verifiable by running the lint script on a fixture import.
  • AC5: 6+ unit tests — quantitative, easy to verify.
  • AC6: multi-line swap-procedure comment in tenant.ts — verifiable via grep.
Test Expectations cleanly map to ACs. Integration test ("manually mutating tenant_id in URL or form body still produces correct WHERE clause") is the strongest signal — that's the data-leak guarantee. Solid.

Blast Radius

  • Same pattern elsewhere: basketball-api owns the source-of-truth tenant_id columns. westside-admin is the first Drizzle consumer; westside-app + westside-contracts use raw pg. No same-bug-elsewhere risk yet, but the pattern set here will inform any future Drizzle adoption.
  • Downstream consumers: Every admin page-server load function (#1092, #1093) and hooks-server import (#1090) will couple to this API surface. Shipping a wrong API shape causes rebases on 3+ tickets. The decision to expose builders select / update / insert rather than a query-string helper is correct (composes with arbitrary where/and/or per the constraint), but agent should sanity-check Drizzle's actual builder API before locking signatures.
  • Lint enforcement risk: A grep-based lint that fires on import { db } from '$lib/server/db' is brittle to renames or re-exports. Acceptable for v1 per the issue's framing. Flag for arch-note follow-up, not a blocker here.
  • Tenant constant location: TENANT_ID = 1 in a TS file works for v1. The swap-point comment is the discipline. Acceptable.

Decomposition Assessment

4 file targets (2 create + 2 modify), 6 ACs, ~6 tests + 1 integration test. Estimated agent work: 30–60 min one-pass (TypeScript generics for the tenant-vs-system table type discrimination is the only non-trivial piece). No decomposition needed. Within the 5-minute-rule envelope for a single agent.

Recommendation

  • [SCOPE] Resolve arch:scopeddb-helper label mismatch. Either (preferred) relabel the board item to arch:dataflow-westside-admin to match the existing arch note that the issue's Related section already points to, or create a new arch-scopeddb-helper sub-component note under arch-dataflow-westside-admin. Ava's call.
  • [BODY] Pin Lineage to explicit issue numbers: "Depends on #1 (Drizzle setup) which depends on #6 (scaffolding)." Helps the dev agent and downstream readers.
Once the arch label resolves and Lineage is pinned, this ticket is READY. Scope, ACs, file targets, and constraints are all crisp. Strong ticket.