Skip to content

Production Deployment

This guide covers deploying Quantbot to production environments with Docker, cloud platforms, and advanced configuration options.

Deployment Overview

Quantbot supports multiple deployment strategies:

  • Docker Compose: Single-server deployment with all services
  • Kubernetes: Scalable container orchestration
  • Cloud Platforms: AWS, GCP, Azure with managed services
  • Serverless: Backend as serverless functions with managed databases

Docker Production Deployment

Production Docker Compose

Create a production-ready docker-compose.prod.yml:

version: '3.8'

services:
  frontend:
    build:
      context: ./Quantbot-FE
      dockerfile: Dockerfile.prod
    ports:
      - "80:80"
      - "443:443"
    environment:
      - VITE_API_BASE_URL=https://api.yourdomain.com/api/v1
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./ssl:/etc/ssl/certs
    depends_on:
      - backend
    restart: unless-stopped

  backend:
    build:
      context: ./Quantbot-BE
      dockerfile: Dockerfile.prod
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql+asyncpg://quantbot_admin:${DB_PASSWORD}@postgres:5432/quantbot
      - NEO4J_URI=bolt://neo4j:7687
      - NEO4J_USER=neo4j
      - NEO4J_PASSWORD=${NEO4J_PASSWORD}
      - JWT_SECRET_KEY=${JWT_SECRET_KEY}
      - GOOGLE_API_KEY=${GOOGLE_API_KEY}
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - NEWS_API_KEY=${NEWS_API_KEY}
      - FINNHUB_API_KEY=${FINNHUB_API_KEY}
      - FMP_API_KEY=${FMP_API_KEY}
      - OPIK_API_KEY=${OPIK_API_KEY}
      - OPIK_WORKSPACE=${OPIK_WORKSPACE}
      - OPIK_PROJECT_NAME=${OPIK_PROJECT_NAME}
    depends_on:
      - postgres
      - neo4j
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  postgres:
    image: pgvector/pgvector:pg16
    environment:
      - POSTGRES_DB=quantbot
      - POSTGRES_USER=quantbot_admin
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./backup:/backup
    ports:
      - "5432:5432"
    restart: unless-stopped
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U quantbot_admin -d quantbot"]
      interval: 10s
      timeout: 5s
      retries: 5

  neo4j:
    image: neo4j:5.15-community
    environment:
      - NEO4J_AUTH=neo4j/${NEO4J_PASSWORD}
      - NEO4J_PLUGINS=["graph-data-science"]
      - NEO4J_dbms_security_procedures_unrestricted=gds.*
    volumes:
      - neo4j_data:/data
      - neo4j_logs:/logs
      - neo4j_conf:/conf
    ports:
      - "7474:7474"
      - "7687:7687"
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "cypher-shell", "-u", "neo4j", "-p", "${NEO4J_PASSWORD}", "RETURN 1"]
      interval: 30s
      timeout: 10s
      retries: 3

  redis:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD}
    environment:
      - REDIS_PASSWORD=${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    ports:
      - "6379:6379"
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 3

volumes:
  postgres_data:
  neo4j_data:
  neo4j_logs:
  neo4j_conf:
  redis_data:

Production Environment Variables

Create a secure .env.prod file:

# Database
DB_PASSWORD=your-super-secure-database-password
NEO4J_PASSWORD=your-super-secure-neo4j-password
REDIS_PASSWORD=your-super-secure-redis-password

# JWT Security
JWT_SECRET_KEY=your-256-bit-secret-key-for-jwt-tokens
JWT_ACCESS_TOKEN_EXPIRE_MINUTES=60
JWT_REFRESH_TOKEN_EXPIRE_DAYS=7

# API Keys
GOOGLE_API_KEY=your-production-google-api-key
OPENAI_API_KEY=your-production-openai-api-key
NEWS_API_KEY=your-production-news-api-key
FINNHUB_API_KEY=your-production-finnhub-api-key
FMP_API_KEY=your-production-fmp-api-key

# Observability
OPIK_API_KEY=your-production-opik-api-key
OPIK_WORKSPACE=quantbot-production
OPIK_PROJECT_NAME=quantbot

# Memory Configuration
MEMORY_MAX_EPISODES_PER_USER=50000
MEMORY_RETENTION_DAYS=730
MEMORY_ENABLE_ENCRYPTION=true

# Performance
QUANTBOT_WORKFLOW=production

Deployment Commands

# Deploy to production
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d

# View production logs
docker compose -f docker-compose.prod.yml logs -f

# Update production deployment
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d --force-recreate

# Scale services
docker compose -f docker-compose.prod.yml up -d --scale backend=3

Cloud Platform Deployment

AWS Deployment

Option 1: AWS ECS with Fargate

# docker-compose.aws.yml
version: '3.8'

x-aws-cluster: quantbot-cluster
x-aws-vpc: vpc-12345678

services:
  backend:
    image: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/quantbot-backend:latest
    x-aws-role: arn:aws:iam::${AWS_ACCOUNT_ID}:role/quantbot-execution-role
    environment:
      - DATABASE_URL=postgresql+asyncpg://${RDS_USERNAME}:${RDS_PASSWORD}@${RDS_ENDPOINT}:5432/quantbot
      - NEO4J_URI=${NEO4J_ENDPOINT}
    deploy:
      replicas: 2
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

  frontend:
    image: ${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/quantbot-frontend:latest
    ports:
      - "80:80"
      - "443:443"
    x-aws-load_balancer: quantbot-alb

Deployment Script

#!/bin/bash
# deploy-aws.sh

# Build and push images to ECR
aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com

# Backend
docker build -t quantbot-backend ./Quantbot-BE
docker tag quantbot-backend:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/quantbot-backend:latest
docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/quantbot-backend:latest

# Frontend
docker build -t quantbot-frontend ./Quantbot-FE
docker tag quantbot-frontend:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/quantbot-frontend:latest
docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/quantbot-frontend:latest

# Deploy with Docker Compose for ECS
docker compose -f docker-compose.aws.yml up

Google Cloud Platform (GCP)

Cloud Run Deployment

# cloudbuild.yaml
steps:
  # Build backend
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'build'
      - '-t'
      - 'gcr.io/$PROJECT_ID/quantbot-backend'
      - './Quantbot-BE'

  # Push backend
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'push'
      - 'gcr.io/$PROJECT_ID/quantbot-backend'

  # Deploy backend to Cloud Run
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'quantbot-backend'
      - '--image'
      - 'gcr.io/$PROJECT_ID/quantbot-backend'
      - '--region'
      - 'us-central1'
      - '--allow-unauthenticated'
      - '--set-env-vars'
      - 'DATABASE_URL=postgresql+asyncpg://user:pass@/quantbot?host=/cloudsql/$PROJECT_ID:us-central1:quantbot-db'

  # Build and deploy frontend
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'build'
      - '-t'
      - 'gcr.io/$PROJECT_ID/quantbot-frontend'
      - './Quantbot-FE'

  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'push'
      - 'gcr.io/$PROJECT_ID/quantbot-frontend'

  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: 'gcloud'
    args:
      - 'run'
      - 'deploy'
      - 'quantbot-frontend'
      - '--image'
      - 'gcr.io/$PROJECT_ID/quantbot-frontend'
      - '--region'
      - 'us-central1'
      - '--allow-unauthenticated'

Kubernetes Deployment

Kubernetes Manifests

# quantbot-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: quantbot

---
# quantbot-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: quantbot-config
  namespace: quantbot
data:
  DATABASE_URL: "postgresql+asyncpg://quantbot_admin:password@postgres:5432/quantbot"
  NEO4J_URI: "bolt://neo4j:7687"
  NEO4J_USER: "neo4j"

---
# quantbot-secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: quantbot-secrets
  namespace: quantbot
type: Opaque
stringData:
  JWT_SECRET_KEY: "your-secret-key"
  GOOGLE_API_KEY: "your-google-api-key"
  OPENAI_API_KEY: "your-openai-api-key"
  NEWS_API_KEY: "your-news-api-key"

---
# quantbot-backend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: quantbot-backend
  namespace: quantbot
spec:
  replicas: 3
  selector:
    matchLabels:
      app: quantbot-backend
  template:
    metadata:
      labels:
        app: quantbot-backend
    spec:
      containers:
      - name: backend
        image: quantbot/backend:latest
        ports:
        - containerPort: 8000
        envFrom:
        - configMapRef:
            name: quantbot-config
        - secretRef:
            name: quantbot-secrets
        livenessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 5
          periodSeconds: 5
        resources:
          requests:
            memory: "512Mi"
            cpu: "250m"
          limits:
            memory: "1Gi"
            cpu: "500m"

---
# quantbot-backend-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: quantbot-backend-service
  namespace: quantbot
spec:
  selector:
    app: quantbot-backend
  ports:
  - protocol: TCP
    port: 8000
    targetPort: 8000
  type: ClusterIP

---
# quantbot-frontend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: quantbot-frontend
  namespace: quantbot
spec:
  replicas: 2
  selector:
    matchLabels:
      app: quantbot-frontend
  template:
    metadata:
      labels:
        app: quantbot-frontend
    spec:
      containers:
      - name: frontend
        image: quantbot/frontend:latest
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "256Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "200m"

---
# quantbot-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: quantbot-ingress
  namespace: quantbot
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
  - hosts:
    - quantbot.yourdomain.com
    secretName: quantbot-tls
  rules:
  - host: quantbot.yourdomain.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: quantbot-backend-service
            port:
              number: 8000
      - path: /
        pathType: Prefix
        backend:
          service:
            name: quantbot-frontend-service
            port:
              number: 80

Deploy to Kubernetes

# Apply all manifests
kubectl apply -f k8s/

# Check deployment status
kubectl get pods -n quantbot
kubectl get services -n quantbot
kubectl get ingress -n quantbot

# Scale deployment
kubectl scale deployment quantbot-backend --replicas=5 -n quantbot

# View logs
kubectl logs -f deployment/quantbot-backend -n quantbot

SSL/TLS Configuration

Let's Encrypt with Nginx

# nginx/nginx.conf
upstream backend {
    server backend:8000;
}

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    ssl_certificate /etc/ssl/certs/fullchain.pem;
    ssl_certificate_key /etc/ssl/certs/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers off;

    # Frontend
    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files $uri $uri/ /index.html;

        # Security headers
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-Content-Type-Options "nosniff" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header Referrer-Policy "no-referrer-when-downgrade" always;
        add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
    }

    # Backend API
    location /api/ {
        proxy_pass http://backend;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # CORS
        add_header Access-Control-Allow-Origin * always;
        add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" always;
        add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
    }

    # WebSocket support (if needed)
    location /ws/ {
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
    }
}

Database Migration and Backup

Production Database Setup

# Run migrations
docker compose -f docker-compose.prod.yml exec backend alembic upgrade head

# Create database backup
docker compose -f docker-compose.prod.yml exec postgres pg_dump -U quantbot_admin quantbot > backup_$(date +%Y%m%d_%H%M%S).sql

# Restore from backup
docker compose -f docker-compose.prod.yml exec postgres psql -U quantbot_admin quantbot < backup_20250101_120000.sql

# Neo4j backup
docker compose -f docker-compose.prod.yml exec neo4j neo4j-admin database dump --to-path=/backup neo4j

Automated Backup Script

#!/bin/bash
# backup.sh - Run daily backups

BACKUP_DIR="/backup/$(date +%Y/%m)"
mkdir -p $BACKUP_DIR

# PostgreSQL backup
docker compose -f docker-compose.prod.yml exec postgres pg_dump -U quantbot_admin quantbot | gzip > $BACKUP_DIR/postgres_$(date +%Y%m%d_%H%M%S).sql.gz

# Neo4j backup
docker compose -f docker-compose.prod.yml exec neo4j neo4j-admin database dump neo4j --to-path=/backup/neo4j_$(date +%Y%m%d_%H%M%S).dump

# Cleanup old backups (keep 30 days)
find /backup -type f -mtime +30 -delete

# Upload to cloud storage (optional)
aws s3 sync /backup s3://quantbot-backups/

Monitoring and Observability

Health Checks

# Add to backend: app/api/health.py
from fastapi import APIRouter, HTTPException
from app.core.database import DatabaseManager
from app.services.market_service import MarketService

router = APIRouter()

@router.get("/health")
async def health_check():
    """Comprehensive health check endpoint."""
    health_status = {
        "status": "healthy",
        "timestamp": datetime.utcnow().isoformat(),
        "services": {}
    }

    # Database check
    try:
        db_manager = DatabaseManager()
        await db_manager.get_session()
        health_status["services"]["database"] = "healthy"
    except Exception as e:
        health_status["services"]["database"] = f"unhealthy: {str(e)}"
        health_status["status"] = "unhealthy"

    # Market service check
    try:
        market_service = MarketService()
        await market_service.get_stock_data("AAPL", "1d")
        health_status["services"]["market_data"] = "healthy"
    except Exception as e:
        health_status["services"]["market_data"] = f"degraded: {str(e)}"

    if health_status["status"] == "unhealthy":
        raise HTTPException(status_code=503, detail=health_status)

    return health_status

Prometheus Metrics

# app/core/metrics.py
from prometheus_client import Counter, Histogram, Gauge
import time

# API metrics
api_requests = Counter('quantbot_api_requests_total', 'Total API requests', ['method', 'endpoint', 'status'])
api_duration = Histogram('quantbot_api_request_duration_seconds', 'API request duration')
active_users = Gauge('quantbot_active_users', 'Number of active users')

# AI metrics
ai_requests = Counter('quantbot_ai_requests_total', 'Total AI requests')
ai_response_time = Histogram('quantbot_ai_response_time_seconds', 'AI response time')
tool_usage = Counter('quantbot_tool_usage_total', 'Tool usage count', ['tool_name'])

Logging Configuration

# app/core/logging.py
import logging
from pythonjsonlogger import jsonlogger

def setup_logging():
    logHandler = logging.StreamHandler()
    formatter = jsonlogger.JsonFormatter(
        fmt='%(asctime)s %(name)s %(levelname)s %(message)s'
    )
    logHandler.setFormatter(formatter)

    logger = logging.getLogger()
    logger.addHandler(logHandler)
    logger.setLevel(logging.INFO)

    return logger

Security Configuration

Production Security Checklist

  • API Keys: Store in secure environment variables or secret managers
  • JWT Security: Use strong secret keys (256-bit minimum)
  • Database Security: Use strong passwords, limit network access
  • HTTPS: Use valid SSL certificates, redirect HTTP to HTTPS
  • CORS: Configure appropriate origins, avoid wildcards in production
  • Rate Limiting: Implement API rate limiting
  • Input Validation: Validate and sanitize all inputs
  • Security Headers: Implement security headers in Nginx/proxy
  • Network Security: Use firewalls, VPNs, or security groups
  • Regular Updates: Keep dependencies and base images updated

Environment-Specific Security

# Production environment variables
export JWT_SECRET_KEY=$(openssl rand -hex 32)
export DB_PASSWORD=$(openssl rand -base64 32)
export NEO4J_PASSWORD=$(openssl rand -base64 32)

# Use AWS Secrets Manager, GCP Secret Manager, or Azure Key Vault
aws secretsmanager create-secret --name "quantbot/api-keys" --secret-string '{"GOOGLE_API_KEY":"..."}'

Performance Optimization

Production Optimizations

# app/core/config.py - Production settings
class ProductionConfig:
    # Database connection pooling
    DATABASE_POOL_SIZE = 20
    DATABASE_MAX_OVERFLOW = 30
    DATABASE_POOL_TIMEOUT = 30

    # API rate limiting
    RATE_LIMIT_PER_MINUTE = 60
    RATE_LIMIT_BURST = 10

    # Caching
    CACHE_TTL = 300  # 5 minutes
    MEMORY_CACHE_SIZE = 1000

    # AI optimizations
    MAX_CONCURRENT_AI_REQUESTS = 10
    AI_TIMEOUT = 30

    # Memory system
    MEMORY_BATCH_SIZE = 100
    MEMORY_SIMILARITY_THRESHOLD = 0.8

CDN Configuration

# CloudFront distribution for static assets
Resources:
  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Origins:
          - DomainName: yourdomain.com
            Id: quantbot-origin
            CustomOriginConfig:
              HTTPPort: 80
              HTTPSPort: 443
              OriginProtocolPolicy: https-only
        DefaultCacheBehavior:
          TargetOriginId: quantbot-origin
          ViewerProtocolPolicy: redirect-to-https
          CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad  # CachingOptimized
        Enabled: true
        Comment: Quantbot CDN

This comprehensive deployment guide provides production-ready configurations for various platforms and includes essential considerations for security, monitoring, and performance optimization.