# ManaCore Production Stack # Domain: manacore.ai # # Apps included: # - mana-core-auth (auth.manacore.ai) # - chat (chat.manacore.ai + chat-api.manacore.ai) # - todo (todo.manacore.ai + todo-api.manacore.ai) # - calendar (calendar.manacore.ai + calendar-api.manacore.ai) # - clock (clock.manacore.ai + clock-api.manacore.ai) # - manacore-web (app.manacore.ai) # # Usage: # docker compose -f docker-compose.yml up -d # docker compose -f docker-compose.yml logs -f # docker compose -f docker-compose.yml down services: # ============================================ # Infrastructure Services # ============================================ postgres: image: postgres:16-alpine container_name: manacore-postgres restart: always environment: POSTGRES_DB: ${POSTGRES_DB:-manacore} POSTGRES_USER: ${POSTGRES_USER:-postgres} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} volumes: - postgres_data:/var/lib/postgresql/data - ./backups:/backups ports: - "127.0.0.1:5432:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"] interval: 10s timeout: 5s retries: 5 networks: - manacore-network logging: driver: "json-file" options: max-size: "50m" max-file: "5" redis: image: redis:7-alpine container_name: manacore-redis restart: always command: redis-server --requirepass ${REDIS_PASSWORD:?REDIS_PASSWORD is required} --maxmemory 256mb --maxmemory-policy allkeys-lru volumes: - redis_data:/data ports: - "127.0.0.1:6379:6379" healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] interval: 10s timeout: 5s retries: 5 networks: - manacore-network logging: driver: "json-file" options: max-size: "20m" max-file: "3" # ============================================ # Reverse Proxy (Caddy - Auto HTTPS) # ============================================ caddy: image: caddy:2-alpine container_name: manacore-caddy restart: always ports: - "80:80" - "443:443" - "443:443/udp" # HTTP/3 volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config networks: - manacore-network logging: driver: "json-file" options: max-size: "20m" max-file: "3" # ============================================ # Auth Service # ============================================ mana-core-auth: image: ${DOCKER_REGISTRY:-ghcr.io/memo-2023}/mana-core-auth:${AUTH_VERSION:-latest} container_name: mana-core-auth restart: always depends_on: postgres: condition: service_healthy redis: condition: service_healthy environment: NODE_ENV: production PORT: 3001 DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@postgres:5432/manacore_auth REDIS_HOST: redis REDIS_PORT: 6379 REDIS_PASSWORD: ${REDIS_PASSWORD} JWT_SECRET: ${JWT_SECRET} JWT_PUBLIC_KEY: ${JWT_PUBLIC_KEY} JWT_PRIVATE_KEY: ${JWT_PRIVATE_KEY} JWT_ACCESS_TOKEN_EXPIRY: ${JWT_ACCESS_TOKEN_EXPIRY:-15m} JWT_REFRESH_TOKEN_EXPIRY: ${JWT_REFRESH_TOKEN_EXPIRY:-7d} CORS_ORIGINS: https://app.manacore.ai,https://chat.manacore.ai,https://todo.manacore.ai,https://calendar.manacore.ai,https://clock.manacore.ai CREDITS_SIGNUP_BONUS: ${CREDITS_SIGNUP_BONUS:-100} CREDITS_DAILY_FREE: ${CREDITS_DAILY_FREE:-5} # OAuth (optional) GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID:-} GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET:-} # Stripe (optional) STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY:-} STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET:-} ports: - "127.0.0.1:3001:3001" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/api/v1/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - manacore-network logging: driver: "json-file" options: max-size: "50m" max-file: "5" deploy: resources: limits: cpus: '1' memory: 512M # ============================================ # Chat App # ============================================ chat-backend: image: ${DOCKER_REGISTRY:-ghcr.io/memo-2023}/chat-backend:${CHAT_VERSION:-latest} container_name: chat-backend restart: always depends_on: mana-core-auth: condition: service_healthy postgres: condition: service_healthy environment: NODE_ENV: production PORT: 3002 DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@postgres:5432/chat MANA_CORE_AUTH_URL: http://mana-core-auth:3001 AZURE_OPENAI_ENDPOINT: ${AZURE_OPENAI_ENDPOINT} AZURE_OPENAI_API_KEY: ${AZURE_OPENAI_API_KEY} AZURE_OPENAI_API_VERSION: ${AZURE_OPENAI_API_VERSION:-2024-12-01-preview} CORS_ORIGINS: https://chat.manacore.ai,https://app.manacore.ai ports: - "127.0.0.1:3002:3002" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3002/api/v1/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - manacore-network logging: driver: "json-file" options: max-size: "50m" max-file: "5" deploy: resources: limits: cpus: '2' memory: 1G chat-web: image: ${DOCKER_REGISTRY:-ghcr.io/memo-2023}/chat-web:${CHAT_WEB_VERSION:-latest} container_name: chat-web restart: always depends_on: chat-backend: condition: service_healthy environment: NODE_ENV: production PORT: 3000 # Server-side URLs (Docker internal) PUBLIC_BACKEND_URL: http://chat-backend:3002 PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001 # Client-side URLs (browser) PUBLIC_BACKEND_URL_CLIENT: https://chat-api.manacore.ai PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.manacore.ai ports: - "127.0.0.1:3000:3000" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - manacore-network logging: driver: "json-file" options: max-size: "20m" max-file: "3" deploy: resources: limits: cpus: '0.5' memory: 256M # ============================================ # ManaCore Dashboard # ============================================ manacore-web: image: ${DOCKER_REGISTRY:-ghcr.io/memo-2023}/manacore-web:${MANACORE_WEB_VERSION:-latest} container_name: manacore-web restart: always depends_on: mana-core-auth: condition: service_healthy environment: NODE_ENV: production PORT: 5173 # Auth PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001 PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.manacore.ai # Backend URLs for dashboard widgets PUBLIC_TODO_API_URL: http://todo-backend:3018 PUBLIC_TODO_API_URL_CLIENT: https://todo-api.manacore.ai PUBLIC_CALENDAR_API_URL: http://calendar-backend:3016 PUBLIC_CALENDAR_API_URL_CLIENT: https://calendar-api.manacore.ai PUBLIC_CLOCK_API_URL: http://clock-backend:3017 PUBLIC_CLOCK_API_URL_CLIENT: https://clock-api.manacore.ai PUBLIC_CHAT_API_URL: http://chat-backend:3002 PUBLIC_CHAT_API_URL_CLIENT: https://chat-api.manacore.ai ports: - "127.0.0.1:5173:5173" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5173/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - manacore-network logging: driver: "json-file" options: max-size: "20m" max-file: "3" deploy: resources: limits: cpus: '0.5' memory: 256M # ============================================ # Todo App # ============================================ todo-backend: image: ${DOCKER_REGISTRY:-ghcr.io/memo-2023}/todo-backend:${TODO_VERSION:-latest} container_name: todo-backend restart: always depends_on: mana-core-auth: condition: service_healthy postgres: condition: service_healthy environment: NODE_ENV: production PORT: 3018 DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@postgres:5432/todo DB_HOST: postgres DB_PORT: 5432 DB_USER: ${POSTGRES_USER:-postgres} MANA_CORE_AUTH_URL: http://mana-core-auth:3001 CORS_ORIGINS: https://todo.manacore.ai,https://app.manacore.ai ports: - "127.0.0.1:3018:3018" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3018/api/v1/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - manacore-network logging: driver: "json-file" options: max-size: "20m" max-file: "3" deploy: resources: limits: cpus: '0.5' memory: 256M todo-web: image: ${DOCKER_REGISTRY:-ghcr.io/memo-2023}/todo-web:${TODO_WEB_VERSION:-latest} container_name: todo-web restart: always depends_on: todo-backend: condition: service_healthy environment: NODE_ENV: production PORT: 5188 PUBLIC_BACKEND_URL: http://todo-backend:3018 PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001 PUBLIC_BACKEND_URL_CLIENT: https://todo-api.manacore.ai PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.manacore.ai ports: - "127.0.0.1:5188:5188" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5188/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - manacore-network logging: driver: "json-file" options: max-size: "20m" max-file: "3" deploy: resources: limits: cpus: '0.5' memory: 256M # ============================================ # Calendar App # ============================================ calendar-backend: image: ${DOCKER_REGISTRY:-ghcr.io/memo-2023}/calendar-backend:${CALENDAR_VERSION:-latest} container_name: calendar-backend restart: always depends_on: mana-core-auth: condition: service_healthy postgres: condition: service_healthy environment: NODE_ENV: production PORT: 3016 DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@postgres:5432/calendar DB_HOST: postgres DB_PORT: 5432 DB_USER: ${POSTGRES_USER:-postgres} MANA_CORE_AUTH_URL: http://mana-core-auth:3001 CORS_ORIGINS: https://calendar.manacore.ai,https://app.manacore.ai ports: - "127.0.0.1:3016:3016" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3016/api/v1/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - manacore-network logging: driver: "json-file" options: max-size: "20m" max-file: "3" deploy: resources: limits: cpus: '0.5' memory: 256M calendar-web: image: ${DOCKER_REGISTRY:-ghcr.io/memo-2023}/calendar-web:${CALENDAR_WEB_VERSION:-latest} container_name: calendar-web restart: always depends_on: calendar-backend: condition: service_healthy environment: NODE_ENV: production PORT: 5186 PUBLIC_BACKEND_URL: http://calendar-backend:3016 PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001 PUBLIC_BACKEND_URL_CLIENT: https://calendar-api.manacore.ai PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.manacore.ai ports: - "127.0.0.1:5186:5186" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5186/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - manacore-network logging: driver: "json-file" options: max-size: "20m" max-file: "3" deploy: resources: limits: cpus: '0.5' memory: 256M # ============================================ # Clock App # ============================================ clock-backend: image: ${DOCKER_REGISTRY:-ghcr.io/memo-2023}/clock-backend:${CLOCK_VERSION:-latest} container_name: clock-backend restart: always depends_on: mana-core-auth: condition: service_healthy postgres: condition: service_healthy environment: NODE_ENV: production PORT: 3017 DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@postgres:5432/clock DB_HOST: postgres DB_PORT: 5432 DB_USER: ${POSTGRES_USER:-postgres} MANA_CORE_AUTH_URL: http://mana-core-auth:3001 CORS_ORIGINS: https://clock.manacore.ai,https://app.manacore.ai ports: - "127.0.0.1:3017:3017" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3017/api/v1/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - manacore-network logging: driver: "json-file" options: max-size: "20m" max-file: "3" deploy: resources: limits: cpus: '0.5' memory: 256M clock-web: image: ${DOCKER_REGISTRY:-ghcr.io/memo-2023}/clock-web:${CLOCK_WEB_VERSION:-latest} container_name: clock-web restart: always depends_on: clock-backend: condition: service_healthy environment: NODE_ENV: production PORT: 5187 PUBLIC_BACKEND_URL: http://clock-backend:3017 PUBLIC_MANA_CORE_AUTH_URL: http://mana-core-auth:3001 PUBLIC_BACKEND_URL_CLIENT: https://clock-api.manacore.ai PUBLIC_MANA_CORE_AUTH_URL_CLIENT: https://auth.manacore.ai ports: - "127.0.0.1:5187:5187" healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5187/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s networks: - manacore-network logging: driver: "json-file" options: max-size: "20m" max-file: "3" deploy: resources: limits: cpus: '0.5' memory: 256M # ============================================ # Networks # ============================================ networks: manacore-network: driver: bridge name: manacore-production # ============================================ # Volumes # ============================================ volumes: postgres_data: name: manacore-postgres-prod redis_data: name: manacore-redis-prod caddy_data: name: manacore-caddy-data caddy_config: name: manacore-caddy-config