Review: Tenant-scoped Drizzle query helper
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-adminuser-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]Noarch-scopeddb-helpernote 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 toarch-dataflow-westside-admin— that is the actual backing arch note. Either (a) update the board label toarch:dataflow-westside-adminto match an existing arch note, or (b) create a dedicatedarch-scopeddb-helpersub-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 createssrc/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.tsandschema.tsthat 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-servertickets (#1092 issue #4, #1093 issue #5) consumescopedDb, 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
expectTypeOfortsc --noEmiton a negative-fixture file. - AC4: CI lint check fails on direct
dbimport — 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 / insertrather than a query-string helper is correct (composes with arbitrarywhere/and/orper 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 = 1in 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]Resolvearch:scopeddb-helperlabel mismatch. Either (preferred) relabel the board item toarch:dataflow-westside-adminto match the existing arch note that the issue's Related section already points to, or create a newarch-scopeddb-helpersub-component note underarch-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.