Railway Environment Variables
Set these in Railway for each environment. Never commit real values to the repo.
Domain Configuration — HWORK_DOMAIN
HWORK_DOMAIN is the bare email/CORS domain. It controls Specialist email addresses ({firstname}`@`{HWORK_DOMAIN}), transactional email from-address (onboarding@{HWORK_DOMAIN}), and the wildcard CORS allowlist (`*.`{HWORK_DOMAIN}).
| Service | Variable | Dev value | Staging value | Production value |
|---|---|---|---|---|
| API | HWORK_DOMAIN | dev.h852.work | h852.work | h.work |
| Frontend | NEXT_PUBLIC_HWORK_DOMAIN | dev.h852.work | h852.work | h.work |
Replaces:
SPECIALIST_EMAIL_DOMAINandNEXT_PUBLIC_APP_DOMAIN(both deprecated — remove from any env where they appear).
App URL — APP_BASE_URL
APP_BASE_URL is the public URL of the user-facing app, used in outbound user-facing replies (WhatsApp pairing prompts, etc.). It is intentionally separate from HWORK_DOMAIN because the app and the email domain are not always the same host:
| Service | Variable | Dev value | Staging value | Production value |
|---|---|---|---|---|
| API | APP_BASE_URL | https://dev.h852.work | https://staging.h852.work | https://app.h.work |
Why: dev runs the entire app on dev.h852.work (no app. prefix), while staging/prod use app.{HWORK_DOMAIN}``. Constructing URLs from HWORK_DOMAIN alone would produce https://app.dev.h852.work for dev, which doesn't exist.
Canonical environment selector — APP_ENV
APP_ENV is the canonical environment-name source for all backend services. NODE_ENV is always production in any deployed Node build, so it cannot distinguish staging from production.
| Service | Variable | Acceptable values | Notes |
|---|---|---|---|
API (api/) | APP_ENV | development | staging | production | Read by api/src/common/env.ts (IS_PRODUCTION, IS_STAGING, IS_DEV, IS_DEPLOYED). |
| Frontend (Vercel) | NEXT_PUBLIC_APP_ENV | same values | Frontend mirror — Next.js requires the NEXT_PUBLIC_ prefix to expose env to the browser bundle. Read by frontend/src/lib/env.ts. |
Agent (agent/) | APP_ENV | same values | Same convention. |
Set this per Railway environment (and per Vercel environment) — never in code. The hard-delete-org endpoint and other dev-only paths are gated on IS_PRODUCTION === false.
WhatsApp / Twilio
One inbound WhatsApp number per environment. Set WHATSAPP_PHONE_NUMBER to the E.164 number for that env. Leave it unset on environments that don't have a number provisioned yet — the UI will show "not configured" and inbound routing will be inert.
| Variable | Dev | Staging | Production |
|---|---|---|---|
WHATSAPP_PHONE_NUMBER | +18566992888 | (unset — not provisioned) | (unset — not provisioned) |
TWILIO_WEBHOOK_BASE_URL | https://api-dev-b36f.up.railway.app | https://api-staging-bd3f.up.railway.app | https://api-production-f95e.up.railway.app |
TWILIO_ACCOUNT_SID | ACb23672b636fa0d15522099ec5119bb3f (main) | same (main) | same (main) |
TWILIO_API_KEY / TWILIO_API_SECRET | (per env) | (per env) | (per env) |
TWILIO_AUTH_TOKEN | main account auth token (preferred for sig verify) | same | same |
TWILIO_SUBACCOUNT_SID / TWILIO_SUBACCOUNT_TOKEN | optional — fallback for subaccount-owned senders | same | same |
The Twilio webhook for each WhatsApp sender must be set in the Twilio Console (Messaging → Senders) to ${TWILIO_WEBHOOK_BASE_URL}/channels/whatsapp/inbound. The dev sender (+18566992888, SID XE5d4de7ff487f3fd6efc37e970205f8f9) currently points at the dev API.
Legacy data: The
whatsapp_number_pooltable still exists for back-compat with old tests, but routing readsWHATSAPP_PHONE_NUMBERdirectly. New senders are linked to orgs via pairing codes (whatsapp_linked_numbers).