x-customizable-image: # Custom Academy LMS image with all required apps &customizable_image image: ${CUSTOM_IMAGE:-ghcr.io/exarlabs/ignis-academy-lms}:${CUSTOM_TAG:-latest} pull_policy: ${PULL_POLICY:-always} restart: ${RESTART_POLICY:-unless-stopped} x-depends-on-configurator: &depends_on_configurator depends_on: configurator: condition: service_completed_successfully x-backend-defaults: &backend_defaults <<: [ *depends_on_configurator, *customizable_image ] volumes: - sites:/home/frappe/frappe-bench/sites networks: - frappe-network - langchain-network services: # MariaDB database (from academy-lms) mariadb: image: mariadb:10.8 command: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci - --skip-character-set-client-handshake - --skip-innodb-read-only-compressed environment: MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD} volumes: - mariadb-data:/var/lib/mysql - ./backups:/backups networks: - frappe-network restart: unless-stopped # Redis (shared between frappe and langchain) redis: image: redis:alpine networks: - frappe-network - langchain-network restart: unless-stopped # PostgreSQL for LangChain service postgres: image: postgres:15 environment: POSTGRES_DB: ${LANGCHAIN_DB_NAME:-langchain_db} POSTGRES_USER: ${LANGCHAIN_DB_USER:-langchain_user} POSTGRES_PASSWORD: ${LANGCHAIN_DB_PASSWORD:-langchain_pass} volumes: - postgres-data:/var/lib/postgresql/data networks: - langchain-network restart: unless-stopped healthcheck: test: [ "CMD-SHELL", "pg_isready -U ${LANGCHAIN_DB_USER:-langchain_user}" ] interval: 10s timeout: 5s retries: 5 # Initialize LangChain database tables langchain-db-init: image: ${LANGCHAIN_IMAGE:-ghcr.io/exarlabs/academy-langchain}:${LANGCHAIN_TAG:-latest} environment: - DATABASE_URL=postgresql://${LANGCHAIN_DB_USER:-langchain_user}:${LANGCHAIN_DB_PASSWORD:-langchain_pass}@postgres:5432/${LANGCHAIN_DB_NAME:-langchain_db} networks: - langchain-network depends_on: postgres: condition: service_healthy restart: on-failure command: sh -c "cd /app && PYTHONPATH=/app python app/create_tables.py" # LangChain service for AI functionality langchain-service: image: ${LANGCHAIN_IMAGE:-ghcr.io/exarlabs/academy-langchain}:${LANGCHAIN_TAG:-latest} environment: - OPENAI_API_KEY=${OPENAI_API_KEY} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - DATABASE_URL=postgresql://${LANGCHAIN_DB_USER:-langchain_user}:${LANGCHAIN_DB_PASSWORD:-langchain_pass}@postgres:5432/${LANGCHAIN_DB_NAME:-langchain_db} - REDIS_URL=redis://redis:6379 - ENV=${LANGCHAIN_ENV:-development} - DEBUG=${LANGCHAIN_DEBUG:-true} networks: - langchain-network depends_on: postgres: condition: service_healthy redis: condition: service_started langchain-db-init: condition: service_completed_successfully restart: unless-stopped ports: - "8001:8000" # Expose on different port to avoid conflict healthcheck: test: [ "CMD", "curl", "-f", "http://localhost:8000/health" ] interval: 30s timeout: 10s retries: 5 start_period: 40s configurator: <<: *backend_defaults platform: linux/amd64 entrypoint: - bash - -c command: - > ls -1 apps > sites/apps.txt; bench set-config -g db_host mariadb; bench set-config -gp db_port 3306; bench set-config -g redis_cache "redis://redis:6379"; bench set-config -g redis_queue "redis://redis:6379"; bench set-config -g redis_socketio "redis://redis:6379"; bench set-config -gp socketio_port 9000; bench set-config -g ai_tutor_api_url "${AI_TUTOR_API_URL}"; environment: DB_HOST: mariadb DB_PORT: 3306 REDIS_CACHE: redis:6379 REDIS_QUEUE: redis:6379 SOCKETIO_PORT: 9000 AI_TUTOR_API_URL: ${AI_TUTOR_API_URL:-http://langchain-service:8000} depends_on: - mariadb - redis restart: on-failure backend: <<: *backend_defaults platform: linux/amd64 environment: - LANGCHAIN_SERVICE_URL=http://langchain-service:8000 - AI_TUTOR_API_URL=${AI_TUTOR_API_URL:-http://langchain-service:8000} depends_on: - mariadb - redis - langchain-service frontend: <<: *customizable_image platform: linux/amd64 command: - nginx-entrypoint.sh ports: - "80:8080" - "443:443" environment: BACKEND: backend:8000 SOCKETIO: websocket:9000 FRAPPE_SITE_NAME_HEADER: ${FRAPPE_SITE_NAME_HEADER:-$$host} UPSTREAM_REAL_IP_ADDRESS: ${UPSTREAM_REAL_IP_ADDRESS:-127.0.0.1} UPSTREAM_REAL_IP_HEADER: ${UPSTREAM_REAL_IP_HEADER:-X-Forwarded-For} UPSTREAM_REAL_IP_RECURSIVE: ${UPSTREAM_REAL_IP_RECURSIVE:-off} PROXY_READ_TIMEOUT: ${PROXY_READ_TIMEOUT:-120} CLIENT_MAX_BODY_SIZE: ${CLIENT_MAX_BODY_SIZE:-50m} volumes: - sites:/home/frappe/frappe-bench/sites networks: - frappe-network depends_on: - backend - websocket restart: unless-stopped websocket: <<: [ *depends_on_configurator, *customizable_image ] platform: linux/amd64 command: - node - /home/frappe/frappe-bench/apps/frappe/socketio.js volumes: - sites:/home/frappe/frappe-bench/sites networks: - frappe-network queue-short: <<: *backend_defaults platform: linux/amd64 command: bench worker --queue short,default queue-long: <<: *backend_defaults platform: linux/amd64 command: bench worker --queue long,default,short scheduler: <<: *backend_defaults platform: linux/amd64 command: bench schedule # Volumes for persistent data volumes: sites: mariadb-data: postgres-data: # Networks for service communication networks: frappe-network: driver: bridge langchain-network: driver: bridge