Skip to content

feat: add staging environment with prod sync and migration CI#30

Merged
chiptus merged 22 commits intomainfrom
claude/environment-sync-setup-OSX1B
May 9, 2026
Merged

feat: add staging environment with prod sync and migration CI#30
chiptus merged 22 commits intomainfrom
claude/environment-sync-setup-OSX1B

Conversation

@chiptus
Copy link
Copy Markdown
Owner

@chiptus chiptus commented May 9, 2026

Summary

  • Adds a staging Supabase environment alongside prod and local, wired through Vite modes (pnpm run dev for local, pnpm run dev:staging for staging).
  • Adds scripts/sync-from-prod.sh (pnpm run db:sync:{staging,local}) that pulls the public schema from prod, anonymizes PII, and upserts auth.users with rewritten emails so RLS-gated reads/writes work on synced data.
  • Adds .github/workflows/db-migrate.yml: PRs touching supabase/migrations/** auto-push to staging; merges to main auto-push to prod. Posts a single status comment on the PR (success or failure).
  • Drops the unused develop branch from CI triggers.
  • Pins Node via .nvmrc + engines in package.json.
  • Commits the magic-link email template at supabase/templates/magic_link.html and tracks key auth settings in supabase/config.toml.
  • Removes the prod URL fallback in src/integrations/supabase/client.ts — missing env vars now throw with a helpful message instead of silently hitting prod.
  • Documents the whole setup in docs/ENVIRONMENTS.md.

Test plan

  • Add the required GitHub variables (PROD_PROJECT_REF, STAGING_PROJECT_REF) and secrets (SUPABASE_ACCESS_TOKEN, {PROD,STAGING}_DB_PASSWORD).
  • In Vercel, scope VITE_SUPABASE_URL / VITE_SUPABASE_PUBLISHABLE_KEY to Production = prod values, Preview = staging values.
  • Bootstrap staging: Actions → DB Migrate → Run workflow → target = staging. Confirm migrations apply.
  • Locally: pnpm run db:sync:staging and confirm staging gets prod data with anonymized emails (user-*@example.test) and no note_content.
  • (Recommended) Add required-reviewer protection to the production GitHub environment so prod migrations pause for approval.

claude added 6 commits May 8, 2026 17:21
Adds three Vite-mode-based environments so we can test changes against a
staging Supabase project before touching prod, plus a one-way sync script
that copies prod data into staging or local with PII scrubbed.

- New scripts: dev:staging, dev:local, build:staging, db:sync:{staging,local}
- scripts/sync-from-prod.sh: pg_dump public schema -> truncate target ->
  restore -> run anonymize.sql. Refuses to write back to prod, prompts
  before overwriting, never copies auth.users.
- scripts/anonymize.sql: scrubs profiles.username, artist_notes.note_content,
  rotates group_invites.invite_token.
- .env.{,staging,local}.example templates + scripts/.env.sync.example.
- docs/ENVIRONMENTS.md walks through one-time setup and day-to-day usage.
Adds an auth.users sync step that runs before the public schema dump so
synced FK references resolve and RLS-gated reads/writes work as a test user.

- Pulls (id, email, email_confirmed_at, created_at, updated_at, aud, role)
  from prod via psql \copy into a temp table on the target.
- Upserts into auth.users with ON CONFLICT (id) DO NOTHING so existing test
  accounts on staging/local are preserved.
- Synced rows get email = user-<short-id>@example.test, no password, no
  OAuth metadata, is_super_admin = false. They can't sign in.
- Skip with SYNC_AUTH=0.

Also fixes a bogus pg_dump flag (--column-inserts=false isn't valid).
Adds .github/workflows/db-migrate.yml that runs on push to develop or main
when supabase/migrations/** changes. Resolves target from the branch (or
workflow_dispatch input), then runs supabase link + supabase db push against
the matching project.

Uses GitHub environments (staging, production) so prod migrations can later
be gated behind required-reviewer approval via repo settings.

Required secrets: SUPABASE_ACCESS_TOKEN, {PROD,STAGING}_PROJECT_REF,
{PROD,STAGING}_DB_PASSWORD. Documented in docs/ENVIRONMENTS.md.
PRs target main directly. Vercel preview deploys (any non-main branch)
point at staging Supabase, so testing happens on the preview URL before
merge.

- db-migrate.yml: only auto-runs on push to main (-> prod). Use
  workflow_dispatch with target=staging to push a PR's migrations to
  staging before merging.
- lint/unit-tests/e2e-tests: drop develop from triggers.
- docs/ENVIRONMENTS.md: rewrite the promotion flow + flag the staging
  drift caveat (abandoned PRs leave migrations on staging) and recommend
  required-reviewer protection on the production environment.
Removes the manual workflow_dispatch step from the dev loop. The DB Migrate
workflow now also runs on pull_request to main when supabase/migrations/**
changes, and resolves target=staging for that event.

supabase db push is idempotent so re-runs on each PR commit are safe.
workflow_dispatch is kept for manual re-runs and for migrating staging
when no migration file changed.
Adds a step that runs only on failure during pull_request events. Posts a
comment with a link to the failed run and a hint about common causes, so
the failure is visible in the PR conversation rather than only in the
Actions tab.

Adds the required pull-requests: write permission at the workflow level.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 9, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
upline Ready Ready Preview, Comment May 9, 2026 2:59pm

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

DB Migrate failedstaging was not updated.

View workflow run

Common causes: a migration that conflicts with the current schema, a dependency on objects that don't exist, or an out-of-order timestamp. Fix the migration and push again to re-run.

Project refs aren't sensitive (they're in dashboard URLs), so they belong
as Actions variables. Using secrets.PROD_PROJECT_REF returned an empty
string and supabase link failed.
Comment thread docs/ENVIRONMENTS.md Outdated
Comment thread docs/ENVIRONMENTS.md Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a first-class staging Supabase environment alongside prod/local, plus tooling and CI automation to keep staging data/schema aligned with production for safer preview testing.

Changes:

  • Introduces Vite modes and env templates for prod / staging / local (dev:staging, dev:local, build:staging).
  • Adds a prod→staging/local sync script (public schema restore + PII anonymization, optional auth.users sync).
  • Adds DB migration CI to push to staging on PRs and to prod on merges to main, and removes develop from CI triggers.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
scripts/sync-from-prod.sh Synces prod data into staging/local (auth user stub sync + public schema restore + anonymize).
scripts/anonymize.sql Post-restore PII scrubbing steps for synced datasets.
scripts/.env.sync.example Template for local-only DB connection strings used by the sync script.
package.json Adds Vite mode scripts and db sync script entrypoints.
docs/ENVIRONMENTS.md Documents env model, bootstrap steps, sync flow, and CI migration behavior.
.gitignore Ensures sync script credentials file is ignored.
.github/workflows/unit-tests.yml Drops develop branch trigger.
.github/workflows/lint.yml Drops develop branch trigger.
.github/workflows/e2e-tests.yml Drops develop branch trigger.
.github/workflows/db-migrate.yml New workflow to push Supabase migrations to staging/prod with PR failure comment.
.env.example Template for prod Supabase browser env vars.
.env.staging.example Template for staging Supabase browser env vars.
.env.local.example Template for local Supabase browser env vars.

Comment thread .github/workflows/db-migrate.yml Outdated
Comment thread .github/workflows/db-migrate.yml Outdated
Comment thread .github/workflows/db-migrate.yml Outdated
Comment thread scripts/anonymize.sql Outdated
Comment thread docs/ENVIRONMENTS.md Outdated
- package.json: pnpm dev now defaults to local supabase; old behavior
  moves to pnpm dev:prod
- db-migrate.yml: environment selection now event-driven (workflow_dispatch
  with target=staging from main no longer picks production); pin
  supabase-cli to 2.58.5 instead of latest; rewrite the failure-comment as
  a single-line --body so leading indentation doesn't render as a code
  block
- anonymize.sql: header comment was stale — auth.users IS now synced
  separately by sync-from-prod.sh
- docs/ENVIRONMENTS.md: spell out PII on first use; correct Vite env
  load order (.env -> .env.local -> .env.[mode] -> .env.[mode].local);
  reorder env table to put local first
…prod

The hardcoded fallback to prod URL/anon key meant that running pnpm dev
without an env file would quietly send local-dev requests to production.
Removes the fallback and throws at module load with a message pointing
to .env.local.example.

Wires VITE_SUPABASE_URL / VITE_SUPABASE_PUBLISHABLE_KEY into the e2e
workflow at job level (pointing at the local supabase started in the
Setup Supabase step) so the build and the Playwright webServer both have
them. Lint and unit tests don't import the client and don't need them.
psql -c with multi-line continuations and leading whitespace was sending
\copy to the server as SQL instead of treating it as a client meta-command.
Single line works because psql sees the leading backslash immediately.
The :'authcsv' substitution wasn't being applied — psql was trying to
open the literal string ":'authcsv'" as a file. Unquoted heredoc with
'$AUTH_CSV' lets bash do the substitution before psql sees the SQL,
which is more portable across psql versions.
…triggers

pg_dump --disable-triggers emits ALTER TABLE ... DISABLE TRIGGER ALL,
which Postgres treats as touching system triggers (RI_ConstraintTrigger_*)
and rejects without superuser — Supabase's postgres role isn't super.

Drop the flag and instead set session_replication_role=replica for the
restore session, which silences FK/constraint triggers session-wide
without per-trigger ALTERs.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

DB Migrate failedstaging was not updated. View workflow run. Common causes: a migration that conflicts with the current schema, a dependency on objects that don't exist, or an out-of-order timestamp. Fix the migration and push again to re-run.

Same fix as e2e-tests.yml — without the fallback, any test that
transitively imports the supabase client now hits the throw at module
load. Setting the local-supabase URL + demo anon key at job level keeps
the import side-effect-free for tests.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 16 changed files in this pull request and generated 6 comments.

Comment thread .env.local.example Outdated
Comment thread .env.example Outdated
Comment thread src/integrations/supabase/client.ts
Comment thread docs/ENVIRONMENTS.md
Comment thread .github/workflows/db-migrate.yml Outdated
Comment thread .github/workflows/db-migrate.yml
…cess

Old behavior posted a fresh failure comment on every failed run and never
cleaned up after a subsequent success — leaving stale comments on the PR.
New behavior:

- Always runs (success or failure) and finds prior comments via a hidden
  marker.
- On failure: upserts (PATCH if exists, create if not) — at most one
  failure comment per PR.
- On success: deletes any existing failure comment.

Also trims the canned "common causes" text since it was misleading when
the actual failure was a config issue (missing secret, etc.).
Always upserts a single status comment (success or failure) so the
current state is always visible on the PR rather than disappearing on
the happy path.
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 9, 2026

DB Migrate succeeded for stagingworkflow run.

Adds .nvmrc (22) so local devs using nvm pick up the right runtime, and
mirrors it in package.json engines (node >=22 <23, pnpm >=10) so pnpm
validates the environment on install.

Workflows now read node-version-file: .nvmrc instead of hardcoding the
version, giving us one place to bump.
- pnpm dev: 'vite --mode local' -> 'vite' (default mode=development).
  This makes .env.local the natural personal override (loaded for every
  mode but beaten by .env.[mode] / .env.[mode].local), so the awkward
  .env.local.local filename goes away.
- pnpm dev:prod: explicit '--mode production'.
- .env.example: deleted (was a duplicate "prod template" with stale
  comments). Devs only need .env.local for normal local dev.
- .env.local.example: refreshed wording, copy target is .env.local.
- client.ts: tiny tweak to error message.
- db-migrate.yml push trigger: drop the workflow file from paths so
  editing the workflow on main doesn't fire a no-op prod migration. Kept
  in pull_request paths so workflow changes are still tested on staging
  before merge.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 16 changed files in this pull request and generated 3 comments.

Comment thread scripts/sync-from-prod.sh Outdated
Comment thread package.json
Comment thread docs/ENVIRONMENTS.md
- scripts/sync-from-prod.sh: drop email column from the prod auth.users
  dump and the temp table on target. Email is recomputed from id during
  the upsert; no need to write real prod emails to disk in between.
- package.json: remove the dev:prod script. There's no .env.production*
  template and devving against prod from a laptop is a footgun.
- docs/ENVIRONMENTS.md: drop dev:prod from the day-to-day commands and
  from the env table.
@chiptus chiptus deployed to staging May 9, 2026 14:59 — with GitHub Actions Active
@chiptus chiptus merged commit 3aa7863 into main May 9, 2026
9 checks passed
@chiptus chiptus deleted the claude/environment-sync-setup-OSX1B branch May 9, 2026 15:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants