Phase 2 schema completion + RLS + L1 (H1, L5, L1 closed)
Migrations 0005-0011 create the remaining PIP application tables.
Every user_id is now uuid REFERENCES public.users(id) ON DELETE
CASCADE, closing audit finding H1. The previous user_id text columns
that had no foreign key allowed orphaned data after user deletion.
Added migrations:
0005_user_profiles_and_api_keys.sql user_profiles, user_api_keys
0006_projects.sql projects, project_subfolders
0007_documents.sql documents, document_versions,
document_edits (chat_message_id
FK added later in 0008)
0008_chats.sql chats, chat_messages, document
_edits.chat_message_id FK
0009_workflows.sql workflows, hidden_workflows,
workflow_shares
0010_tabular_reviews.sql tabular_reviews, tabular_cells,
tabular_review_chats,
tabular_review_chat_messages
0011_rls.sql ENABLE + FORCE ROW LEVEL SECURITY
on every backend-owned table;
revokes any inherited grants to
anon/authenticated
L5 closed by 0011_rls.sql. No row-level policies are defined; the
application connects via a BYPASSRLS role and is itself the access-
control boundary. RLS sits in place as defence-in-depth so any future
direct grant fails closed. The role provisioning commands are
documented in the migration file and in docs/developer/08-migrations.md.
L1 closed in backend/src/lib/userApiKeys.ts. USER_API_KEYS_ENCRYPTION
_SECRET is now required (minimum 32 characters); the previous fallback
to SUPABASE_SECRET_KEY is removed. Rotating the Supabase key no longer
renders stored model provider API keys undecipherable.
backend/schema.sql is marked deprecated. PIP defines its schema only
through the incremental migration files. The Supabase-flavoured file
is retained as a historical reference only.
End-to-end verification against a fresh Postgres 16 database:
- All 11 migrations apply cleanly in order.
- 20 tables created (19 application tables + pip_migrations).
- RLS enabled on every backend-owned table; pip_migrations excluded.
- org_settings seeded with 10 jurisdictions, 17 PA services, 16 PA
sectors, 7-year retention, piperalderman.com.au allowlist.
- /health and /ready return ok with db: true.
- POST /auth/register grants admin role to BOOTSTRAP_ADMIN_EMAIL on
first registration.
- POST /auth/register rejects disallowed domains and short passwords
with clear messages.
- POST /auth/verify-credentials returns the same 401 for wrong
password and unknown email (no user enumeration).
- users_ensure_profile trigger auto-creates the user_profiles row.
- audit_events table records user.register and user.login.credentials.
| Repository | cpatpa/PIP |
|---|---|
| Author | Claude <noreply@anthropic.com> |
| Authored | |
| Parents | b4f7697f |
| Stats | 13 files changed , +677 , -409 |
| Part of | Phase 2 - Supabase JS → plain pg cutover across the backend |
Capture this commit into my fork
Download a Markdown prompt that tells Claude how to port this
exact commit into your working tree. Run it via
claude -p < capture-commit-d384aee8.md
from inside the repo you want the change in.