SCOPE database: review pack
For the DBA reviewing SCOPE ahead of moving it off Supabase. It describes the database as it stands. Where it goes next is not decided here.
In this folder
| File | What it is |
|---|---|
inventory.md |
Generated. Sizes and row counts, schemas, every table, foreign keys with no index, functions, triggers, grants, and every piece that is Supabase rather than PostgreSQL |
schema.sql |
Generated. pg_dump --schema-only of the four schemas the app owns (public, app, cofi, sales): tables, constraints, indexes, functions, triggers, policies and grants, with no data |
prerequisites.sql |
Hand-written. What a plain PostgreSQL needs before schema.sql will load |
review-findings.md |
Hand-written, measured 6 October 2026. Performance, indexes, concurrent writes and access controls as they stand, and the questions they raise |
On the hub, Data and technical > Database review downloads each SQL file on its own, or the
whole folder as scope-dba-pack.zip, which also carries docs/ERD.html as schema-diagram.html.
Regenerate both before handing them over, since row counts move whenever the demo is used:
python3 scripts/db/gen_dba_pack.py
Elsewhere in the repository
| File | What it is |
|---|---|
docs/ERD.html, docs/ERD.md |
The schema as a diagram, generated from the live database: one definition per table, its keys, its row-level policies and the functions that write it |
data/README.md |
The sample data set: what each CSV holds and how the tables fit together |
docs/access-and-relationships.md |
The access model in plain English, and the three places only the app enforces a rule |
supabase/migrations/ |
All 105 migrations, applied in filename order |
scripts/db/verify_*.sql |
Tests of the access rules run as real logins, each in a transaction that rolls back |
The facts in brief
- PostgreSQL 17.6, hosted by Supabase on AWS us-east-1. 431 MB in all; the largest tables
are
inspection(233k rows) andinvoice_line(209k). - The data is synthetic. Every row is generated by
scripts/generate_sample_data.pyand loaded byscripts/db/load.sh. It holds no real people and can be rebuilt from nothing. - Security lives in the database. Row-level security is on for all 67 tables in
public. The app reads through Supabase's web API (PostgREST) as the signed-in user, and writes throughSECURITY DEFINERfunctions that check the caller. All 77 of those functions pin theirsearch_path. - Entity tables use UUID keys minted on the device, because capture works offline. Reference
tables use readable codes (
SITE-RUT). - Not everything is product.
demo_baseline(the demo's reset copy),sales(an internal lead tracker) and four support tables are marked ininventory.md. - "Today" is fixed.
app.today()returns 2026-09-28, the demo date, not the clock.
Loading schema.sql somewhere other than Supabase
Run prerequisites.sql first. It creates stand-ins for the parts Supabase provides:
- the roles
anon,authenticatedandservice_role, which the grants and policies name auth.userswith anid uuidkey (two foreign keys point at it), and the functionauth.uid()storage.objects, which one function reads
psql -d scratch -f docs/dba/prerequisites.sql
psql -d scratch -f docs/dba/schema.sql
Tested on 2 October 2026 on a plain PostgreSQL 17.11:
- Every object arrived, with the same counts as the live database: 73 tables, 123 functions, 100 policies, 215 indexes, 11 triggers, 424 constraints and 3 views.
- All 123 function bodies re-validated against the loaded schema.
- 13 statements fail, and both causes are expected. One is
schema "public" already exists. The other 12 are Supabase's project-wide default-privilege settings, which run as its own admin rolesupabase_admin. That is the setting behind the over-wide grants ininventory.md, so it is right that it does not carry over.
No extension is required: the only generated keys use gen_random_uuid(), which is built in.
Not covered here
Facts the files cannot show:
- Backups and point-in-time recovery are whatever the Supabase project's plan provides. They are not set up or recorded in the repository.
- There is one environment. Migrations are applied straight to the live database, with no separate development or test database.
- There is no monitoring or alerting beyond what Supabase's dashboard shows.
Known open items: a driver's login can read the investigation columns of their own incident, and
a GM's login can read settled cost (docs/access-and-relationships.md). Default write grants on
27 tables are still to be revoked (docs/todo.md, item 12).