Skip to content

Latest commit

 

History

History
107 lines (81 loc) · 3.74 KB

File metadata and controls

107 lines (81 loc) · 3.74 KB

Production Deployment Guide

Architecture

  • Web App (Next.js) → Vercel → app.trynullsec.com
  • Worker (BullMQ + Playwright) → Railway (Docker)
  • Database → Supabase (same project: itvznvetqclwamqjrcgc)
  • Redis → Upstash (job queue via ioredis, rate limiting via REST)

1. Vercel (Web App)

Setup

  1. Import the repo in Vercel
  2. Set Root Directory to apps/web
  3. Set Framework Preset to Next.js
  4. Set Install Command to pnpm install
  5. Set Build Command to pnpm run build
  6. Vercel will resolve workspace dependencies from the monorepo root automatically with these settings

Environment Variables (Production)

NEXT_PUBLIC_SUPABASE_URL=https://itvznvetqclwamqjrcgc.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=<your anon key>
SUPABASE_SERVICE_ROLE_KEY=<your service role key>
UPSTASH_REDIS_REST_URL=<from Upstash console, REST tab>
UPSTASH_REDIS_REST_TOKEN=<from Upstash console, REST tab>
NEXT_PUBLIC_APP_URL=https://app.trynullsec.com
NEXT_PUBLIC_SENTRY_DSN=<optional>
NEXT_PUBLIC_POSTHOG_KEY=<optional>
NEXT_PUBLIC_POSTHOG_HOST=<optional>
RESEND_API_KEY=<optional>
REDIS_URL=<ioredis URL for BullMQ queue — same as worker>

Domain

  1. In Vercel → Project → Settings → Domains → Add app.trynullsec.com
  2. In your DNS provider, add: CNAME app → cname.vercel-dns.com

2. Railway (Worker)

Setup

  1. Create a new Railway project
  2. Link the GitHub repo
  3. Set Root Directory to / (monorepo root — Dockerfile needs full context)
  4. Railway uses packages/worker/Dockerfile (configured in railway.toml)

Environment Variables

NEXT_PUBLIC_SUPABASE_URL=https://itvznvetqclwamqjrcgc.supabase.co
SUPABASE_SERVICE_ROLE_KEY=<your service role key>
REDIS_URL=rediss://default:<password>@<host>:6379
ANTHROPIC_API_KEY=<your key>
NEXT_PUBLIC_APP_URL=https://app.trynullsec.com
SENTRY_DSN=<optional>
RESEND_API_KEY=<optional>

Notes

  • The Dockerfile runs playwright install --with-deps chromium which installs the exact Chromium build Playwright expects plus all system libraries
  • The worker runs via tsx src/index.ts (the start script) — no separate compile step needed
  • Worker concurrency is set to 1 by default for memory safety

3. Supabase Configuration

  1. Authentication → URL Configuration:

    • Site URL: https://app.trynullsec.com
    • Redirect URLs: add https://app.trynullsec.com/auth/callback
  2. Database → Replication:

    • Confirm scan_events table has Realtime enabled
  3. Migrations:

    • Confirm 0001_phase3_dismissals.sql is applied (adds dismissed_at, dismissed_by, dismiss_reason to findings, stripe_payment_intent_id to scans)

4. Upstash Redis REST Credentials

The web app uses @upstash/redis (HTTP-based, serverless-safe) for rate limiting. The worker uses ioredis (TCP, persistent connection) for BullMQ.

Both connect to the same Upstash Redis instance but via different protocols:

  • Worker: uses the rediss:// connection URL (REDIS_URL)
  • Web app rate limiter: uses REST URL + token (UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN)

Get the REST credentials from: Upstash Console → Your Database → REST API tab.


5. Post-Deploy Smoke Test

After both services are deployed:

  1. https://app.trynullsec.com → should redirect to /login
  2. Sign up via magic link → check email → click → should land on /dashboard
  3. Submit a scan → confirm Realtime progress streams on /scan/[id]
  4. After completion → /report/[id] renders with findings
  5. Publish report → /r/[badgeId] and badge SVG resolve
  6. 6th scan on same account → 403 with beta limit message
  7. Burst 4+ requests to POST /api/scans → 429 rate limit
  8. Submit a garbage URL → honest failure, no crash