constitution.md §5 (Database), DATABASE_DEVELOPMENT_GUIDE, SUPABASE_CLI_LOCAL_WORKFLOW
This page consolidates everything an engineer needs to ship a database change — from a spec gate to a deployed migration with RLS coverage. If you’ve never added a table before, follow this top-to-bottom once; afterwards use it as a checklist.
When to use which workflow
Encore OS supports two migration workflows. Use the right one:
If you’re not sure, use declarative — it stays in sync with the live schema and avoids drift.
End-to-end workflow
1
Pre-flight
- Confirm the spec is at
pipeline_status: validatedor later. New tables without a spec are forbidden — seeSPEC_WORKFLOW. - Ensure
npm run supabase:startis running locally (Docker daemon + Supabase stack). - Pull main:
git fetch origin && git rebase origin/main.
2
Edit the declarative schema
Edit the relevant file under
supabase/schemas/{core}/ (e.g. supabase/schemas/hr/employees.sql). Add the table, columns, indexes, and RLS policy in the same file — the final shape of the entity lives in one place.Follow the naming conventions:- Tables:
{core}_{entity}snake_case (e.g.hr_credentials,pm_encounters). - Columns: snake_case; required audit columns
id,created_at,updated_at,org_id(tenant); soft-deletedeleted_atonly when explicit policy requires.
3
Add the RLS policy in the same edit
Every business table MUST have RLS enabled and tested. Use the template (also in For role-bounded reads (e.g. only HR managers see credentials), add a second policy. See
.cursor/rules/database-migrations.md):RLS_PATTERNS for the canonical templates (tenant + role-bounded + read/write split).For PHI tables, add the standard audit trigger:4
Generate the migration
supabase/migrations/<ts>_add_hr_credentials.sql. Review the generated SQL — if it contains anything you didn’t intend, edit the declarative file and re-diff.For an imperative change instead: supabase migration new add_hr_credentials_backfill.5
Validate before applying
- Missing
enable row level security - Policy without
org_id = auth_org_id()predicate - SECURITY DEFINER without
search_pathlockdown - Column-level grant without RLS
6
Apply locally
generate-types is required — TypeScript will fail later if you don’t.7
Add RLS tests
Every new table needs an RLS test in Run:
tests/rls/{core}/{table}.rls.test.ts. Pattern:npm run test:rls -- hr/credentials. See rls-testing skill for failure-mode debugging.8
Commit and push
Stage the declarative schema file, the generated migration, and the regenerated types together:CI runs
validate-migration, check-rls-coverage, test:rls, and architecture checks. Fix locally on failure — never --no-verify.9
Deploy to dev / prod
Migrations apply automatically on merge through the Supabase branching pipeline. See
SUPABASE_MULTI_ENV_SETUP for env wiring and SUPABASE_GO_LIVE_DASHBOARD_CHECKLIST for prod cuts.Rollback
If a migration ships and breaks something:- Do not delete the migration file. It’s already applied to dev/prod.
- Write a forward-fix migration that undoes the breaking change:
supabase migration new revert_<original_name>. - Apply locally, test, ship through the same pipeline.
- If the issue is PHI-data corruption, also create a compliance evidence entry under
docs/compliance/evidence/.
MIGRATION_ROLLBACK_STRATEGY for the full playbook.
Common mistakes (the ones reviewers will flag)
Related skills
migration-authoring— pre-flight checklist + constitutional patterns; trigger when starting any migration.rls-testing— debugging RLS test failures.test-rls— running the RLS suite scoped to a table/core.check-rls-coverage— gap report for tables missing tests.