Skip to content

Clinic Portal — Staging / Production Environments

Branch Railway environment Service Supabase
main production clinic-theonset-app Onset (emxrmjysvxeboavhatry)
develop staging clinic-theonset-app-staging Onset-staging (lzpyfohgfdohrtlamzek)

Production: https://clinic.theonset.app
Staging: https://clinic-theonset-app-staging-staging.up.railway.app


Railway staging service

Project: disciplined-beauty → environment staging → service clinic-theonset-app-staging

  • Connected to GitHub repo Last-1-Enterprises/clinic.theonset.app
  • Source branch: develop — connect in Railway → service → Settings → Source (one-time; initial deploy used railway up)
  • Dockerfile build (railway.toml)

Staging env vars (set via Railway CLI or dashboard)

Variable Notes
NEXT_PUBLIC_SUPABASE_URL https://lzpyfohgfdohrtlamzek.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY staging anon JWT
SUPABASE_SERVICE_ROLE_KEY staging service-role JWT
NEXT_PUBLIC_APP_URL https://clinic-theonset-app-staging-staging.up.railway.app
NEXT_PUBLIC_ONSET_APP_URL https://develop.onset-web.pages.dev or https://theonset.app
PATIENT_PII_ENCRYPTION_KEY Separate from prod (base64url, 32 bytes)
STRIPE_SECRET_KEY / NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY Stripe test keys only
STRIPE_SOLO_MONTHLY_PRICE_ID / STRIPE_SOLO_ANNUAL_PRICE_ID Solo $59/mo, $499/yr — run npm run stripe:pricing (test key) to mint
STRIPE_PRACTICE_MONTHLY_PRICE_ID / STRIPE_PRACTICE_ANNUAL_PRICE_ID Practice $129/mo, $1,090/yr
STRIPE_PRACTICE_SEAT_MONTHLY_PRICE_ID / STRIPE_PRACTICE_SEAT_ANNUAL_PRICE_ID Per-seat $39/mo, $390/yr (licensed quantity)
STRIPE_FULLSCRIPT_ADDON_MONTHLY_PRICE_ID / STRIPE_FULLSCRIPT_ADDON_ANNUAL_PRICE_ID Fullscript add-on for Solo $29/mo, $290/yr
STRIPE_TRIAL_DAYS 14 — card-required trial granted on first Practice checkout
STRIPE_WEBHOOK_SECRET Test webhook we_1Tjn5pJBZ5q5XOPpd48kyyk6 (set in Railway only)
NOTIFY_FUNCTION_SECRET Staging-specific; must match staging Supabase edge function secret
CLINIC_SUPPORT_INBOX_EMAIL Optional; default ryan@theonset.app — portal Help tool email destination
SENDGRID_API_KEY Optional on Railway; required for portal Help emails with attachments (otherwise tickets save but email fails)
PROTOCOL_IMPORT_SECRET Staging-specific
CRON_SECRET Staging-specific
FULLSCRIPT_CLIENT_ID / FULLSCRIPT_CLIENT_SECRET Fullscript sandbox OAuth app
FULLSCRIPT_API_BASE https://api-us-snd.fullscript.io for sandbox
FULLSCRIPT_WEBHOOK_SECRET Webhook HMAC secret from Fullscript dashboard
FULLSCRIPT_TOKEN_ENCRYPTION_KEY Optional; base64url 32-byte key (or reuse PATIENT_PII_ENCRYPTION_KEY)
FULLSCRIPT_INTEGRATION_ENABLED Staging: true. Production: false until compliance
FULLSCRIPT_CUSTOMER_AVAILABLE Staging: true for sandbox POC. Production: false
FULLSCRIPT_BILLING_ENABLED false until launch (blocks Solo add-on checkout)
FULLSCRIPT_EMBED_PUBLIC_KEY / FULLSCRIPT_EMBED_ENV Optional; enables in-portal embed on patient profile
CLINIC_REQUIRE_OWNER_MFA Optional; true to require owner TOTP (enable Supabase MFA first). Default unset = enrollment available, not forced

Auth session TTLs (Supabase Dashboard)

Set on both staging (lzpyfohgfdohrtlamzek) and prod (emxrmjysvxeboavhatry):

Setting Recommended Where
JWT expiry (access token) 3600 (1 hour) Auth → Settings → JWT expiry
Refresh token reuse / rotation Enabled Auth → Settings
Refresh token lifetime ≤ 7 days (604800s) if the dashboard exposes it; otherwise document current value Auth → Settings

Shorter refresh TTL is a dashboard change, not an app deploy. Coordinate with MFA rollout so owners are not locked out mid-session.

MFA (owners)

  1. Supabase Dashboard → Auth → MFA → enable TOTP
  2. Owners enroll at Settings → Security
  3. Optional hard gate: set CLINIC_REQUIRE_OWNER_MFA=true on Railway after enrollment is verified on staging

Do not copy production live Stripe keys or prod PII encryption key to staging.

See FULLSCRIPT_INTEGRATION.md for OAuth redirect URI, webhook URL, and E2E checklist.

See GOOGLE_SIGNIN.md for Google OAuth setup (Google Cloud + Supabase providers on staging and prod). Includes OAuth consent screen branding (docs/assets/google-oauth-app-logo.png). No Railway env vars — credentials are configured in Supabase Auth only.

Staging patient invite emails

Patient invites (Add Patient, quickstart, resend invite) call the practitioner-notifications Supabase Edge Function unless SENDGRID_API_KEY is set on Railway. Staging requires a one-time edge function deploy + secrets sync.

Symptom: patient saves but UI shows "email could not be delivered" — usually 404 (function not deployed) or 500 (missing SENDGRID_API_KEY on staging Supabase).

One-time setup:

cd clinic.theonset.app
cp supabase/.env.staging.example supabase/.env.staging
# Paste SENDGRID_API_KEY (same key as prod Supabase Edge secrets / SendGrid dashboard)
chmod +x scripts/supabase/deploy-staging-notifications.sh
./scripts/supabase/deploy-staging-notifications.sh

The script reads NOTIFY_FUNCTION_SECRET and PATIENT_PII_ENCRYPTION_KEY from Railway staging and mirrors them onto staging Supabase along with SendGrid.

Auth signup emails (clinic portal account confirmation) use Supabase Auth templates. Point staging Auth at the staging portal URL:

SUPABASE_ACCESS_TOKEN=sbp_xxx \
PROJECT_REF=lzpyfohgfdohrtlamzek \
SITE_URL=https://clinic-theonset-app-staging-staging.up.railway.app \
URI_ALLOW_LIST="https://clinic-theonset-app-staging-staging.up.railway.app/auth/callback,http://localhost:3000/auth/callback" \
./scripts/supabase/apply-auth-email-templates.sh

Staging email test checklist

  1. Add Patient → invite email with connection code (+ optional clinic code block)
  2. Patient detail → Resend invite
  3. Assign protocol to invited patient → protocol assigned email (edge function)
  4. (Optional) Weekly summary cron → /api/cron/weekly-summary with staging CRON_SECRET

Stripe test mode (configured)

Product: Onset Clinic Pro (Staging) (prod_UjFbg8neAbAUGC)

Plan Test price ID Amount
Monthly price_1Tjn5oJBZ5q5XOPpozzGJP5E $49/mo
Annual price_1Tjn5oJBZ5q5XOPpLovS80bh $399/yr

Webhook: https://clinic-theonset-app-staging-staging.up.railway.app/api/stripe/webhook
Events: checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, customer.subscription.trial_will_end, invoice.payment_failed.

Use Stripe test card 4242 4242 4242 4242 with any future expiry/CVC at checkout.

CLI helpers

railway environment staging
railway service link clinic-theonset-app-staging
railway variables   # inspect
railway logs
railway redeploy

Promotion flow

feature/* → develop (staging portal) → verify → main (production)

Supabase migrations: staging first, then prod (see Onset/docs/ENVIRONMENTS.md).