Deployment
DigitalOcean App Platform

DigitalOcean App Platform Deployment

Comprehensive deployment guide for the MyNATCA ecosystem on DigitalOcean App Platform, including multi-service configuration, Redis setup, and production best practices.

Deployment Architecture Overview

The MyNATCA ecosystem is deployed using Docker containers on DigitalOcean infrastructure with Express.js backend services:

Docker Configuration

Platform Service Dockerfile

The platform uses a production-optimized Dockerfile with Node.js 18 Alpine:

# MyNATCA Platform - Production Docker Configuration
FROM node:18-alpine
 
# Set the working directory
WORKDIR /app
 
# Copy package files first (for better caching)
COPY package*.json ./
 
# Install production dependencies only
RUN npm ci --only=production && npm cache clean --force
 
# Create a non-root user for security
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001
 
# Copy the rest of the application
COPY . .
 
# Create logs directory and set permissions
RUN mkdir -p logs && chown -R nodejs:nodejs /app
 
# Switch to non-root user
USER nodejs
 
# Expose the port the app runs on
EXPOSE 3000
 
# Add health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000/api/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"
 
# Start the application
CMD ["npm", "start"]

PM2 Production Configuration

The platform uses PM2 for process management in cluster mode:

// ecosystem.config.js - PM2 Production Configuration
module.exports = {
  apps: [{
    name: 'mynatca-platform',
    script: 'server.js',
    cwd: '/opt/mynatca-platform',
    instances: 'max', // Use all available CPU cores
    exec_mode: 'cluster',
 
    // Environment configuration
    env: {
      NODE_ENV: 'production',
      PORT: 3000,
      HOST: '0.0.0.0'
    },
 
    // Logging configuration
    log_file: './logs/combined.log',
    out_file: './logs/out.log',
    error_file: './logs/error.log',
    time: true,
    log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
 
    // Memory and performance
    max_memory_restart: '500M',
    node_args: '--max_old_space_size=460',
 
    // Process management
    min_uptime: '10s',
    max_restarts: 5,
    autorestart: true,
 
    // Monitoring
    monitor: true,
 
    // Health check
    health_check_grace_period: 3000
  }]
};

Production Deployment Process

Prerequisites

DigitalOcean Requirements

  • Droplet: Minimum 2GB RAM, 1 vCPU (recommended: 4GB RAM, 2 vCPU)
  • Operating System: Ubuntu 22.04 LTS
  • Storage: 50GB SSD minimum
  • Networking: Firewall configured for ports 80, 443, 22

External Services

  1. Supabase Project: PostgreSQL database with migrations applied
  2. Auth0 Tenant: Server-side authentication configuration
  3. Redis Instance: Session storage with password authentication
  4. MySQL Access: Read-only access to MyNATCA production database

Server Setup

# Update system and install Node.js 18.x
sudo apt update && sudo apt upgrade -y
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
 
# Install Docker and Docker Compose
sudo apt install docker.io docker-compose -y
sudo systemctl enable docker
sudo usermod -aG docker $USER
 
# Install Nginx for reverse proxy
sudo apt install nginx -y
sudo systemctl enable nginx
 
# Install PM2 for process management
sudo npm install -g pm2

Application Deployment

# Clone and setup application
git clone <repository-url> /opt/mynatca-platform
cd /opt/mynatca-platform
 
# Install production dependencies
npm ci --only=production
 
# Copy environment configuration
cp .env.production.example .env.production
 
# Build Docker image
docker build -t mynatca-platform:latest .
 
# Start with PM2 cluster mode
pm2 start ecosystem.config.js --env production
 
# Save PM2 configuration
pm2 save
pm2 startup

Environment Variables

Required Production Configuration

# Server Configuration
NODE_ENV=production
PORT=3000
HOST=0.0.0.0
 
# Database Configuration
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
 
# Authentication
AUTH0_DOMAIN=mynatca.auth0.com
AUTH0_CLIENT_ID=your_client_id
AUTH0_CLIENT_SECRET=your_client_secret
AUTH0_REDIRECT_URI=https://platform.natca.org/api/auth/callback
AUTH0_BASE_URL=https://platform.natca.org
 
# Session Management
SESSION_SECRET=your_secure_session_secret_64_chars_minimum
REDIS_URL=redis://username:password@redis-host:6379
 
# Service Keys
SYNC_API_KEY=secure_sync_api_key
DISCORD_SERVICE_KEY=discord_bot_service_key
 
# External Services
DISCORD_BOT_URL=https://discord.natca.org

App Platform Configuration

Complete App Specification

# .do/app.yaml - DigitalOcean App Platform specification
name: mynatca-ecosystem
region: nyc
 
# Platform Service Configuration
services:
  - name: platform
    source_dir: /
    dockerfile_path: Dockerfile
    github:
      repo: natca/mynatca-platform
      branch: main
    run_command: npm start
    environment_slug: node-js
    instance_count: 2
    instance_size_slug: professional-xs
 
    # Health check configuration
    health_check:
      http_path: /api/health
      initial_delay_seconds: 30
      period_seconds: 10
      timeout_seconds: 5
      success_threshold: 1
      failure_threshold: 3
 
    # Auto-scaling configuration
    autoscaling:
      min_instance_count: 1
      max_instance_count: 3
      metrics:
        cpu:
          percent: 80
 
# Environment Variables
envs:
  - key: NODE_ENV
    value: production
    type: GENERAL
  - key: PORT
    value: "3000"
    type: GENERAL
    value: ${supabase.url}
    type: SECRET
  - key: SUPABASE_ANON_KEY
    value: ${supabase.anon_key}
    type: SECRET
  - key: SUPABASE_SERVICE_ROLE_KEY
    value: ${supabase.service_role_key}
    type: SECRET
  - key: AUTH0_DOMAIN
    value: ${auth0.domain}
    type: SECRET
  - key: AUTH0_CLIENT_ID
    value: ${auth0.client_id}
    type: SECRET
  - key: AUTH0_CLIENT_SECRET
    value: ${auth0.client_secret}
    type: SECRET
  - key: AUTH0_AUDIENCE
    value: ${auth0.audience}
    type: SECRET
  - key: REDIS_URL
    value: ${redis.url}
    type: SECRET
  - key: MYSQL_HOST
    value: ${mysql.host}
    type: SECRET
  - key: MYSQL_USER
    value: ${mysql.user}
    type: SECRET
  - key: MYSQL_PASSWORD
    value: ${mysql.password}
    type: SECRET
  - key: MYSQL_DATABASE
    value: ${mysql.database}
    type: SECRET
 
services:
  # MyNATCA Platform (Backend API & Proxy)
  - name: platform
    source_dir: /platform
    github:
      repo: yourusername/mynatca-platform
      branch: main
      deploy_on_push: true
 
    build_command: |
      echo "Building MyNATCA Platform..."
      npm ci --production=false
      echo "Platform build complete"
 
    run_command: |
      echo "Starting MyNATCA Platform..."
      npm start
 
    environment_slug: node-js
    instance_count: 2
    instance_size_slug: professional-xs
    http_port: 1300
 
    health_check:
      http_path: /api/health
      initial_delay_seconds: 60
      period_seconds: 10
      success_threshold: 1
      failure_threshold: 3
      timeout_seconds: 5
 
    envs:
      - key: PORT
        value: "1300"
        type: GENERAL
      - key: SESSION_SECRET
        value: ${session.secret}
        type: SECRET
      - key: PLATFORM_SERVICE_NAME
        value: "mynatca-platform"
        type: GENERAL
 
    alerts:
      - rule: CPU_UTILIZATION
        value: 75
        operator: GREATER_THAN
      - rule: MEM_UTILIZATION
        value: 80
        operator: GREATER_THAN
 
  # MyNATCA Hub (Frontend Vue.js Application)
  - name: hub
    source_dir: /hub
    github:
      repo: yourusername/mynatca-hub
      branch: main
      deploy_on_push: true
 
    build_command: |
      echo "Building MyNATCA Hub..."
      npm ci --production=false
      npm run typecheck
      npm run build
      echo "Hub build complete"
 
    run_command: |
      echo "Starting MyNATCA Hub preview server..."
      npm run preview
 
    environment_slug: node-js
    instance_count: 2
    instance_size_slug: professional-xs
    http_port: 1301
 
    health_check:
      http_path: /
      initial_delay_seconds: 60
      period_seconds: 10
      success_threshold: 1
      failure_threshold: 3
      timeout_seconds: 5
 
    envs:
      - key: PORT
        value: "1301"
        type: GENERAL
      - key: VITE_SUPABASE_URL
        value: ${supabase.url}
        type: SECRET
      - key: VITE_SUPABASE_ANON_KEY
        value: ${supabase.anon_key}
        type: SECRET
      - key: VITE_AUTH0_DOMAIN
        value: ${auth0.domain}
        type: SECRET
      - key: VITE_AUTH0_CLIENT_ID
        value: ${auth0.client_id}
        type: SECRET
      - key: VITE_PLATFORM_URL
        value: "https://${APP_DOMAIN}/api"
        type: GENERAL
 
    routes:
      - path: /hub
        preserve_path_prefix: true
 
    alerts:
      - rule: CPU_UTILIZATION
        value: 75
        operator: GREATER_THAN
 
  # MyNATCA Discord Bot
  - name: discord-bot
    source_dir: /discord
    github:
      repo: yourusername/mynatca-discord
      branch: main
      deploy_on_push: true
 
    build_command: |
      echo "Building MyNATCA Discord Bot..."
      npm ci --production=false
      echo "Discord bot build complete"
 
    run_command: |
      echo "Starting MyNATCA Discord Bot..."
      npm start
 
    environment_slug: node-js
    instance_count: 1
    instance_size_slug: basic-xxs
 
    envs:
      - key: DISCORD_TOKEN
        value: ${discord.token}
        type: SECRET
      - key: DISCORD_CLIENT_ID
        value: ${discord.client_id}
        type: SECRET
      - key: DISCORD_CLIENT_SECRET
        value: ${discord.client_secret}
        type: SECRET
      - key: GUILD_ID
        value: ${discord.guild_id}
        type: SECRET
      - key: PLATFORM_URL
        value: "https://${APP_DOMAIN}/api"
        type: GENERAL
 
    alerts:
      - rule: CPU_UTILIZATION
        value: 85
        operator: GREATER_THAN
 
# Database Configuration (References to external services)
databases: []
 
# Ingress Configuration
ingress:
  rules:
    - match:
        path:
          prefix: /api
      component:
        name: platform
    - match:
        path:
          prefix: /hub
      component:
        name: hub
    - match:
        path:
          prefix: /
      component:
        name: platform
 
  load_balancer:
    algorithm: round_robin
    sticky_sessions:
      type: cookies
      cookie_name: PLATFORM_SESSION
      cookie_ttl_seconds: 3600
 
# Domain Configuration
domains:
  - domain: mynatca-hub.com
    type: PRIMARY
    minimum_tls_version: "1.2"
    certificate:
      type: LETS_ENCRYPT
  - domain: platform.mynatca-hub.com
    type: ALIAS
    minimum_tls_version: "1.2"
    certificate:
      type: LETS_ENCRYPT
 
# Static Sites (if any)
static_sites: []
 
# Background Jobs/Workers
jobs: []

Redis Database Setup

Managed Redis Configuration

#!/bin/bash
# .do/provision-redis.sh - Automated Redis provisioning
 
set -e
 
# Configuration
REDIS_CLUSTER_NAME="mynatca-redis"
REDIS_REGION="nyc3"
REDIS_SIZE="db-s-1vcpu-2gb"  # Production recommendation
REDIS_NODES=1                 # Single node for cost efficiency
REDIS_VERSION="7"
 
echo "🔧 Provisioning MyNATCA Redis cluster..."
 
# Create Redis cluster
echo "📦 Creating Redis cluster: $REDIS_CLUSTER_NAME"
doctl databases create redis $REDIS_CLUSTER_NAME \
  --engine redis \
  --version $REDIS_VERSION \
  --size $REDIS_SIZE \
  --region $REDIS_REGION \
  --num-nodes $REDIS_NODES \
  --wait
 
# Get cluster information
echo "🔍 Retrieving cluster information..."
CLUSTER_ID=$(doctl databases list --format ID,Name --no-header | grep $REDIS_CLUSTER_NAME | awk '{print $1}')
 
if [ -z "$CLUSTER_ID" ]; then
  echo "❌ Failed to retrieve cluster ID"
  exit 1
fi
 
echo "✅ Redis cluster created successfully!"
echo "📋 Cluster ID: $CLUSTER_ID"
 
# Get connection details
echo "🔗 Retrieving connection details..."
CONNECTION_INFO=$(doctl databases connection $CLUSTER_ID --format URI --no-header)
 
echo "✅ Redis cluster ready for use!"
echo "🔗 Connection String: $CONNECTION_INFO"
echo ""
echo "📝 Next Steps:"
echo "   1. Add REDIS_URL environment variable to your App Platform config"
echo "   2. Update app.yaml with the connection string"
echo "   3. Deploy your application"
echo ""
echo "💰 Estimated Monthly Cost: $25 USD (db-s-1vcpu-2gb)"

Redis Sizing Recommendations

Use CaseSizeMonthly CostRecommendation
Developmentdb-s-1vcpu-1gb$15Testing and dev environments
Production (Recommended)db-s-1vcpu-2gb$25Main production deployment
High Availabilitydb-s-2vcpu-4gb (2 nodes)$100Critical production with failover
Enterprisedb-s-4vcpu-8gb (3 nodes)$300High-traffic, mission-critical

Automated Deployment

Deployment Script

#!/bin/bash
# .do/deploy.sh - Automated deployment script
 
set -e
 
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
 
# Configuration
APP_NAME="mynatca-ecosystem"
REGION="nyc3"
 
echo -e "${BLUE}🚀 MyNATCA Ecosystem Deployment${NC}"
echo "========================================="
 
# Pre-flight checks
echo -e "${YELLOW}🔍 Running pre-flight checks...${NC}"
 
# Check if doctl is installed
if ! command -v doctl &> /dev/null; then
    echo -e "${RED}❌ doctl CLI is not installed${NC}"
    echo "   Install: https://docs.digitalocean.com/reference/doctl/how-to/install/"
    exit 1
fi
 
# Check authentication
if ! doctl auth list &> /dev/null; then
    echo -e "${RED}❌ Please authenticate with DigitalOcean first${NC}"
    echo "   Run: doctl auth init"
    exit 1
fi
 
# Check required files
for file in ".do/app.yaml" "platform/package.json" "hub/package.json"; do
    if [ ! -f "$file" ]; then
        echo -e "${RED}❌ Required file not found: $file${NC}"
        exit 1
    fi
done
 
echo -e "${GREEN}✅ Pre-flight checks passed${NC}"
 
# Environment variables check
echo -e "${YELLOW}🔐 Checking environment variables...${NC}"
 
required_vars=(
    "SUPABASE_URL"
    "SUPABASE_ANON_KEY"
    "SUPABASE_SERVICE_ROLE_KEY"
    "AUTH0_DOMAIN"
    "AUTH0_CLIENT_ID"
    "AUTH0_CLIENT_SECRET"
    "AUTH0_AUDIENCE"
    "REDIS_URL"
    "SESSION_SECRET"
    "DISCORD_TOKEN"
    "DISCORD_CLIENT_ID"
    "DISCORD_CLIENT_SECRET"
    "GUILD_ID"
)
 
missing_vars=()
for var in "${required_vars[@]}"; do
    if [ -z "${!var}" ]; then
        missing_vars+=("$var")
    fi
done
 
if [ ${#missing_vars[@]} -ne 0 ]; then
    echo -e "${YELLOW}⚠️  Missing environment variables:${NC}"
    printf '   - %s\n' "${missing_vars[@]}"
    echo -e "${YELLOW}   Configure these in DigitalOcean App Platform dashboard${NC}"
fi
 
# Deploy application
echo -e "${YELLOW}🚀 Deploying application...${NC}"
 
if doctl apps list --format Name --no-header | grep -q "^${APP_NAME}$"; then
    echo -e "${YELLOW}📱 App '${APP_NAME}' exists, updating...${NC}"
 
    APP_ID=$(doctl apps list --format ID,Name --no-header | grep "${APP_NAME}" | awk '{print $1}')
    doctl apps update ${APP_ID} --spec .do/app.yaml
 
    echo -e "${GREEN}✅ App updated successfully!${NC}"
else
    echo -e "${BLUE}🆕 Creating new app '${APP_NAME}'...${NC}"
 
    APP_OUTPUT=$(doctl apps create --spec .do/app.yaml --format ID,Name,DefaultIngress --no-header)
    APP_ID=$(echo "$APP_OUTPUT" | awk '{print $1}')
    APP_URL=$(echo "$APP_OUTPUT" | awk '{print $3}')
 
    echo -e "${GREEN}✅ App created successfully!${NC}"
    echo -e "${BLUE}📋 App ID: ${APP_ID}${NC}"
    echo -e "${BLUE}🌐 App URL: https://${APP_URL}${NC}"
fi
 
# Monitor deployment
echo -e "${YELLOW}⏳ Monitoring deployment...${NC}"
 
DEPLOYMENT_ID=""
while true; do
    if [ -z "$DEPLOYMENT_ID" ]; then
        DEPLOYMENT_ID=$(doctl apps list-deployments ${APP_ID} --format ID --no-header | head -n1)
    fi
 
    if [ -n "$DEPLOYMENT_ID" ]; then
        STATUS=$(doctl apps get-deployment ${APP_ID} ${DEPLOYMENT_ID} --format Phase --no-header)
        echo -e "${BLUE}   Status: ${STATUS}${NC}"
 
        case "$STATUS" in
            "ACTIVE")
                echo -e "${GREEN}✅ Deployment completed successfully!${NC}"
                break
                ;;
            "ERROR"|"SUPERSEDED")
                echo -e "${RED}❌ Deployment failed: ${STATUS}${NC}"
                exit 1
                ;;
            *)
                sleep 30
                ;;
        esac
    else
        sleep 10
    fi
done
 
echo -e "${GREEN}🎉 MyNATCA Ecosystem deployed successfully!${NC}"
echo -e "${BLUE}🎛️  Dashboard: https://cloud.digitalocean.com/apps/${APP_ID}${NC}"

CI/CD Integration

# .github/workflows/deploy.yml - GitHub Actions deployment
name: Deploy to DigitalOcean App Platform
 
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
 
env:
  REGISTRY: registry.digitalocean.com
  IMAGE_NAME: mynatca-platform
 
jobs:
  deploy:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
 
    steps:
    - name: Checkout repository
      uses: actions/checkout@v3
 
    - name: Install doctl
      uses: digitalocean/action-doctl@v2
      with:
        token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
 
    - name: Update app specification
      run: |
        # Replace environment variable placeholders
        sed -i 's/${supabase.url}/${{ secrets.SUPABASE_URL }}/g' .do/app.yaml
        sed -i 's/${auth0.domain}/${{ secrets.AUTH0_DOMAIN }}/g' .do/app.yaml
        # ... other replacements
 
    - name: Deploy to App Platform
      run: |
        APP_ID=$(doctl apps list --format ID,Name --no-header | grep mynatca-ecosystem | awk '{print $1}')
        if [ -n "$APP_ID" ]; then
          doctl apps update $APP_ID --spec .do/app.yaml
        else
          doctl apps create --spec .do/app.yaml
        fi
 
    - name: Wait for deployment
      run: |
        APP_ID=$(doctl apps list --format ID,Name --no-header | grep mynatca-ecosystem | awk '{print $1}')
        doctl apps get $APP_ID --wait

Environment Management

Development Environment

# .env.development
NODE_ENV=development
PORT=1300
 
# Database
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your_anon_key
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
 
# Auth
AUTH0_DOMAIN=your-domain.auth0.com
AUTH0_CLIENT_ID=your_client_id
AUTH0_CLIENT_SECRET=your_client_secret
AUTH0_AUDIENCE=your_audience
 
# Session
SESSION_SECRET=your_long_random_secret_key_here
REDIS_URL=redis://localhost:6379/0
 
# Frontend
VITE_PLATFORM_URL=http://localhost:1300/api
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your_anon_key
VITE_AUTH0_DOMAIN=your-domain.auth0.com
VITE_AUTH0_CLIENT_ID=your_client_id

Production Environment Variables

Environment variables in DigitalOcean App Platform dashboard:

VariableTypeDescriptionExample
NODE_ENVGeneralApplication environmentproduction
SUPABASE_URLSecretSupabase project URLhttps://abc.supabase.co
SUPABASE_SERVICE_ROLE_KEYSecretSupabase service role keyeyJhbGciOiJI...
AUTH0_DOMAINSecretAuth0 tenant domainmynatca.auth0.com
AUTH0_CLIENT_SECRETSecretAuth0 application secretabc123...
REDIS_URLSecretRedis connection stringredis://user:pass@host:port/db
SESSION_SECRETSecretSession encryption key256-bit random key
DISCORD_TOKENSecretDiscord bot tokenODc2...

Monitoring and Scaling

Health Checks

// Platform: /api/health endpoint
app.get('/api/health', async (req, res) => {
  const health = {
    status: 'healthy',
    timestamp: new Date().toISOString(),
    service: 'mynatca-platform',
    version: process.env.npm_package_version,
    environment: process.env.NODE_ENV,
    dependencies: {}
  };
 
  try {
    // Check Redis connectivity
    await redisClient.ping();
    health.dependencies.redis = 'healthy';
  } catch (error) {
    health.dependencies.redis = 'unhealthy';
    health.status = 'degraded';
  }
 
  try {
    // Check Supabase connectivity
    const { data, error } = await supabase
      .from('proxy_routes')
      .select('count')
      .limit(1);
 
    health.dependencies.supabase = error ? 'unhealthy' : 'healthy';
    if (error) health.status = 'degraded';
  } catch (error) {
    health.dependencies.supabase = 'unhealthy';
    health.status = 'degraded';
  }
 
  const statusCode = health.status === 'healthy' ? 200 : 503;
  res.status(statusCode).json(health);
});

Auto-scaling Configuration

# App Platform auto-scaling alerts
alerts:
  - rule: CPU_UTILIZATION
    value: 75
    operator: GREATER_THAN
    window: FIVE_MINUTES
 
  - rule: MEM_UTILIZATION
    value: 80
    operator: GREATER_THAN
    window: FIVE_MINUTES
 
  - rule: RESTART_COUNT
    value: 10
    operator: GREATER_THAN
    window: ONE_HOUR

Performance Monitoring

// Platform: Performance middleware
const performanceMonitoring = (req, res, next) => {
  const start = Date.now();
 
  res.on('finish', () => {
    const duration = Date.now() - start;
    const logData = {
      method: req.method,
      url: req.url,
      statusCode: res.statusCode,
      duration,
      userAgent: req.get('user-agent'),
      ip: req.ip,
      timestamp: new Date().toISOString()
    };
 
    // Log slow requests
    if (duration > 5000) {
      console.warn('Slow request detected:', logData);
    }
 
    // Log errors
    if (res.statusCode >= 400) {
      console.error('Error request:', logData);
    }
  });
 
  next();
};
 
app.use(performanceMonitoring);

Cost Optimization

Resource Sizing

ServiceInstance TypeCountMonthly CostUse Case
PlatformProfessional-XS2~$50API gateway with session management
HubProfessional-XS2~$50Vue.js frontend with build process
Discord BotBasic-XXS1~$5Lightweight Discord integration
Redisdb-s-1vcpu-2gb1~$25Session storage
Total~$130Production deployment

Cost Reduction Strategies

  1. Development Environment: Use Basic instances
  2. Single Node Redis: Avoid cluster for non-critical applications
  3. Horizontal Scaling: Start with 1 instance per service
  4. Monitor Usage: Use DigitalOcean monitoring to right-size

Estimated Costs by Scale

ScaleInstancesRedisTotal Monthly
Starter3x BasicSingle node~$45
Production5x Professional-XSSingle node~$130
Enterprise8x Professional-SHA cluster~$400

Troubleshooting Deployment

Common Issues

Build Failures

# Check build logs
doctl apps logs <APP_ID> --type=build
 
# Common solutions
# 1. Clear node_modules in build command
# 2. Specify Node.js version
# 3. Check dependency versions

Environment Variable Issues

# List current environment variables
doctl apps get <APP_ID> --format Spec
 
# Update environment variables
doctl apps update <APP_ID> --spec .do/app.yaml

Database Connection Issues

# Test Redis connectivity
doctl databases connection <REDIS_CLUSTER_ID>
 
# Check connection string format
redis://username:password@host:port/database

Service Communication Issues

# Check ingress routing
doctl apps get <APP_ID> --format Spec
 
# Verify service endpoints
curl -v https://your-app.ondigitalocean.app/api/health

This deployment configuration provides a robust, scalable foundation for the MyNATCA ecosystem on DigitalOcean App Platform with proper monitoring, auto-scaling, and cost optimization.