Repository navigation
feat(staging): admin staging switcher and staging sync procedure - #81
Conversation
Admins get a Developer card in Settings that signs out, sets the debate-supabase-env key that src/lib/supabase/env.ts already reads, and reloads. While staging is active, every page shows a strip with Switch to Production, and the Settings card shows to everyone. A new staging session starts signed out and need not have the admin role, so the way back cannot depend on either. If sign-out fails the switch still happens; each project keeps its own auth storage key. docs/operations.md gains the staging sync procedure, built on npm run backend:status --project-ref from plan item 6. It also records why the staging job is skipped: STAGING_E2E_ENABLED is already true, and the Quality run it waits for fails before any runner starts. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ging The switcher needs connect-src to keep allowing the staging project, which today rides on the *.supabase.co wildcard that plan item 4 wants to narrow. Only demo-code sign-in is known to work on staging from the deployed frontend; Google and email depend on staging's Auth redirect URLs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@coderabbitai full review |
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Warning Review limit reachedEnable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. Next included review available in 39 minutes. View limit detailsLimit details: You’ve used the included review currently available. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (1)
ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (5)
🚧 Files skipped from review as they are similar to previous changes (1)
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review. 📝 WalkthroughWalkthroughThe frontend now supports switching between staging and production. Switching clears local state and reloads the page; other tabs respond to environment changes. The changes also add staging-operation documentation and tests for switching behavior. ChangesFrontend environment switching
Staging operations documentation
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant SettingsPage
participant EnvironmentSwitcher
participant AuthProvider
participant switchEnv
participant EnvironmentStorage
participant OtherTab
SettingsPage->>EnvironmentSwitcher: Render switch control
EnvironmentSwitcher->>switchEnv: Request environment switch
switchEnv->>AuthProvider: Leave current environment
switchEnv->>EnvironmentStorage: Store target environment
switchEnv->>EnvironmentSwitcher: Reload current page
EnvironmentStorage->>OtherTab: Emit storage change
OtherTab->>AuthProvider: Discard tab state
OtherTab->>OtherTab: Reload page
Architecture SummaryArchitecture risk: 🔵 Low · up to The change affects 3 systems. Changed systems: Architecture concerns Review detailsSystems and components
Before / after behavior
Note 🎁 Summarized by CodeRabbit FreeYour organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Essentials by visiting https://app.coderabbit.ai/settings/billing. Comment |
|
|
@coderabbitai full review |
|
|
@coderabbitai full review |
|
…witch AuthProvider.signOut waits on the Supabase logout request with no timeout, and both switch controls disable themselves on click. An unresponsive staging project could therefore leave the switch pending forever, which is the trap the staging strip exists to avoid. Wait at most 4 s, the same as AuthProvider's auth operation timeout, then switch anyway. Found by Codex review. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ut hangs The persisted app stores are shared by production and staging. AuthProvider resets them only once sign-out completes and SIGNED_OUT fires, so a timed-out sign-out let one project's cached results, such as a generated case, reload into the other. AuthProvider now offers leaveEnvironment. It waits at most 4 s for sign-out, then always drops this project's stored session and resets the session, settings (keeping the interface language), sparring, debate and debate context stores. The switcher and the staging strip use it. client.ts exports AUTH_STORAGE_KEY so the key is defined once. Found by Codex review. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@coderabbitai review |
|
…he strip clickable - leaveEnvironment now clears the cached Google provider token, which export falls back to. A hung sign-out never fires SIGNED_OUT, so the token could otherwise reach the other project's account. Both paths share one helper. - It also calls the session store's clearSession, which empties the persisted form drafts and active results that resetLocalData leaves behind. - On the landing page the fixed navbar covered the staging strip and caught its clicks. The strip now stacks above it. A new Playwright test clicks Switch to Production on / and /login once the navbar has slid in. Found by Codex review. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Each tab picks its Supabase project once at startup, but all tabs share the persisted stores and merge each other's writes. After one tab switched, the others kept the old project while receiving the new project's data, so a production draft could be submitted to staging. Every tab now watches the debate-supabase-env key and reloads as soon as it points elsewhere, before the switching tab writes anything for the new project. A two-tab Playwright test covers it and fails without the listener. Found by Codex review. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… the strip - A tab that reloads because another tab switched projects now clears its own session storage first: the Google token, which export falls back to, and the sparring state. AuthProvider exposes discardLocalState for this, and leaveEnvironment uses the same function after its bounded sign-out. - The staging strip is now sticky with a fixed height, published as --staging-banner-height. The landing navigation and the app header offset by it, so on mobile the strip no longer covers the menu button. Found by Codex review. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai full review |
|
A tab that handled the storage event late reset the shared persisted stores, which by then could hold the new project's data, such as the Current Debate pointer and the theme. Follower tabs now call discardTabState, which clears only sessionStorage state (Google token, sparring). The full cleanup stays inside leaveEnvironment for the tab that switches. Found by Codex review. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
leaveEnvironment called signOut() with Supabase's default global scope, which revokes every session of the account. Switching between production and staging signed the admin out on all their other devices too. Use the local scope, which ends only this browser's session. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
# Conflicts: # docs/operations.md
|
@coderabbitai review |
|
Plan item 8 from
plans/2026-10-01-next-15.md: make staging usable.What changes
settings.developer*andsettings.envSwitch*strings that were already translated in en, hu and es.--staging-banner-height, and the landing navbar and app header sit below it.AuthProvider.leaveEnvironmentwaits at most 4 seconds for sign-out. Then it always drops this project's stored session and Google token and resets every user-specific store, including form drafts. An unresponsive project can't block the switch or leak data into the other project.debate-supabase-envkey. When another tab switches, it clears only its ownsessionStorage(Google token, sparring state) and reloads, so no tab keeps talking to the old project while sharing stores with the new one.docs/operations.md. It has five steps: confirm the ref, list what is pending, apply migrations, deploy stale functions, then verify. Steps 3 and 4 need Adam's authorization each time. The status step runsnpm run backend:status -- --project-ref <staging-ref> --checkfrom feat(ops): add a read-only backend drift check #79. Until feat(ops): add a read-only backend drift check #79 lands, the step also lists the two read-only CLI queries the script wraps.The switch is a convenience. Staging RLS and its separate accounts are the access boundary.
What I found about "enable the staging workflow"
The workflow is already enabled.
STAGING_E2E_ENABLEDhas beentruesince 2026-09-18, and the staging environment has all three secrets. The job passed 10 times, most recently on 2026-09-23. Every run since then was skipped because theQualityrun it waits for fails in 4 to 5 seconds with zero steps, which is the Actions-minutes pattern. Once Actions minutes are back, the staging job will run again. The workflow file doesn't need to change.docs/operations.mdnow records this.Staging's backend, checked read-only today against
brifeyypjauyusmkptkx:migration listcompares version numbers only. fix(db): define the legacy purge without running it #78 rewrote20260926090100_legacy_debate_cleanup.sqlafter staging had recorded it, so staging most likely ran the old body, which purged legacy rows. That only affects staging test data, but staging's function definitions match the new file while its data reflects the old one.stripe-webhookon staging is stale. It was last deployed 2026-05-20, before f7c9fd7 (2026-07-13, payment hardening) and 65cc821 (2026-08-21, the entitlement upsert fix). Production's copy is current (deployed 2026-08-21 11:04 UTC). Redeploying it to staging is step 4 of the new procedure and needs Adam's authorization.workspace-invitesisn't deployed because Workspace is hidden.I changed nothing on staging.
What actually unblocks the staging job
Qualitypush run onmain. Both triggers need one, including manualworkflow_dispatch. Actions was out of minutes from 2026-09-24 until today and is running again, so the next merge tomainshould start the staging job.STAGING_DEMO_CODE, which exists only as a GitHub environment secret, so Adam would have to supply it out of band. It also writes and deletes one test source on staging, which needs Adam's go-ahead.Note for plan item 4 (CSP)
The switcher only works while
vercel.jsonconnect-srcallows the staging project origin. Today the*.supabase.cowildcard covers it. If item 4 narrows that wildcard, it has to list both project origins.docs/operations.mdnow says so. From the deployed frontend, only demo-code sign-in is known to work on staging. Google and email sign-in depend on staging's Auth redirect URLs, which I didn't check.Verification
All at
60c3f65, run locally:EnvironmentSwitcher.test.tsx(switcher, strip, cross-tab reload),AuthProvider.behavior.test.tsx(leaveEnvironmentwith a hung sign-out,discardTabStateleaving shared stores alone) andSettingsAdminNavigation.test.tsx(who sees the card). Each failed before its fix.e2e/staging-switch.spec.ts, desktop and mobile Chromium: the strip returns to production from/and/login, the landing navbar sits below the strip, and switching in one tab reloads another. The landing test and the two-tab test each fail without their fix.docs:checkand build pass.Review
Codex (
gpt-6.1-sol, high) reviewed every push. Six rounds of findings, all checked against the code and fixed, each with a test:The seventh pass, at
60c3f65, found nothing actionable.CodeRabbit was rate-limited on every request because the open PRs share its hourly allowance. One reply said "Review finished" but posted no review and no comments. Copilot is out of quota.
CI
GitHub Actions is running again.
live-e2efails here exactly as it does on #79, #80 andmain(5 of 8 live journeys), but not because of billing or this PR. From 2026-09-27 to 2026-09-30 everylive-e2erun died in 2 to 5 seconds without a runner, so the live suite never ran against Current Debate (#72). Today's runs are the first real ones since. The live specs don't set up a current debate:The Edge "wall clock" terminations in the log come from the browser closing when the tests time out, not from slow AI calls. Fixing the live specs, for example with the
seedCurrentDebatehelper the other E2E suites use, belongs in its own PR. Earlier,browser-testsfailed once on 3 timeouts and passed on rerun with no change.🤖 Generated with Claude Code
Summary by CodeRabbit