Individual Service Deployment
This page is for teams that prefer deploying individual services to different hosting providers (Vercel, Fly.io, Supabase Cloud, etc.) rather than running everything on a single EC2 instance via Docker Compose.
If you are using the standard Docker Compose deployment, you can skip this page — all services are already included and deployed together.
The standard CTMS deployment runs all services on a single server via Docker Compose. However, some teams may prefer a distributed deployment where individual services are hosted on specialized platforms for better scaling, reduced operational overhead, or cost optimization.
Deployment Options Comparison
| Service | Standard (Docker Compose) | Individual Deployment |
|---|---|---|
| Zynexa (Web App) | Docker container on EC2 | Vercel |
| Sublink (Mobile App) | Docker container on EC2 | Vercel / Netlify |
| Cube.dev (Analytics) | Docker container on EC2 | Fly.io |
| MCP Server (AI Agent) | Docker container on EC2 | Fly.io |
| Supabase (Auth) | Self-hosted Docker | Supabase Cloud |
| Frappe (Clinical Backend) | Self-hosted Docker | Frappe Cloud |
| Lakehouse DB | Docker container on EC2 | Neon / RDS |
| OpenObserve | Docker container on EC2 | OpenObserve Cloud |
Zynexa on Vercel
Deploy the Next.js web application to Vercel for zero-config edge hosting.
Prerequisites
# Install Vercel CLI
npm install -g vercel
# Authenticate
vercel login
Deployment
cd hb-life-science-web
# Link to Vercel project
vercel link
# Set environment variables
vercel env add NEXT_PUBLIC_SUPABASE_URL
vercel env add NEXT_PUBLIC_SUPABASE_ANON_KEY
vercel env add NEXT_PUBLIC_API_BASE_URL
# ... (set all required env vars from .env.example)
# Deploy preview
vercel
# Deploy production
vercel --prod
Environment Variables
All variables from the Environment Variables reference apply. Key variables for Vercel:
| Variable | Description |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Supabase anonymous key |
NEXT_PUBLIC_API_BASE_URL | API Gateway URL |
NEXT_PUBLIC_API_CLIENT_URL | Client-side API URL (must match browsing domain) |
NEXT_PUBLIC_DEFAULT_PRACTITIONER_ID | Default practitioner ID from Stage 5 |
Semantic Cube on Fly.io
Deploy the Cube.dev analytics semantic layer to Fly.io for serverless container hosting.
Architecture
Frappe API → DLT Ingester → PostgreSQL (Bronze)
↓
DBT (Gold Layer)
↓
Cube.dev on Fly.io (Semantic Layer)
↓
Web App Dashboards
Prerequisites
# Install Fly.io CLI
brew install flyctl # macOS
# or: curl -L https://fly.io/install.sh | sh
# Authenticate
flyctl auth login
Deployment
Option A: Standalone
cd ctms-semantic-cube
make deploy ENV=production
This command:
- Loads environment variables from
.env.production - Sets Fly.io secrets from those variables
- Deploys to Fly.io
Option B: From Monorepo
cd ctms-data-pipeline-ai-analytics
make env-copy
make cube-deploy
Environment Variables
| Variable | Description | Example |
|---|---|---|
CUBEJS_DB_TYPE | Database type | postgres |
CUBEJS_DB_HOST | PostgreSQL host | ep-xxx.neon.tech |
CUBEJS_DB_PORT | Database port | 5432 |
CUBEJS_DB_NAME | Database name | neondb |
CUBEJS_DB_USER | Database user | neondb_owner |
CUBEJS_DB_PASS | Database password | your-password |
CUBEJS_DB_SSL | Enable SSL | true |
CUBEJS_API_SECRET | API authentication secret | your-secret-key |
CUBEJS_DEV_MODE | Enable dev mode | true |
CUBEJS_CACHE_AND_QUEUE_DRIVER | Cache driver | memory |
CUBEJS_DEV_MODE=true is required when not using Cube Store for pre-aggregations.
Makefile Commands
make help # Show all commands
make status ENV=production # View configuration
make deploy ENV=production # Deploy to Fly.io
make restart # Restart Fly.io app
make health ENV=production # Check health
make meta ENV=production # Get schema metadata
make flush-cache ENV=production # Clear analytics cache
make validate # Validate cube definitions
Available Cubes
| Cube | Source Table | Description |
|---|---|---|
Studies | gold.dim_study | Clinical study master data |
Subjects | gold.dim_subject | Study subjects/participants |
Sites | gold.dim_site | Clinical trial sites |
Enrollments | gold.fct_enrollment | Subject enrollment metrics |
AdverseEvents | gold.fct_adverse_events | Safety data |
Visits | gold.fct_visits | Visit compliance data |
StudyPersonnel | gold.dim_study_personnel | User-study role mappings |
API Endpoints
| Endpoint | Description |
|---|---|
/readyz | Health check |
/cubejs-api/v1/meta | Schema metadata |
/cubejs-api/v1/load | Query data |
After DBT Refresh
When the DBT pipeline refreshes the gold layer, flush the Cube cache:
make flush-cache ENV=production
Supabase Cloud
Use Supabase Cloud instead of self-hosting.
- Create a project at supabase.com
- Copy the Project URL, Anon Key, and Service Role Key into your
.env - Run the CTMS Supabase seed to create required tables:
# Set DATABASE_URL to your Supabase connection string
docker compose --env-file .env.production --profile init run --rm ctms-supabase-seed
This creates the profiles, devices, medication_consumption_logs, notification_logs tables and RLS policies.
Frappe Cloud
Use Frappe Cloud instead of self-hosting.
When purchasing a Frappe Cloud site, the default setup creates a site with only the ERPNext app. You must install the MarleyHealth (Healthcare module) app on top of ERPNext. See System Requirements for details.
- Create a Frappe Cloud site at frappecloud.com
- Install the MarleyHealth app (Sites → Your Site → Apps → Install App)
- Generate an API token (Settings → API Access)
- Set
FRAPPE_URLandFRAPPE_API_TOKENin your.env - Run the 5-stage provisioning
Useful Fly.io Commands
| Task | Command |
|---|---|
| View app status | flyctl status |
| View logs | flyctl logs |
| SSH into container | flyctl ssh console |
| List secrets | flyctl secrets list |
| Set secret | flyctl secrets set KEY=value |
Useful Vercel Commands
| Task | Command |
|---|---|
| Link project | vercel link |
| Deploy preview | vercel |
| Deploy production | vercel --prod |
| List deployments | vercel list |
| View logs | vercel logs |
| Pull env variables | vercel env pull |
| Add env variable | vercel env add VAR_NAME |
| Remove env variable | vercel env rm VAR_NAME |
Troubleshooting
Cube.dev on Fly.io
| Problem | Fix |
|---|---|
| "Cannot find module" errors | Ensure npm install was run and node_modules is in the Docker image |
| Database connection errors | Verify credentials and that the DB allows connections from Fly.io IPs |
| Cache stale data | Run make flush-cache ENV=production |
| Pre-aggregation errors | Set CUBEJS_DEV_MODE=true if not using Cube Store |
Vercel
| Problem | Fix |
|---|---|
| Build fails | Check vercel logs for errors; ensure all env vars are set |
| API routes 500 | Verify NEXT_PUBLIC_API_BASE_URL points to the correct API Gateway |
| Auth redirect fails | Ensure Supabase redirect URLs include the Vercel domain |