# FFOA 统一 Docker Compose 配置
# 支持多环境：development (30XX), uat (70XX), production (60XX)
#
# 环境变量通过 .env 文件自动加载
# 详见: docs/setup/02-dev-environment.md
#
# 使用方法：
#   开发环境: bash scripts/deploy/deploy-unified.sh dev up
#   UAT环境:   bash scripts/deploy/deploy-unified.sh uat up
#   生产环境:  bash scripts/deploy/deploy-unified.sh production up

services:
  # ============================================
  # PostgreSQL 数据库（核心服务）
  # ============================================
  postgres:
    image: postgres:16-alpine
    container_name: ${CONTAINER_PREFIX}-postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      PGDATA: /var/lib/postgresql/data/pgdata
    ports:
      - "${POSTGRES_PORT}:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - core

  # ============================================
  # Redis 缓存（核心服务）
  # ============================================
  redis:
    image: redis:7.4-alpine
    container_name: ${CONTAINER_PREFIX}-redis
    restart: unless-stopped
    command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
    ports:
      - "${REDIS_PORT}:6379"
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - core

  # ============================================
  # Redis Commander - Redis 管理界面（开发工具）
  # ============================================
  redis-commander:
    image: rediscommander/redis-commander:latest
    container_name: ${CONTAINER_PREFIX}-redis-commander
    restart: unless-stopped
    depends_on:
      - redis
    environment:
      - REDIS_HOSTS=local:redis:6379:0:${REDIS_PASSWORD}
    ports:
      - "${REDIS_COMMANDER_PORT}:8081"
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "5m"
        max-file: "2"
    profiles:
      - tools

  # ============================================
  # Temporal Server 
  # ============================================
  temporal:
    image: temporalio/auto-setup:1.25.2
    container_name: ${CONTAINER_PREFIX}-temporal
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      - DB=postgres12
      - DB_PORT=5432
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PWD=${POSTGRES_PASSWORD}
      - POSTGRES_SEEDS=postgres
    ports:
      - "${TEMPORAL_GRPC_PORT}:7233"  # gRPC
      - "${TEMPORAL_HTTP_PORT}:8233"  # HTTP API
    # 验"业务可用"而非"端口活着"：能 list namespace = auto-setup 完成 + Temporal frontend OK
    # 详见 docs/standards/12-five-meta-rules.md 规则 5
    healthcheck:
      test: ["CMD-SHELL", "temporal operator namespace list >/dev/null 2>&1 || exit 1"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 60s   # auto-setup 首启含 schema 创建 + namespace 注册，60s 给足余量
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - temporal

  # ============================================
  # Temporal UI - 工作流管理界面
  # ============================================
  temporal-ui:
    image: temporalio/ui:2.44.0
    container_name: ${CONTAINER_PREFIX}-temporal-ui
    restart: unless-stopped
    depends_on:
      - temporal
    environment:
      - TEMPORAL_ADDRESS=temporal:7233
      - TEMPORAL_CORS_ORIGINS=${CORS_ORIGIN:-http://localhost:3000}
    ports:
      - "${TEMPORAL_UI_PORT}:8080"
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - temporal

  # ============================================
  # MinIO - 对象存储
  # ============================================
  minio:
    image: minio/minio:RELEASE.2024-09-13T20-26-02Z
    container_name: ${CONTAINER_PREFIX}-minio
    restart: unless-stopped
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: ${MINIO_ROOT_USER}
      MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
    ports:
      - "${MINIO_API_PORT}:9000"      # API
      - "${MINIO_CONSOLE_PORT}:9001"  # Console
    volumes:
      - minio_data:/data
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - storage

  # ============================================
  # RAGFlow - 知识库检索与问答引擎
  # ============================================
  ragflow:
    image: ${RAGFLOW_IMAGE:-infiniflow/ragflow:v0.23.1}
    container_name: ${CONTAINER_PREFIX}-ragflow
    restart: unless-stopped
    depends_on:
      ragflow-mysql:
        condition: service_healthy
      ragflow-es:
        condition: service_healthy
      ragflow-minio:
        condition: service_healthy
      ragflow-redis:
        condition: service_healthy
    command:
      - --enable-adminserver
    environment:
      DOC_ENGINE: ${RAGFLOW_DOC_ENGINE:-elasticsearch}
      DEVICE: ${RAGFLOW_DEVICE:-cpu}
      MAX_CONTENT_LENGTH: ${RAGFLOW_MAX_CONTENT_LENGTH:-134217728}
    ports:
      - "${RAGFLOW_WEB_HTTP_PORT:-3095}:80"
      - "${RAGFLOW_WEB_HTTPS_PORT:-3443}:443"
      - "${RAGFLOW_HTTP_PORT:-3098}:9380"
      - "${RAGFLOW_ADMIN_HTTP_PORT:-3099}:9381"
    volumes:
      - ./ragflow/ragflow-logs:/ragflow/logs
      - ./ragflow/nginx/ragflow.conf:/etc/nginx/conf.d/ragflow.conf
      - ./ragflow/nginx/proxy.conf:/etc/nginx/conf.d/proxy.conf
      - ./ragflow/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./ragflow/service_conf.yaml.template:/ragflow/conf/service_conf.yaml.template
      - ./ragflow/entrypoint.sh:/ragflow/entrypoint.sh
      - ./ragflow/overrides/picture.py:/ragflow/rag/app/picture.py
    env_file: ${ENV_FILE_PATH:-.env}
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - knowledge-tei

  ragflow-mysql:
    image: mysql:8.0.39
    container_name: ${CONTAINER_PREFIX}-ragflow-mysql
    restart: unless-stopped
    command:
      --max_connections=1000
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
      --default-authentication-plugin=mysql_native_password
      --tls_version="TLSv1.2,TLSv1.3"
      --init-file /data/application/init.sql
      --binlog_expire_logs_seconds=604800
    environment:
      MYSQL_ROOT_PASSWORD: ${RAGFLOW_MYSQL_PASSWORD:-infini_rag_flow}
    ports:
      - "${RAGFLOW_MYSQL_HOST_PORT:-3092}:3306"
    volumes:
      - ragflow_mysql_data:/var/lib/mysql
      - ./ragflow/init.sql:/data/application/init.sql
    env_file: ${ENV_FILE_PATH:-.env}
    healthcheck:
      test: ["CMD", "mysqladmin" ,"ping", "-uroot", "-p${RAGFLOW_MYSQL_PASSWORD:-infini_rag_flow}"]
      interval: 10s
      timeout: 10s
      retries: 120
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - knowledge

  ragflow-minio:
    image: quay.io/minio/minio:RELEASE.2025-06-13T11-33-47Z
    container_name: ${CONTAINER_PREFIX}-ragflow-minio
    restart: unless-stopped
    command: ["server", "--console-address", ":9001", "/data"]
    environment:
      MINIO_ROOT_USER: ${RAGFLOW_MINIO_USER:-rag_flow}
      MINIO_ROOT_PASSWORD: ${RAGFLOW_MINIO_PASSWORD:-infini_rag_flow}
    ports:
      - "${RAGFLOW_MINIO_PORT:-3093}:9000"
      - "${RAGFLOW_MINIO_CONSOLE_PORT:-3094}:9001"
    volumes:
      - ragflow_minio_data:/data
    env_file: ${ENV_FILE_PATH:-.env}
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - knowledge

  ragflow-redis:
    image: valkey/valkey:8
    container_name: ${CONTAINER_PREFIX}-ragflow-redis
    restart: unless-stopped
    command: ["redis-server", "--requirepass", "${RAGFLOW_REDIS_PASSWORD:-infini_rag_flow}", "--maxmemory", "128mb", "--maxmemory-policy", "allkeys-lru"]
    ports:
      - "${RAGFLOW_REDIS_PORT:-3097}:6379"
    volumes:
      - ragflow_redis_data:/data
    env_file: ${ENV_FILE_PATH:-.env}
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${RAGFLOW_REDIS_PASSWORD:-infini_rag_flow}", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - knowledge

  ragflow-tei:
    image: ${TEI_IMAGE_CPU:-ghcr.io/huggingface/text-embeddings-inference:cpu-1.5}
    container_name: ${CONTAINER_PREFIX}-ragflow-tei
    restart: unless-stopped
    command: ["--model-id", "${TEI_MODEL:-/data/models/bge-m3}", "--auto-truncate"]
    ports:
      - "${TEI_PORT:-3088}:80"
    volumes:
      - ragflow_tei_data:/data
    env_file: ${ENV_FILE_PATH:-.env}
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - knowledge

  ragflow-es:
    image: elasticsearch:${RAGFLOW_ES_STACK_VERSION:-8.11.3}
    container_name: ${CONTAINER_PREFIX}-ragflow-es
    restart: unless-stopped
    ports:
      - "${RAGFLOW_ES_PORT:-3096}:9200"
    env_file: ${ENV_FILE_PATH:-.env}
    environment:
      - node.name=ragflow-es01
      - ELASTIC_PASSWORD=${RAGFLOW_ELASTIC_PASSWORD:-infini_rag_flow}
      - bootstrap.memory_lock=false
      - discovery.type=single-node
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=false
      - xpack.security.transport.ssl.enabled=false
      - ES_JAVA_OPTS=${RAGFLOW_ES_JAVA_OPTS:--Xms1g -Xmx1g}
      - cluster.routing.allocation.disk.watermark.low=5gb
      - cluster.routing.allocation.disk.watermark.high=3gb
      - cluster.routing.allocation.disk.watermark.flood_stage=2gb
    mem_limit: ${RAGFLOW_MEM_LIMIT:-4g}
    ulimits:
      memlock:
        soft: -1
        hard: -1
    healthcheck:
      test: ["CMD-SHELL", "curl http://localhost:9200"]
      interval: 10s
      timeout: 10s
      retries: 120
    networks:
      - ffoa-network
    volumes:
      - ragflow_es_data:/usr/share/elasticsearch/data
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - knowledge

  # ============================================
  # Prometheus - 监控数据收集
  # ============================================
  prometheus:
    image: prom/prometheus:v2.54.1
    container_name: ${CONTAINER_PREFIX}-prometheus
    restart: unless-stopped
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/usr/share/prometheus/console_libraries'
      - '--web.console.templates=/usr/share/prometheus/consoles'
    ports:
      - "${PROMETHEUS_PORT}:9090"
    volumes:
      - ./monitoring/prometheus-config.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - monitoring

  # ============================================
  # Grafana - 监控数据可视化
  # ============================================
  grafana:
    image: grafana/grafana:11.3.0
    container_name: ${CONTAINER_PREFIX}-grafana
    restart: unless-stopped
    depends_on:
      - prometheus
    environment:
      - GF_SECURITY_ADMIN_USER=${GRAFANA_USER:-admin}
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
      - GF_INSTALL_PLUGINS=
    ports:
      - "${GRAFANA_PORT}:3000"
    volumes:
      - grafana_data:/var/lib/grafana
      - ./monitoring/grafana/dashboards:/etc/grafana/provisioning/dashboards
      - ./monitoring/grafana/datasources:/etc/grafana/provisioning/datasources
    networks:
      - ffoa-network
    logging:
      driver: "json-file"
      options:
        max-size: "${LOG_MAX_SIZE:-10m}"
        max-file: "${LOG_MAX_FILE:-3}"
    profiles:
      - monitoring

# ============================================
# 数据卷定义
# ============================================
volumes:
  postgres_data:
    name: ${CONTAINER_PREFIX}_postgres_data
    driver: local
  redis_data:
    name: ${CONTAINER_PREFIX}_redis_data
    driver: local
  minio_data:
    name: ${CONTAINER_PREFIX}_minio_data
    driver: local
  prometheus_data:
    name: ${CONTAINER_PREFIX}_prometheus_data
    driver: local
  grafana_data:
    name: ${CONTAINER_PREFIX}_grafana_data
    driver: local
  ragflow_mysql_data:
    name: ${CONTAINER_PREFIX}_ragflow_mysql_data
    driver: local
  ragflow_minio_data:
    name: ${CONTAINER_PREFIX}_ragflow_minio_data
    driver: local
  ragflow_redis_data:
    name: ${CONTAINER_PREFIX}_ragflow_redis_data
    driver: local
  ragflow_es_data:
    name: ${CONTAINER_PREFIX}_ragflow_es_data
  ragflow_tei_data:
    name: ${CONTAINER_PREFIX}_ragflow_tei_data
    driver: local

# ============================================
# 网络定义
# ============================================
networks:
  ffoa-network:
    name: ${CONTAINER_PREFIX}-network
    driver: bridge

# ============================================
# 环境配置说明
# ============================================
#
# 本文件通过环境变量支持多个部署环境，无需维护多个配置文件。
#
# 环境变量策略：
#   - 端口配置：必须由脚本提供，无默认值（确保多环境隔离）
#   - 镜像版本：有默认值兜底（确保可用性）
#   - 其他配置：根据重要性选择
#
# 必需的环境变量（在 .env 文件中配置）：
#
#   CONTAINER_PREFIX       容器名前缀（ffoa-dev, ffws-uat, ffoa）
#   POSTGRES_DB           数据库名称
#   POSTGRES_USER         数据库用户名
#   POSTGRES_PASSWORD     数据库密码
#   POSTGRES_PORT         PostgreSQL 外部端口
#   REDIS_PASSWORD        Redis 密码
#   REDIS_PORT            Redis 外部端口
#   MINIO_ROOT_USER       MinIO 用户名
#   MINIO_ROOT_PASSWORD   MinIO 密码
#   TEMPORAL_GRPC_PORT    Temporal gRPC 端口（必需）
#   TEMPORAL_HTTP_PORT    Temporal HTTP 端口（必需）
#   TEMPORAL_UI_PORT      Temporal UI 端口（必需）
#   MINIO_API_PORT        MinIO API 端口（必需）
#   MINIO_CONSOLE_PORT    MinIO Console 端口（必需）
#   PROMETHEUS_PORT       Prometheus 端口（必需）
#   GRAFANA_PORT          Grafana 端口（必需）
#   REDIS_COMMANDER_PORT  Redis Commander 端口（必需）
#   GRAFANA_PASSWORD      Grafana 管理员密码（必需）
#
# Knowledge (RAGFlow) profile 必需变量：
#
#   RAGFLOW_IMAGE             RAGFlow 镜像版本
#   RAGFLOW_WEB_HTTP_PORT     RAGFlow Web HTTP 端口
#   RAGFLOW_WEB_HTTPS_PORT    RAGFlow Web HTTPS 端口
#   RAGFLOW_HTTP_PORT         RAGFlow API 端口 (9380)
#   RAGFLOW_ADMIN_HTTP_PORT   RAGFlow Admin 端口 (9381)
#   RAGFLOW_MYSQL_PASSWORD    RAGFlow MySQL Root 密码
#   RAGFLOW_MYSQL_PORT        RAGFlow MySQL 容器端口 (默认: 3306)
#   RAGFLOW_MYSQL_HOST_PORT   RAGFlow MySQL 映射到宿主机的端口
#   RAGFLOW_MINIO_USER        RAGFlow MinIO 用户名
#   RAGFLOW_MINIO_PASSWORD    RAGFlow MinIO 密码
#   RAGFLOW_MINIO_PORT        RAGFlow MinIO API 端口
#   RAGFLOW_MINIO_CONSOLE_PORT RAGFlow MinIO Console 端口
#   RAGFLOW_REDIS_PASSWORD    RAGFlow Redis 密码
#   RAGFLOW_REDIS_PORT        RAGFlow Redis 端口
#   RAGFLOW_ES_PORT           RAGFlow Elasticsearch 端口
#   RAGFLOW_ELASTIC_PASSWORD  RAGFlow Elasticsearch 密码
#   RAGFLOW_ES_STACK_VERSION  RAGFlow Elasticsearch 版本
#   RAGFLOW_MEM_LIMIT         RAGFlow Elasticsearch 内存限制
#   TEI_IMAGE_CPU             Text Embeddings Inference 镜像
#   TEI_MODEL                 Text Embeddings Inference 模型
#   TEI_PORT                  Text Embeddings Inference 对外端口
#   RAGFLOW_TEI_HOST          RAGFlow 指向 TEI 的主机名
#
# 可选的环境变量（有默认值）：
#
#   LOG_MAX_SIZE          日志文件最大大小（默认: 10m）
#   LOG_MAX_FILE          保留日志文件数量（默认: 3）
#   GRAFANA_USER          Grafana 管理员用户名（默认: admin）
#
# ============================================
# 端口映射参考
# ============================================
#
# 开发环境 (30XX)：
#   PostgreSQL:         3002
#   Redis:              3003
#   Temporal gRPC:      3033
#   Temporal HTTP:      3034
#   Temporal UI:        3080
#   MinIO API:          3090
#   MinIO Console:      3091
#   RAGFlow Web HTTP:   3095
#   RAGFlow Web HTTPS:  3443
#   RAGFlow API:        3098
#   RAGFlow Admin:      3099
#   RAGFlow MySQL:      3092
#   RAGFlow TEI:        30911
#   RAGFlow MySQL:      3092
#   RAGFlow MinIO API:  3093
#   RAGFlow MinIO Console: 3094
#   RAGFlow Redis:      3097
#   RAGFlow ES:         3096
#
# 生产环境 (60XX)：
#   PostgreSQL:         6002
#   Redis:              6003
#   Temporal gRPC:      6033
#   Temporal HTTP:      6034
#   Temporal UI:        6080
#   Redis Commander:    6081
#   MinIO API:          6090
#   MinIO Console:      6091
#   RAGFlow Web HTTP:   6095
#   RAGFlow Web HTTPS:  6443
#   RAGFlow API:        6098
#   RAGFlow Admin:      6099
#   RAGFlow MySQL:      6092
#   RAGFlow MinIO API:  6093
#   RAGFlow MinIO Console: 6094
#   RAGFlow Redis:      6097
#   RAGFlow ES:         6096
#   Prometheus:         6009
#   Grafana:            6012
#
#   注: Frontend (6064) 和 Backend (6001) 由 PM2 管理，不在 Docker 中
#   注: 6000-6063 为 X11 保留端口，避免使用
#
# UAT 环境 (70XX)：
#   PostgreSQL:         7002
#   Redis:              7003
#   Temporal gRPC:      7033
#   Temporal HTTP:      7034
#   Temporal UI:        7080
#   MinIO API:          7090
#   MinIO Console:      7091
#   RAGFlow Web HTTP:   7095
#   RAGFlow Web HTTPS:  7443
#   RAGFlow API:        7098
#   RAGFlow Admin:      7099
#   RAGFlow MySQL:      7092
#   RAGFlow MinIO API:  7093
#   RAGFlow MinIO Console: 7094
#   RAGFlow Redis:      7097
#   RAGFlow ES:         7096
#
# ============================================
# Profile 说明
# ============================================
#
# --profile core       核心服务（PostgreSQL + Redis）
# --profile temporal   包含 Temporal 工作流引擎
# --profile storage    包含 MinIO 对象存储
# --profile tools      包含开发工具（Redis Commander）
# --profile monitoring 包含监控（Prometheus + Grafana）
# --profile knowledge  包含 RAGFlow 知识库引擎
#
# 使用示例：
#
#   # 仅核心服务
#   docker compose -f docker/docker-compose.yml --profile core up -d
#
#   # 包含 Temporal 和 MinIO
#   docker compose -f docker/docker-compose.yml --profile core --profile temporal --profile storage up -d
#
#   # 自定义 profile 组合
#   docker compose -f docker/docker-compose.yml \
#     --profile core --profile temporal --profile storage up -d
#
