Calafai Docs

Deployment Guide

Deployment Guide

The Groundtruth Platform consists of three services that must be deployed and configured together.

Service Overview

ServicePlatformPurpose
Web AppVercelNext.js frontend + API routes
EngineRailwayPython FastAPI engine (long-running crew execution)
Database + Auth + StorageSupabasePostgreSQL, authentication, file storage

Supporting services:

ServicePlatformPurpose
BillingStripeSubscriptions, checkout, usage metering
Caching + Rate LimitingUpstash RedisAPI response cache, sliding-window rate limits
EmailResendTransactional notifications
ObservabilitySentryError tracking, performance monitoring

1. Supabase (Database + Auth + Storage)

Supabase is the foundation. Set it up first since other services depend on its connection strings and API keys.

Create Project

  1. Create a new project at supabase.com
  2. Note the following from Settings > API:
    • Project URL (NEXT_PUBLIC_SUPABASE_URL)
    • Anon key (NEXT_PUBLIC_SUPABASE_ANON_KEY)
    • Service role key (SUPABASE_SERVICE_ROLE_KEY)
  3. Note the connection string from Settings > Database:
    • Direct connection: DATABASE_URL (for migrations)
    • Connection pooler (port 6543): for the Railway engine (use Transaction mode)

Apply Migrations

From your local machine (or CI):

cd apps/web
DATABASE_URL="postgresql://postgres:PASSWORD@db.PROJECT.supabase.co:5432/postgres" npx prisma migrate deploy

This creates all 20 tables, indexes, and RLS policies.

Seed Data

cd apps/web
DATABASE_URL="postgresql://..." npx prisma db seed

This populates the AgentConfig table with 20 agents and creates system engagement templates.

Create Storage Bucket

  1. Go to Storage in the Supabase dashboard
  2. Create a new bucket named engagement-attachments
  3. Set it to Private (access controlled by service role key)

Configure Auth

  1. Go to Authentication > URL Configuration
  2. Set the Site URL to your Vercel deployment URL (e.g., https://your-app.vercel.app)
  3. Add redirect URLs:
    • https://your-app.vercel.app/auth/callback
    • http://localhost:3000/auth/callback (for local development)
  4. Enable desired auth providers (email/password is enabled by default)

SSO Configuration (Enterprise Plan Only)

For tenants on the enterprise plan, SAML SSO is configured per-tenant via the /api/tenant/sso API endpoint. Supabase Pro plan includes SAML support.

2. Vercel (Next.js Web App)

Connect Repository

  1. Import your GitHub repository at vercel.com
  2. Set the Root Directory to apps/web
  3. Framework Preset: Next.js
  4. Build Command: npx prisma generate && next build
  5. Install Command: npm install

Environment Variables

Set these in the Vercel dashboard under Settings > Environment Variables:

# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://PROJECT.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ...

# Database
DATABASE_URL=postgresql://postgres:PASSWORD@db.PROJECT.supabase.co:5432/postgres

# Stripe
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...

# Engine
RAILWAY_ENGINE_URL=https://your-engine.up.railway.app

# Upstash Redis
UPSTASH_REDIS_REST_URL=https://REGION.upstash.io
UPSTASH_REDIS_REST_TOKEN=AX...

# Resend
RESEND_API_KEY=re_...

# Sentry
NEXT_PUBLIC_SENTRY_DSN=https://...@sentry.io/...
SENTRY_AUTH_TOKEN=sntrys_...

Deployment

Vercel auto-deploys on push to main. Each pull request gets a preview deployment.

3. Railway (Python Engine)

The Python engine runs as a persistent service (not serverless) because engagement runs take 10-60 minutes, well beyond serverless timeout limits.

Deploy

  1. Create a new project at railway.app
  2. Connect your GitHub repository
  3. Set the Root Directory to packages/engine
  4. Railway detects the Python project automatically via requirements.txt
  5. The railway.toml file in infrastructure/ configures the deployment

Environment Variables

Set these in the Railway dashboard:

# Database (use Supabase connection pooler URL, port 6543)
DATABASE_URL=postgresql://postgres:PASSWORD@PROJECT.supabase.co:6543/postgres

# LLM API keys
OPENAI_API_KEY=sk-...
XAI_API_KEY=xai-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_API_KEY=AIza...

# CORS
ALLOWED_ORIGINS=https://your-app.vercel.app

# Sentry
SENTRY_DSN=https://...@sentry.io/...
ENVIRONMENT=production
SENTRY_TRACES_SAMPLE_RATE=0.1

Important Notes

  • Use the Supabase connection pooler URL (port 6543) for the engine, not the direct connection. This prevents connection exhaustion under load.
  • The engine must be stateless -- no local filesystem state. All persistence goes through the DatabaseStorageAdapter to PostgreSQL.
  • Railway provides a public URL automatically. Set this as RAILWAY_ENGINE_URL in Vercel.

4. Stripe (Billing)

Create Products and Prices

Create three subscription products in the Stripe dashboard (or via API):

PlanMonthly PriceFeatures
Starter$99/moBasic engagement execution
Professional$299/moAdvanced features, higher limits
EnterpriseCustomSSO, custom branding, dedicated support

Configure Webhook

  1. Go to Developers > Webhooks in the Stripe dashboard
  2. Add endpoint: https://your-app.vercel.app/api/billing/webhook
  3. Select events:
    • checkout.session.completed
    • customer.subscription.updated
    • customer.subscription.deleted
    • invoice.paid
    • invoice.payment_failed
  4. Copy the signing secret as STRIPE_WEBHOOK_SECRET

Customer Portal

  1. Go to Settings > Billing > Customer portal
  2. Enable the customer portal
  3. Configure allowed actions (cancel subscription, update payment method)

5. Upstash Redis (Caching + Rate Limiting)

  1. Create a database at upstash.com
  2. Choose a region close to your Vercel deployment
  3. Copy the REST URL and token:
    • UPSTASH_REDIS_REST_URL
    • UPSTASH_REDIS_REST_TOKEN

The platform uses Redis for:

  • API response caching: Agent configs, engagement lists, tenant settings
  • Rate limiting: Sliding-window algorithm via @upstash/ratelimit

If Redis is unavailable, the platform degrades gracefully to no-cache and in-memory rate limiting.

6. Resend (Email)

  1. Create an account at resend.com
  2. Verify your sending domain
  3. Generate an API key: RESEND_API_KEY

Email notifications are sent for:

  • Engagement started, completed, or failed
  • Deliverable ready for review
  • Client portal comment received
  • Team member invited

7. Sentry (Observability)

Next.js Project

  1. Create a project at sentry.io for the Next.js app
  2. Set NEXT_PUBLIC_SENTRY_DSN in Vercel
  3. Generate an auth token for source map uploads: SENTRY_AUTH_TOKEN

Python Engine Project

  1. Create a separate Sentry project for the Python engine
  2. Set SENTRY_DSN in Railway
  3. The engine uses sentry-sdk[fastapi] for automatic request instrumentation

Deployment Checklist

Before going live, verify:

  • Supabase migrations applied, agents seeded, storage bucket created
  • Supabase Auth redirect URLs configured
  • Vercel deploying successfully with all env vars
  • Railway engine running and reachable from Vercel (RAILWAY_ENGINE_URL)
  • Stripe products/prices created, webhook endpoint configured
  • Health checks passing:
    • GET https://your-app.vercel.app/api/health
    • GET https://your-engine.up.railway.app/health
  • Redis connected (check admin health dashboard)
  • Sentry receiving events from both services
  • Email delivery working (send a test)

Cost Summary

ServiceMonthly Cost
Supabase Pro$25
Vercel Pro$20
Railway$5-20 (usage-based)
Upstash Redis$0-10
Resend$0-20
Stripe2.9% + $0.30 per transaction
SentryFree tier (5K events) or $26/mo
Total~$50-95/month (before Stripe fees)

On this page