Deployment Guide
Complete deployment guide for PublicRisk.ai frontend and backend services
Deployment Guide
This guide covers deploying PublicRisk.ai to production, including frontend hosting, Modal backend services, and environment configuration.
Overview
PublicRisk.ai uses a hybrid architecture:
- Frontend: React + TypeScript app hosted on Vercel
- Backend: Python services on Modal Cloud Platform
- Database: Supabase (PostgreSQL + Auth)
- AI/ML: OpenRouter API for model inference
Prerequisites
Before deploying, ensure you have:
- ✅ GitHub account with repository access
- ✅ Vercel account (free tier works)
- ✅ Modal account with CLI installed
- ✅ Supabase project created
- ✅ OpenRouter API key (for AI models)
Part 1: Frontend Deployment (Vercel)
Step 1: Import Repository to Vercel
- Go to vercel.com/new
- Click Import Git Repository
- Select your GitHub repository:
casouth/PRAI - Configure project:
- Framework Preset: Vite
- Root Directory:
frontend - Build Command:
npm run build - Output Directory:
dist
Step 2: Configure Environment Variables
In Vercel dashboard → Settings → Environment Variables, add:
# API Configuration
VITE_API_URL=https://publicrisk--publicrisk-consolidated-backend-serve.modal.run
VITE_ENVIRONMENT=production
VITE_APP_VERSION=4.2.0
# Authentication
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-supabase-anon-key
# AI Models
VITE_OPENROUTER_API_KEY=your-openrouter-api-key
VITE_DEFAULT_AI_MODEL=moonshot/v1/moonshot-kimi-k2-thinking-general
# Features
VITE_ENABLE_HAZUS=true
VITE_ENABLE_2FA=true
VITE_ENABLE_STORM=true
# Analytics (Optional)
VITE_ANALYTICS_ID=your-analytics-id# API Configuration
VITE_API_URL=http://localhost:8000
VITE_ENVIRONMENT=development
VITE_APP_VERSION=4.2.0-dev
# Authentication
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-supabase-anon-key
# AI Models
VITE_OPENROUTER_API_KEY=your-openrouter-api-key
VITE_DEFAULT_AI_MODEL=moonshot/v1/moonshot-kimi-k2-thinking-general
# Features
VITE_ENABLE_HAZUS=true
VITE_ENABLE_2FA=true
VITE_ENABLE_STORM=trueStep 3: Deploy
Click Deploy. Vercel will:
- Build your application (~2-3 minutes)
- Deploy to production URL
- Set up auto-deployment from
mainbranch
Production URL: https://your-app.vercel.app
Auto-Deployment from GitHub
Every push to main automatically deploys:
git add .
git commit -m "feat: Add new feature"
git push origin main
# Vercel auto-deploys in ~2 minutesPreview deployments: Pull requests get unique URLs for testing.
Rollback to Previous Version
In Vercel dashboard:
- Go to Deployments
- Find working deployment
- Click ⋯ → Promote to Production
Part 2: Backend Deployment (Modal)
Step 1: Install Modal CLI
# Install Modal
pip install modal
# Authenticate
modal token newFollow prompts to authenticate with your Modal account.
Step 2: Deploy Core Services
Navigate to frontend/modal-services/core/ and deploy each service:
# Deploy HAZUS disaster risk service
cd modal-services/core
modal deploy modal_hazus_service.py
# Verify deployment
modal app list | grep hazusEndpoint: https://publicrisk--publicrisk-hazard-service-*.modal.run
Key endpoints: /health, /assess-property, /realtime-all
# Deploy DSPy optimized query service
modal deploy modal_dspy_optimized_service.py
# Verify
modal app list | grep dspyEndpoint: https://publicrisk--dspy-optimized-service-*.modal.run
Key endpoints: /api/dspy/query, /api/dspy/storm/generate
# Deploy SIPMath probabilistic risk service
modal deploy modal_sipmath_service.py
# Verify
modal app list | grep sipmathEndpoint: https://publicrisk--publicrisk-sipmath-*.modal.run
Key endpoints: /api/sipmath/create-slurp, /api/sipmath/hazus-to-sip
# Deploy PEFT domain adapters service
modal deploy modal_peft_service.py
# Verify
modal app list | grep peftEndpoint: https://publicrisk--publicrisk-peft-adapters-*.modal.run
Key endpoints: /api/peft/adapters, /api/peft/generate
# Deploy cybersecurity KEV service
modal deploy modal_cyber_service.py
# Verify
modal app list | grep cyberEndpoint: https://publicrisk--publicrisk-cyber-*.modal.run
Key endpoints: /api/cyber/kev, /api/cyber/infrastructure-threats
Step 3: Deploy Consolidated Backend
The consolidated backend unifies all services:
cd frontend
modal deploy modal_consolidated_backend.pyEndpoint: https://publicrisk--publicrisk-consolidated-backend-serve.modal.run
This is the main API endpoint used by the frontend (VITE_API_URL).
Step 4: Configure Modal Secrets
Store sensitive credentials in Modal secrets:
# OpenRouter API key
modal secret create openrouter-api-key OPENROUTER_API_KEY=sk-or-v1-...
# Supabase credentials
modal secret create supabase-credentials \
SUPABASE_URL=https://your-project.supabase.co \
SUPABASE_KEY=your-service-role-key
# Redis connection (if using)
modal secret create redis-credentials \
REDIS_URL=redis://default:password@host:portSecrets are automatically available to deployed services.
Part 3: Database Setup (Supabase)
Step 1: Create Supabase Project
- Go to supabase.com
- Create new project
- Note your Project URL and anon key
Step 2: Run Database Migrations
Execute SQL in Supabase SQL Editor:
-- Users table
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
email TEXT UNIQUE NOT NULL,
name TEXT,
role TEXT DEFAULT 'User',
client_id UUID REFERENCES client_organizations(id),
two_factor_enabled BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
-- Client organizations table
CREATE TABLE client_organizations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT NOT NULL,
contact_email TEXT,
max_users INTEGER DEFAULT 10,
subscription_tier TEXT DEFAULT 'basic',
status TEXT DEFAULT 'active',
created_at TIMESTAMP DEFAULT NOW()
);
-- Audit logs table
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES users(id),
action TEXT NOT NULL,
resource TEXT,
status TEXT,
ip_address TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
-- Enable Row Level Security
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE client_organizations ENABLE ROW LEVEL SECURITY;
ALTER TABLE audit_logs ENABLE ROW LEVEL SECURITY;
-- Create policies (example)
CREATE POLICY "Users can view own data"
ON users FOR SELECT
USING (auth.uid() = id);Step 3: Configure Authentication
In Supabase dashboard → Authentication → Providers:
- Enable Email provider
- Configure email templates (optional)
- Set up 2FA settings (optional)
Part 4: Verification & Testing
Frontend Health Check
Visit your Vercel URL and verify:
- ✅ Landing page loads
- ✅ Login works
- ✅ Dashboard displays correctly
- ✅ No console errors
Backend Health Checks
Test each Modal service:
# Consolidated backend
curl https://publicrisk--publicrisk-consolidated-backend-serve.modal.run/health
# HAZUS service
curl https://publicrisk--publicrisk-hazard-service-*.modal.run/health
# DSPy service
curl https://publicrisk--dspy-optimized-service-*.modal.run/healthAll should return {"status": "healthy"}.
End-to-End Test
- Login: Authenticate as test user
- Query Explorer: Run sample query
- HAZUS: Assess property risk (34.0522, -118.2437)
- STORM: Generate test document
- RAG Upload: Upload sample PDF
All features should work without errors.
Part 5: Production Configuration
Performance Optimization
Vercel:
- Enable Edge Caching for static assets
- Use Image Optimization for images
- Enable Analytics for monitoring
Modal:
- Keep services warm (increase
keep_warmparameter) - Use Redis caching for frequently accessed data
- Enable auto-scaling for high traffic
Security Best Practices
Important: Follow these security guidelines for production deployments.
-
API Keys: Never commit secrets to Git
# Use .env.local for local development echo ".env.local" >> .gitignore -
CORS: Restrict origins in Modal backend
allowed_origins = [ "https://your-app.vercel.app", "https://custom-domain.com" ] -
Rate Limiting: Enable in Modal services
@app.function( concurrency_limit=100, # Max concurrent requests timeout=30 # Request timeout ) -
2FA: Require for admin users
// Enable in Supabase dashboard // Enforce in frontend AuthContext
Monitoring & Logging
Vercel Analytics:
- View deployment logs in dashboard
- Monitor Core Web Vitals
- Track errors with Sentry (optional)
Modal Logs:
# View service logs
modal app logs publicrisk-consolidated-backend
# Follow logs in real-time
modal app logs --follow publicrisk-hazard-serviceSupabase Logs:
- View in dashboard → Logs
- Monitor auth events
- Track database performance
Part 6: Custom Domain Setup
Add Custom Domain to Vercel
- Go to Vercel dashboard → Domains
- Click Add Domain
- Enter your domain (e.g.,
app.publicrisk.ai) - Follow DNS configuration instructions
DNS Configuration:
Type: A
Name: app
Value: 76.76.21.21 (Vercel IP)
Type: CNAME
Name: www
Value: cname.vercel-dns.comChanges take 24-48 hours to propagate.
Part 7: Client-Specific Deployments
For clients needing private RAG stores, deploy dedicated backends:
# Deploy client-specific backend
.\deploy-client-backend.ps1 `
-ClientName "springfield" `
-AllowedIPs "203.0.113.0/24,198.51.100.50"Generates:
client-configs/springfield.json- Full configurationclient-configs/springfield.env- Environment variables
Send to client:
# client-configs/springfield.env
VITE_CLIENT_RAG_ENDPOINT=https://publicrisk--springfield-rag-backend.modal.run
VITE_CLIENT_API_KEY=aB3dE9fG2hK5mN7pQ8rS1tU4vW6xY0zA
VITE_CLIENT_NAME=springfieldClient adds these to their .env file and restarts the app.
Part 8: CI/CD Automation
GitHub Actions (Optional)
Create .github/workflows/deploy.yml:
name: Deploy to Production
on:
push:
branches: [main]
jobs:
deploy-frontend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm ci
working-directory: frontend
- run: npm run build
working-directory: frontend
# Vercel auto-deploys, no explicit step needed
deploy-backend:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3.11'
- run: pip install modal
- run: modal token set --token-id ${{ secrets.MODAL_TOKEN_ID }} --token-secret ${{ secrets.MODAL_TOKEN_SECRET }}
- run: modal deploy modal_consolidated_backend.py
working-directory: frontendRequired secrets (in GitHub repo settings):
MODAL_TOKEN_IDMODAL_TOKEN_SECRET
Troubleshooting
Frontend Issues
Problem: White screen after deployment
Solutions:
- Check Vercel build logs for errors
- Verify environment variables are set
- Test locally with production build:
npm run build && npm run preview - Clear browser cache
Problem: API calls failing with CORS errors
Solutions:
- Verify
VITE_API_URLmatches Modal endpoint - Check Modal CORS configuration
- Ensure Vercel domain is whitelisted in Modal
Backend Issues
Problem: Modal service cold starts (30-60s delay)
Solutions:
- Increase
keep_warmparameter:@app.function(keep_warm=2) # Keep 2 containers warm - Use Redis caching for frequent queries
- Implement health check endpoints to ping services
Problem: Modal deployment fails
Solutions:
- Verify Modal CLI is authenticated:
modal token new - Check file paths are correct
- Review Modal logs:
modal app logs <app-name> - Ensure all dependencies in
requirements.txt
Database Issues
Problem: Supabase connection errors
Solutions:
- Verify credentials in environment variables
- Check Supabase project status
- Review database logs in Supabase dashboard
- Ensure RLS policies allow access
Deployment Checklist
Use this checklist for every production deployment.
Pre-Deployment
- All tests passing locally
- Environment variables configured
- Database migrations reviewed
- API keys secured (not in code)
- CORS settings configured
- Build succeeds locally
Deployment
- Frontend deployed to Vercel
- Backend services deployed to Modal
- Custom domain configured (if applicable)
- SSL certificates active
- Health checks passing
Post-Deployment
- Smoke tests completed
- Login/authentication working
- API endpoints responding
- Database connections stable
- Monitoring enabled
- Documentation updated
Rollback Procedures
Frontend Rollback (Vercel)
- Go to Vercel dashboard → Deployments
- Find last working deployment
- Click ⋯ → Promote to Production
Backend Rollback (Modal)
-
Find previous deployment:
modal app list --all -
Redeploy previous version:
git checkout <previous-commit> modal deploy modal_consolidated_backend.py
Database Rollback (Supabase)
- Run rollback SQL script (pre-prepared)
- Restore from backup if needed (Supabase automatic backups)
Production Monitoring
Key Metrics to Track
| Metric | Tool | Target |
|---|---|---|
| Frontend Load Time | Vercel Analytics | less than 2s |
| API Response Time | Modal Logs | less than 500ms |
| Error Rate | Sentry/Vercel | less than 0.1% |
| Uptime | Status Page | greater than 99.9% |
| Cold Start Frequency | Modal Logs | less than 5% |
Alerting
Set up alerts for:
- ❌ API response time greater than 1s (5 min average)
- ❌ Error rate greater than 1% (1 min spike)
- ❌ Service downtime (immediate)
- ❌ Database connection failures
Cost Optimization
Vercel
- Free tier: 100GB bandwidth/month
- Upgrade triggers:
- greater than 100GB bandwidth
- Need advanced analytics
- Need team collaboration
Modal
- Pricing: Pay-per-use (CPU/GPU seconds)
- Optimization:
- Use
keep_warm=0for low-traffic services - Cache responses with Redis
- Batch requests when possible
- Use
Supabase
- Free tier: 500MB database, 2GB bandwidth
- Upgrade triggers:
- greater than 500MB data
- Need point-in-time recovery
- Need custom domains
Related Documentation
- API Reference - Complete API documentation
- HAZUS Detailed Guide - HAZUS deployment specifics
- Architecture Overview - System design details
- Getting Started - Local development setup
Support
For deployment assistance:
- Documentation: docs.publicrisk.ai
- GitHub Issues: github.com/casouth/PRAI/issues
- Email: support@publicrisk.ai
- Modal Support: modal.com/docs
- Vercel Support: vercel.com/support
Changelog
| Date | Version | Changes |
|---|---|---|
| 2025-12-04 | 4.2.0 | Initial comprehensive deployment guide |
| 2025-11-15 | 4.1.0 | HAZUS production deployment |
| 2025-10-30 | 4.0.0 | Modal backend consolidation |