From b433c7967706a83fc9898a10980b8b5d45cc29a7 Mon Sep 17 00:00:00 2001 From: default Date: Fri, 5 Jun 2026 16:45:37 +0000 Subject: [PATCH] supabase dump & restore guide (runbook for after spend cap removed) Covers: - Connection test (direct vs pooler, IPv4 vs IPv6) - pg_dump commands (schema-only and data-only) - Restore steps to local DB - Verification queries - Schema-per-brand restructure (future work) --- docs/SUPABASE_DUMP_GUIDE.md | 176 ++++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 docs/SUPABASE_DUMP_GUIDE.md diff --git a/docs/SUPABASE_DUMP_GUIDE.md b/docs/SUPABASE_DUMP_GUIDE.md new file mode 100644 index 0000000..d2bed9f --- /dev/null +++ b/docs/SUPABASE_DUMP_GUIDE.md @@ -0,0 +1,176 @@ +# Supabase Dump & Restore Guide + +This guide is the runbook for when your brother removes the Supabase +spend cap and we can finally connect to the live Supabase project to +pull the real schema + data. + +## Prerequisites + +- Brother has removed the Supabase spend cap (project status: ACTIVE_HEALTHY) +- Supabase project ref: `wnzkhezyhnfzhkhiflrp` (from CLAUDE.md) +- Supabase DB password: `YLKzP9jz2yqop7jr` (user-provided) +- Local Postgres running on `127.0.0.1:5432` (user: `routecommerce`, + password: `routecommerce_dev_password`, db: `route_commerce`) + +## Connection Test + +The Supabase hostname has NO IPv4 address from this dev box. You +must use the **Supabase Supavisor pooler** (port 6543) which resolves +over IPv4. From your home network, you can also use the direct +hostname on port 5432. + +```bash +# Direct hostname (home network only — dev box has no IPv6) +psql "postgres://postgres.wnzkhezyhnfzhkhiflrp:YLKzP9jz2yqop7jr@db.wnzkhezyhnfzhkhiflrp.supabase.co:5432/postgres" + +# Pooler (works from dev box — IPv4 only) +psql "postgres://postgres.wnzkhezyhnfzhkhiflrp:YLKzP9jz2yqop7jr@aws-0-us-east-1.pooler.supabase.com:6543/postgres" +``` + +If neither works after the cap is removed, check: +1. `getent hosts db.wnzkhezyhnfzhkhiflrp.supabase.co` — should return IPv4 +2. Supabase dashboard → Settings → API → "Direct connection" string + +## Capture Schema (no data) + +```bash +# From your home network, with the password set: +PGPASSWORD="YLKzP9jz2yqop7jr" pg_dump \ + --host=db.wnzkhezyhnfzhkhiflrp.supabase.co \ + --port=5432 \ + --username=postgres \ + --dbname=postgres \ + --schema-only \ + --no-owner \ + --no-privileges \ + --no-acl \ + --file=supabase/captured_schema.sql +``` + +This produces a SQL file with all CREATE TABLE, CREATE FUNCTION, +CREATE INDEX, etc. statements. May be 50-200 MB depending on the +function count. **Compress it before committing:** + +```bash +gzip supabase/captured_schema.sql # → captured_schema.sql.gz +``` + +## Capture Data (no schema) + +```bash +PGPASSWORD="YLKzP9jz2yqop7jr" pg_dump \ + --host=db.wnzkhezyhnfzhkhiflrp.supabase.co \ + --port=5432 \ + --username=postgres \ + --dbname=postgres \ + --data-only \ + --no-owner \ + --no-privileges \ + --no-acl \ + --disable-triggers \ + --file=supabase/captured_data.sql +``` + +Use `--disable-triggers` so the dump skips triggers that might fire +on INSERT and slow things down. Compress: + +```bash +gzip supabase/captured_data.sql +``` + +## Restore to Local DB + +```bash +cd /path/to/route-commerce +export PGPASSWORD=routecommerce_dev_password + +# 1. Wipe the synthesized schema +psql -U routecommerce -h 127.0.0.1 -d route_commerce \ + -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;" + +# 2. Apply the real schema +zcat supabase/captured_schema.sql.gz | \ + psql -U routecommerce -h 127.0.0.1 -d route_commerce \ + -v ON_ERROR_STOP=1 2>&1 | tee /tmp/schema_restore.log + +# 3. Apply the data +zcat supabase/captured_data.sql.gz | \ + psql -U routecommerce -h 127.0.0.1 -d route_commerce \ + -v ON_ERROR_STOP=1 2>&1 | tee /tmp/data_restore.log +``` + +## Verify + +```bash +# Should show ~70+ tables (not just the 70 from the synthesized schema) +psql -U routecommerce -h 127.0.0.1 -d route_commerce -c "\dt" + +# Should show actual data, not 0 rows everywhere +psql -U routecommerce -h 127.0.0.1 -d route_commerce -c "SELECT count(*) FROM brands;" +psql -U routecommerce -h 127.0.0.1 -d route_commerce -c "SELECT count(*) FROM products;" +psql -U routecommerce -h 127.0.0.1 -d route_commerce -c "SELECT count(*) FROM orders;" +``` + +## Clean Up + +```bash +# Once verified, drop the synthesized schema (no longer needed) +rm supabase/synthesized/000_base_schema.sql +git add -A +git commit -m "remove synthesized schema (real dump now in place)" +``` + +## Schema-Per-Brand Restructure (FUTURE, not in this dump) + +The user wants each brand in its own Postgres schema: +- `brand_tuxedo` — products, orders, stops, etc. for Tuxedo +- `brand_indian_river_direct` — products, orders, stops, etc. for IRD + +This is a major refactor and is **NOT** part of the dump-and-restore. +Plan for it as a follow-up phase once the data is loaded into shared +tables and the app is verified working. + +The refactor will involve: +1. Creating schemas `brand_tuxedo`, `brand_indian_river_direct` +2. Moving brand-specific tables into the appropriate schema +3. Updating all RPC SECURITY DEFINER functions to set + `search_path` based on caller brand +4. Updating server actions to set `search_path` per request +5. Updating PostgREST config to expose schemas +6. Testing brand isolation thoroughly + +## Troubleshooting + +### "password authentication failed" +Password has been rotated. Check Supabase dashboard → Settings → +Database → Reset password. The user-provided password +`YLKzP9jz2yqop7jr` may need to be reset. + +### "could not translate host name" +Dev box has no IPv6. Use the pooler hostname +`aws-0-us-east-1.pooler.supabase.com` or run from a machine with IPv6. + +### "permission denied for schema auth" +The dump includes the `auth` schema which is Supabase-managed. +Filter it out with: `--exclude-schema=auth --exclude-schema=storage +--exclude-schema=realtime --exclude-schema=supabase_functions`. + +### "relation already exists" +You forgot step 1 (DROP SCHEMA public CASCADE). The data restore +runs `INSERT` and may not recreate tables — only the schema dump +does that. + +### "out of memory" during data restore +The data file is huge. Use `--single-transaction` to keep +Postgres from spilling to disk: + +```bash +zcat supabase/captured_data.sql.gz | \ + psql -U routecommerce -h 127.0.0.1 -d route_commerce \ + --single-transaction \ + -v ON_ERROR_STOP=0 2>&1 | tee /tmp/data_restore.log +``` + +### Data dump is too big to commit +Don't commit it. The data file is in `.gitignore` and gets +re-loaded on first run via a one-shot script.