Skip to main content

Individual Service Deployment

Optional — Alternative Deployment Strategy

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

ServiceStandard (Docker Compose)Individual Deployment
Zynexa (Web App)Docker container on EC2Vercel
Sublink (Mobile App)Docker container on EC2Vercel / Netlify
Cube.dev (Analytics)Docker container on EC2Fly.io
MCP Server (AI Agent)Docker container on EC2Fly.io
Supabase (Auth)Self-hosted DockerSupabase Cloud
Frappe (Clinical Backend)Self-hosted DockerFrappe Cloud
Lakehouse DBDocker container on EC2Neon / RDS
OpenObserveDocker container on EC2OpenObserve 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:

VariableDescription
NEXT_PUBLIC_SUPABASE_URLSupabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEYSupabase anonymous key
NEXT_PUBLIC_API_BASE_URLAPI Gateway URL
NEXT_PUBLIC_API_CLIENT_URLClient-side API URL (must match browsing domain)
NEXT_PUBLIC_DEFAULT_PRACTITIONER_IDDefault 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:

  1. Loads environment variables from .env.production
  2. Sets Fly.io secrets from those variables
  3. Deploys to Fly.io

Option B: From Monorepo

cd ctms-data-pipeline-ai-analytics
make env-copy
make cube-deploy

Environment Variables

VariableDescriptionExample
CUBEJS_DB_TYPEDatabase typepostgres
CUBEJS_DB_HOSTPostgreSQL hostep-xxx.neon.tech
CUBEJS_DB_PORTDatabase port5432
CUBEJS_DB_NAMEDatabase nameneondb
CUBEJS_DB_USERDatabase userneondb_owner
CUBEJS_DB_PASSDatabase passwordyour-password
CUBEJS_DB_SSLEnable SSLtrue
CUBEJS_API_SECRETAPI authentication secretyour-secret-key
CUBEJS_DEV_MODEEnable dev modetrue
CUBEJS_CACHE_AND_QUEUE_DRIVERCache drivermemory
Dev Mode Required

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

CubeSource TableDescription
Studiesgold.dim_studyClinical study master data
Subjectsgold.dim_subjectStudy subjects/participants
Sitesgold.dim_siteClinical trial sites
Enrollmentsgold.fct_enrollmentSubject enrollment metrics
AdverseEventsgold.fct_adverse_eventsSafety data
Visitsgold.fct_visitsVisit compliance data
StudyPersonnelgold.dim_study_personnelUser-study role mappings

API Endpoints

EndpointDescription
/readyzHealth check
/cubejs-api/v1/metaSchema metadata
/cubejs-api/v1/loadQuery 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.

  1. Create a project at supabase.com
  2. Copy the Project URL, Anon Key, and Service Role Key into your .env
  3. 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.

MarleyHealth App Required

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.

  1. Create a Frappe Cloud site at frappecloud.com
  2. Install the MarleyHealth app (Sites → Your Site → Apps → Install App)
  3. Generate an API token (Settings → API Access)
  4. Set FRAPPE_URL and FRAPPE_API_TOKEN in your .env
  5. Run the 5-stage provisioning

Useful Fly.io Commands

TaskCommand
View app statusflyctl status
View logsflyctl logs
SSH into containerflyctl ssh console
List secretsflyctl secrets list
Set secretflyctl secrets set KEY=value

Useful Vercel Commands

TaskCommand
Link projectvercel link
Deploy previewvercel
Deploy productionvercel --prod
List deploymentsvercel list
View logsvercel logs
Pull env variablesvercel env pull
Add env variablevercel env add VAR_NAME
Remove env variablevercel env rm VAR_NAME

Troubleshooting

Cube.dev on Fly.io

ProblemFix
"Cannot find module" errorsEnsure npm install was run and node_modules is in the Docker image
Database connection errorsVerify credentials and that the DB allows connections from Fly.io IPs
Cache stale dataRun make flush-cache ENV=production
Pre-aggregation errorsSet CUBEJS_DEV_MODE=true if not using Cube Store

Vercel

ProblemFix
Build failsCheck vercel logs for errors; ensure all env vars are set
API routes 500Verify NEXT_PUBLIC_API_BASE_URL points to the correct API Gateway
Auth redirect failsEnsure Supabase redirect URLs include the Vercel domain