# From the api package directory, link the service to its configcd packages/apirailway service create apirailway link# Railway auto-reads packages/api/railway.toml.# Set env vars in the dashboard or via CLI:railway variables --set "DATABASE_URL=\${{Postgres.DATABASE_URL}}"railway variables --set "AUTH_PROVIDER=better-auth"railway variables --set "AUTH_API_BASE_URL=https://api.enqr.dev/auth"railway variables --set "BETTER_AUTH_SECRET=<paste-32-byte-secret>"railway
Migrations run on boot via RUN_MIGRATIONS_ON_BOOT=true (default). Watch
the deploy log:
railway logs --tail# Should see "migrations up-to-date" then "api listening port=8080"
Open https://app.enqr.dev/sign-in — you should see the email/password
sign-in form (since AUTH_PROVIDER=better-auth). Sign up with a test
email; verify you land on /app.
cd /Users/dom/work/development/projects/enquire# Build the production bundleVITE_CLOUD_BRIDGE_URL=wss://bridge.enqr.dev/ws \VITE_CLOUD_API_URL=https://api.enqr.dev \VITE_CLOUD_WEB_URL=https://app.enqr.dev \VITE_AUTH_PROVIDER=better-auth \npm run build:store# Output: dist/chrome-mv3-store (manifest mode "store" — no debugger permission)npm run zip:store# Output: .output/chrome-mv3.zip
Once DNS resolves and all three services are live:
# 1. Web sign-up creates user in DBcurl -i -X POST https://api.enqr.dev/auth/sign-up/email \ -H "Content-Type: application/json" \ -d '{"email":"e2e@enqr.dev","password":"hunter2hunter2","name":"E2E"}'# Capture the set-auth-token header value as $TOKEN.# 2. Bridge accepts the token via /auth/get-sessionTOKEN="<paste here>"node -e "import WebSocket from 'ws';const ws = new WebSocket('wss://bridge.enqr.dev/ws?token=' + encodeURIComponent('$TOKEN'));ws.on('open', () => { console.log('✓ tunnel up'); ws.close(); });ws.on('error', console.error);"
Railway auto-keeps the previous deploy and lets you redeploy it via the
dashboard's "Deployments" tab. Vercel does the same via the project's
"Deployments" panel.
For schema rollbacks: drizzle-kit doesn't auto-generate down migrations.
Keep manual rollback SQL in packages/api/migrations/rollback/ if you
need them; migrations are forward-only by default.
API 503 on /auth/get-session: the bridge calls this endpoint to verify
tokens. If it fails, the bridge fails-open on its 5s timeout. Check API
logs for auth verify failed — usually a stale BETTER_AUTH_SECRET.
Bridge 401 on every WS upgrade: extension is sending a token the bridge
can't verify. Check that AUTH_API_BASE_URL on the bridge matches the
API's BETTER_AUTH_URL. Inspect bridge /__diag/ws (dev-only endpoint;
keep it disabled in prod by NOT setting LOG_LEVEL=debug).
Stripe webhook 400 with WEBHOOK_SIGNATURE_INVALID: Stripe's
test-mode and live-mode signatures use different secrets. In Railway,
set the appropriate STRIPE_WEBHOOK_SECRET for whichever mode you're in.
Web sign-in returns 500: if AUTH_API_BASE_URL points at a different
host than BETTER_AUTH_URL, the cookie-domain mismatch breaks
session validation. Both should resolve to the same API host.