Skip to content

feat(rls): Phase 1 #4 — Department RLS + callsite fixes + gitignore scheduler lock#132

Merged
webdevcom01-cell merged 1 commit into
mainfrom
feat/rls-phase1-department
May 23, 2026
Merged

feat(rls): Phase 1 #4 — Department RLS + callsite fixes + gitignore scheduler lock#132
webdevcom01-cell merged 1 commit into
mainfrom
feat/rls-phase1-department

Conversation

@webdevcom01-cell
Copy link
Copy Markdown
Owner

Summary

  • Migration 20260529000000_rls_phase1_department: enables RLS + FORCE on Department, adds composite index on (organizationId, id), SELECT/INSERT/UPDATE/DELETE policies for app_user, grants to app_user + admin_user
  • 9 callsites wrapped across 3 route files:
    • departments/route.ts (GET findMany, POST parent check + create) → withOrgContext
    • departments/[departmentId]/route.tsloadDepartment() uses withAdminBypass (pre-auth lookup to discover orgId); GET/PATCH/DELETE use withOrgContext(dept.organizationId)
    • agents/[agentId]/department/route.ts → dept existence check uses withAdminBypass (agent's orgId not in scope; full cross-org isolation deferred to Agent table RLS migration)
  • .gitignore: adds .claude/scheduled_tasks.lock; removes file from git index

RLS_ENFORCEMENT_ENABLED=false — all withOrgContext wrapping is a no-op until the flag is flipped after all 14 migrations land.

Callsite audit

Three grep patterns confirmed exactly 9 callsites for prisma.department.* outside generated/test code. No workers or crons access Department directly.

Test plan

  • pnpm precheck — TS ✅ vitest ✅ ESLint ✅ (4119 tests, 307 files)
  • CI green on this PR
  • DB smoke test (post-merge): SELECT COUNT(*) FROM "Department" as app_user without app.current_org_id — must return 0 rows
  • DB smoke test: set app.current_org_id to a valid org ID — must return only that org's departments
  • Verify GET /api/departments?orgId=<id>, POST /api/departments, PATCH/DELETE /api/departments/<id> work with flag off

🤖 Generated with Claude Code

…cheduler lock

- Migration 20260529000000: enable RLS + FORCE on Department,
  composite index on (organizationId, id), SELECT/INSERT/UPDATE/DELETE
  policies for app_user, grants to app_user + admin_user
- departments/route.ts: wrap findMany(GET) and parent findUnique+create(POST)
  with withOrgContext; orgId/organizationId from validated request
- departments/[departmentId]/route.ts: loadDepartment() uses withAdminBypass
  (pre-auth lookup to discover orgId); GET findUnique, PATCH parent check +
  update, DELETE wrapped with withOrgContext(dept.organizationId)
- agents/[agentId]/department/route.ts: dept existence check uses
  withAdminBypass (agent's orgId not in scope; cross-org isolation deferred
  to Agent table RLS migration)
- .gitignore: add .claude/scheduled_tasks.lock; remove from git index

RLS_ENFORCEMENT_ENABLED=false; wrapping is a no-op until flag flip.
@webdevcom01-cell webdevcom01-cell added the e2e Run E2E tests on this PR label May 23, 2026
@webdevcom01-cell webdevcom01-cell merged commit 708e5c7 into main May 23, 2026
6 of 12 checks passed
@webdevcom01-cell webdevcom01-cell deleted the feat/rls-phase1-department branch May 23, 2026 21:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

e2e Run E2E tests on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant