feat(db): sync db to staging#34
Merged
Merged
Conversation
Wraps `supabase db reset --linked`, `sync-from-prod.sh staging`, and a TRUNCATE of admin_roles into one command. After it finishes you sign up on the staging UI and call bootstrap_super_admin yourself — the script can't sign you up. sync-from-prod.sh now honors SKIP_CONFIRM=1 so the wrapper can call it non-interactively after the wrapper's own confirmation.
The script now takes an admin email argument and fully provisions the account: it creates the auth user via the admin Auth API (email_confirm true) and runs bootstrap_super_admin. Password comes from ADMIN_PASSWORD or is generated and printed. Re-runs are safe — an already-registered email is kept rather than treated as an error. Needs STAGING_URL and STAGING_SERVICE_ROLE_KEY in scripts/.env.sync.
Lists STAGING_PROJECT_REF, STAGING_DB_PASSWORD, STAGING_URL, and STAGING_SERVICE_ROLE_KEY, which the recreate-staging script needs but the example file never documented.
The direct connection host (db.<ref>.supabase.co) is IPv6-only and fails with "could not translate host name" on IPv4 networks. The session pooler host is IPv4-compatible and works with pg_dump/psql. https://claude.ai/code/session_01T7UYCNxqTRMB4HJ6pk1nEm
Prod data can pre-date the slug-dedupe migration, so restoring it into a target that already has the artists_slug_unique constraint fails. Drop the constraint before restore, then dedupe and re-add it afterwards. https://claude.ai/code/session_01T7UYCNxqTRMB4HJ6pk1nEm
Seed data does not belong in migrations -- supabase/seed.sql is the supported mechanism. The hardcoded roster and system@boom-voter.local auth user (which also needed pgcrypto's gen_salt) are removed; the file is kept as a no-op so migration history stays intact where it already ran. https://claude.ai/code/session_01T7UYCNxqTRMB4HJ6pk1nEm
soundcloud_followers and stage_name live on our enriched row types but aren't real columns. Supabase-js now flags them via RejectExcessProperties on .insert/.update, so destructure them out of the payload.
The main JS bundle exceeds the workbox 2 MiB default, which fails the Vercel build. Bump maximumFileSizeToCacheInBytes so the bundle is precached. https://claude.ai/code/session_01T7UYCNxqTRMB4HJ6pk1nEm
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Deploy →
|
There was a problem hiding this comment.
Pull request overview
This PR focuses on making staging (and local) database environments reproducible from the current branch by improving the prod→target sync workflow, removing hardcoded seed data from migrations, and adding tooling/docs to support a clean staging rebuild.
Changes:
- Add a full staging rebuild script (
db reset+ prod sync + admin bootstrap) and make the existing sync script automation-friendly. - Neutralize a prior “seed artists” migration so data seeding is handled via
supabase/seed.sqland/or sync scripts. - Prevent client-side mutations from attempting to write computed/non-table fields (
stage_name,soundcloud_followers) into Supabase tables.
Reviewed changes
Copilot reviewed 51 out of 51 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
vite.config.ts |
Increases Workbox max cacheable asset size for PWA builds. |
supabase/migrations/20250811140000_add_festival_logo.sql |
Makes bucket creation idempotent via ON CONFLICT DO NOTHING. |
supabase/migrations/20250620080928_seed_artists_data.sql |
Converts prior hardcoded seed migration into a no-op while preserving history. |
src/hooks/queries/sets/useUpdateSet.ts |
Strips stage_name from set updates before sending to Supabase. |
src/hooks/queries/sets/useCreateSet.ts |
Strips stage_name from set inserts before sending to Supabase. |
src/hooks/queries/artists/useUpdateArtist.ts |
Strips computed soundcloud_followers from artist updates before sending to Supabase. |
skills-lock.json |
Adds a skills lockfile used for agent tooling. |
scripts/sync-from-prod.sh |
Adds SKIP_CONFIRM and attempts to relax/reapply artist slug uniqueness around restore. |
scripts/recreate-staging.sh |
New end-to-end staging recreation script (reset + sync + admin bootstrap). |
scripts/.env.sync.example |
Updates guidance on which Supabase connection string to use for pg_dump/psql. |
package.json |
Adds db:recreate:staging script entry. |
.agents/skills/** |
Adds Supabase-related agent skill reference content and templates. |
The artists slug-uniqueness constraint is owned by a separate PR and is not present in this repo's migrations, so the sync script no longer drops/dedupes/re-adds artists_slug_unique. Also clarify that the DB URL env vars accept any valid postgres connection URL. https://claude.ai/code/session_01L4WM1ni4NX1mpWUdGkVodk
20250620121419 and 20250620121752 inserted a hardcoded artist roster and relied on a profiles row (for artists.added_by) created by the already -neutralized 20250620080928 seed migration. With that profile gone they fail with a not-null violation on a fresh DB. Neutralized to no-ops, consistent with the seed-data-belongs-in-seed.sql decision. https://claude.ai/code/session_01L4WM1ni4NX1mpWUdGkVodk
Interpolating ADMIN_EMAIL into the SQL string broke on emails containing a single quote. Pass it via psql -v and quote with :'email' instead. https://claude.ai/code/session_01L4WM1ni4NX1mpWUdGkVodk
chiptus
commented
May 20, 2026
undefined properties are dropped during JSON serialization, so a field absent from the caller's updates is still not written. Only the derived slug needs a conditional. Drops the per-field if guards. https://claude.ai/code/session_01L4WM1ni4NX1mpWUdGkVodk
psql -c sends the string straight to the server without running the variable-interpolation lexer, so :'email' was passed literally. Reading the statement from stdin lets psql substitute and safely quote it. https://claude.ai/code/session_01L4WM1ni4NX1mpWUdGkVodk
…umns updateSet/updateArtist whitelist fields when building the payload, but their parameter types still advertised columns (created_by, id, slug, added_by, ...) that were silently dropped. Narrow the input types to a Pick of the actually-writable columns so unsupported fields are caught at the call site. SetFormDialog now adds created_by only on create. https://claude.ai/code/session_01L4WM1ni4NX1mpWUdGkVodk
chiptus
commented
May 20, 2026
The sets table has an update_updated_at_column() trigger (update_sets_updated_at), so setting updated_at in the mutation payload is redundant. The artists table lacks that trigger -- tracked in #38. https://claude.ai/code/session_01L4WM1ni4NX1mpWUdGkVodk
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.