# Docker Compose for MapleFile Backend - Production version: '3.8' services: # MapleFile Backend Application backend: build: context: . dockerfile: Dockerfile container_name: maplefile-backend restart: unless-stopped ports: - "${SERVER_PORT:-8000}:8000" environment: # Application - APP_ENVIRONMENT=${APP_ENVIRONMENT:-production} - APP_VERSION=${APP_VERSION:-0.1.0} - APP_DATA_DIRECTORY=/app/data # Server - SERVER_HOST=0.0.0.0 - SERVER_PORT=8000 - SERVER_READ_TIMEOUT=${SERVER_READ_TIMEOUT:-30s} - SERVER_WRITE_TIMEOUT=${SERVER_WRITE_TIMEOUT:-30s} - SERVER_IDLE_TIMEOUT=${SERVER_IDLE_TIMEOUT:-60s} - SERVER_SHUTDOWN_TIMEOUT=${SERVER_SHUTDOWN_TIMEOUT:-10s} # Database (Cassandra) - DATABASE_HOSTS=cassandra:9042 - DATABASE_KEYSPACE=${DATABASE_KEYSPACE:-maplefile} - DATABASE_CONSISTENCY=${DATABASE_CONSISTENCY:-QUORUM} - DATABASE_USERNAME=${DATABASE_USERNAME:-} - DATABASE_PASSWORD=${DATABASE_PASSWORD:-} - DATABASE_MIGRATIONS_PATH=./migrations # Cache (Redis) - CACHE_HOST=redis - CACHE_PORT=6379 - CACHE_PASSWORD=${CACHE_PASSWORD:-} - CACHE_DB=${CACHE_DB:-0} # S3 Storage - S3_ENDPOINT=${S3_ENDPOINT:-http://minio:9000} - S3_ACCESS_KEY=${S3_ACCESS_KEY:-minioadmin} - S3_SECRET_KEY=${S3_SECRET_KEY:-minioadmin} - S3_BUCKET=${S3_BUCKET:-maplefile} - S3_REGION=${S3_REGION:-us-east-1} - S3_USE_SSL=${S3_USE_SSL:-false} # JWT - JWT_SECRET=${JWT_SECRET:-change-me-in-production} - JWT_ACCESS_TOKEN_DURATION=${JWT_ACCESS_TOKEN_DURATION:-15m} - JWT_REFRESH_TOKEN_DURATION=${JWT_REFRESH_TOKEN_DURATION:-168h} - JWT_SESSION_DURATION=${JWT_SESSION_DURATION:-24h} # Email (Mailgun) - MAILGUN_API_KEY=${MAILGUN_API_KEY} - MAILGUN_DOMAIN=${MAILGUN_DOMAIN} - MAILGUN_API_BASE=${MAILGUN_API_BASE:-https://api.mailgun.net/v3} - MAILGUN_FROM_EMAIL=${MAILGUN_FROM_EMAIL:-noreply@maplefile.app} - MAILGUN_FROM_NAME=${MAILGUN_FROM_NAME:-MapleFile} - MAILGUN_FRONTEND_URL=${MAILGUN_FRONTEND_URL} # Invite Email Configuration - MAPLEFILE_INVITE_MAX_EMAILS_PER_DAY=${MAPLEFILE_INVITE_MAX_EMAILS_PER_DAY:-3} # Login Rate Limiting (production defaults - more restrictive) - LOGIN_RATE_LIMIT_MAX_ATTEMPTS_PER_IP=${LOGIN_RATE_LIMIT_MAX_ATTEMPTS_PER_IP:-50} - LOGIN_RATE_LIMIT_IP_WINDOW=${LOGIN_RATE_LIMIT_IP_WINDOW:-15m} - LOGIN_RATE_LIMIT_MAX_FAILED_PER_ACCOUNT=${LOGIN_RATE_LIMIT_MAX_FAILED_PER_ACCOUNT:-10} - LOGIN_RATE_LIMIT_LOCKOUT_DURATION=${LOGIN_RATE_LIMIT_LOCKOUT_DURATION:-30m} # Logging - LOG_LEVEL=${LOG_LEVEL:-info} - LOG_FORMAT=${LOG_FORMAT:-json} # Leader Election - LEADER_ELECTION_ENABLED=${LEADER_ELECTION_ENABLED:-true} - LEADER_ELECTION_LOCK_TTL=${LEADER_ELECTION_LOCK_TTL:-10s} - LEADER_ELECTION_HEARTBEAT_INTERVAL=${LEADER_ELECTION_HEARTBEAT_INTERVAL:-3s} - LEADER_ELECTION_RETRY_INTERVAL=${LEADER_ELECTION_RETRY_INTERVAL:-2s} volumes: - backend_data:/app/data depends_on: cassandra: condition: service_healthy redis: condition: service_healthy minio: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - maplefile-net logging: driver: "json-file" options: max-size: "10m" max-file: "3" # Cassandra Database cassandra: image: cassandra:4.1 container_name: maplefile-cassandra restart: unless-stopped environment: - CASSANDRA_CLUSTER_NAME=maplefile-cluster - CASSANDRA_DC=${CASSANDRA_DC:-datacenter1} - CASSANDRA_RACK=${CASSANDRA_RACK:-rack1} - CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch - MAX_HEAP_SIZE=${CASSANDRA_MAX_HEAP_SIZE:-2G} - HEAP_NEWSIZE=${CASSANDRA_HEAP_NEWSIZE:-512M} volumes: - cassandra_data:/var/lib/cassandra healthcheck: test: ["CMD-SHELL", "cqlsh -e 'describe cluster' || exit 1"] interval: 30s timeout: 10s retries: 10 start_period: 90s networks: - maplefile-net logging: driver: "json-file" options: max-size: "10m" max-file: "3" # Redis Cache redis: image: redis:7-alpine container_name: maplefile-redis restart: unless-stopped command: > redis-server --appendonly yes --maxmemory ${REDIS_MAX_MEMORY:-512mb} --maxmemory-policy allkeys-lru --requirepass ${CACHE_PASSWORD:-} volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 networks: - maplefile-net logging: driver: "json-file" options: max-size: "10m" max-file: "3" # MinIO S3-compatible storage minio: image: minio/minio:latest container_name: maplefile-minio restart: unless-stopped environment: - MINIO_ROOT_USER=${S3_ACCESS_KEY:-minioadmin} - MINIO_ROOT_PASSWORD=${S3_SECRET_KEY:-minioadmin} volumes: - minio_data:/data command: server /data --console-address ":9001" healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 15s timeout: 10s retries: 5 start_period: 20s networks: - maplefile-net logging: driver: "json-file" options: max-size: "10m" max-file: "3" # MinIO Initialization minio-init: image: minio/mc:latest container_name: maplefile-minio-init depends_on: minio: condition: service_healthy entrypoint: > /bin/sh -c " mc alias set myminio http://minio:9000 ${S3_ACCESS_KEY:-minioadmin} ${S3_SECRET_KEY:-minioadmin}; mc mb myminio/${S3_BUCKET:-maplefile} --ignore-existing; echo 'MinIO initialization complete'; " networks: - maplefile-net volumes: backend_data: driver: local cassandra_data: driver: local redis_data: driver: local minio_data: driver: local networks: maplefile-net: driver: bridge