networks:
  frontend:
    name: cluster_frontend
  backend:
    name: cluster_backend
    driver: bridge
    ipam:
      config:
        - subnet: 172.28.0.0/24
  nextcloud-net:
    name: nextcloud_internal
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/24

volumes:
  openwebui_data:
    external: true
    name: openwebui_open-webui
  openwebui_ollama_data:
    external: true
    name: openwebui_ollama
  immich_model_cache:
    external: true
    name: immich_model-cache
  uptimekuma_data:
    external: true
    name: uptimekuma_uptime-kuma
  map-osrm-data:
    external: true
    name: osm-stack_osrm-data
  map-nominatim-data:
    external: true
    name: osm-stack_nominatim-data
  map-nominatim-pbf:
    external: true
    name: osm-stack_nominatim-pbf
  map-osm-db:
    external: true
    name: osm-stack_osm-db
  map-osm-tiles:
    external: true
    name: osm-stack_osm-tiles
  paperless-ai-data:
    name: paperless-ai-data 
    external: true
  nextcloud_db:
    external: true
    name: ncdb
  nextcloud_redis:
    name: ncredis
    external: true
  nextcloud_elasticsearch:  
    name: ncsearch
    external: true
  nc_data:
  nc_config:
  nc_custom_apps:
  nc_themes:
  janus_log:

services:
 # ===========================================================================
 # NEXTCLOUD SERVICE GROUP
 # ===========================================================================

  nc_db:
    image: mariadb:11.4
    container_name: nc_db
    restart: unless-stopped
    networks:
      nextcloud-net:
        ipv4_address: 172.20.0.40
    volumes:
      - nextcloud_db:/var/lib/mysql
      - ${PROJECT_ROOT:-.}/nextcloud/config/mariadb/nextcloud.cnf:/etc/mysql/conf.d/nextcloud.cnf:ro
    environment:
      MYSQL_ROOT_PASSWORD: ${NEXTCLOUD_DB_ROOT_PASSWORD}
      MYSQL_DATABASE:      ${NEXTCLOUD_DB_NAME}
      MYSQL_USER:          ${NEXTCLOUD_DB_USER}
      MYSQL_PASSWORD:      ${NEXTCLOUD_DB_PASSWORD}
    command: >
      --transaction-isolation=READ-COMMITTED
      --log-bin=binlog
      --binlog-format=ROW
      --innodb-file-per-table=1
      --skip-innodb-read-only-compressed
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  nc_redis:
    image: redis:7.4-alpine
    container_name: nc_redis
    restart: unless-stopped
    networks:
      nextcloud-net:
        ipv4_address: 172.20.0.41
    volumes:
      - nextcloud_redis:/data
      - ${PROJECT_ROOT:-.}/nextcloud/config/redis/redis.conf:/usr/local/etc/redis/redis.conf:ro
    command: redis-server /usr/local/etc/redis/redis.conf
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 3s
      retries: 5

  nextcloud:
    build:
      context: ${PROJECT_ROOT:-.}/nextcloud/build/nextcloud
      dockerfile: Dockerfile
      args:
        NC_VERSION: ${NC_VERSION:-33.0.2}
    image: nextcloud-custom:${NC_VERSION:-33.0.2}
    container_name: nextcloud
    restart: unless-stopped
    networks:
      nextcloud-net:
        ipv4_address: 172.20.0.42
      frontend: {}
    depends_on:
      nc_db:
        condition: service_healthy
      nc_redis:
        condition: service_healthy
    volumes:
      - ${PROJECT_ROOT:-.}/nextcloud/data:/var/www/html/data
      - ${PROJECT_ROOT:-.}/nextcloud/webroot/config:/var/www/html/config
      - ${PROJECT_ROOT:-.}/nextcloud/webroot/custom_apps:/var/www/html/custom_apps
      - ${PROJECT_ROOT:-.}/nextcloud/webroot/themes:/var/www/html/themes
    environment:
      NEXTCLOUD_DB_TYPE:        mysql
      NEXTCLOUD_DB_HOST:        172.20.0.40
      NEXTCLOUD_DB_NAME:        ${NEXTCLOUD_DB_NAME}
      NEXTCLOUD_DB_USER:        ${NEXTCLOUD_DB_USER}
      NEXTCLOUD_DB_PASSWORD:    ${NEXTCLOUD_DB_PASSWORD}
      NEXTCLOUD_ADMIN_USER:     ${NC_ADMIN_USER:-admin}
      NEXTCLOUD_ADMIN_PASSWORD: ${NC_ADMIN_PASSWORD}
      NEXTCLOUD_TRUSTED_DOMAINS: ${NEXTCLOUD_DOMAIN} localhost
      NC_DOMAIN:                ${NEXTCLOUD_DOMAIN}
      TRUSTED_PROXIES:          172.20.0.0/24 172.28.0.0/24 127.0.0.1
      REDIS_HOST:               172.20.0.41
      REDIS_PORT:               6379
      REDIS_PASSWORD:           ${REDIS_PASSWORD:-}
      PHP_MEMORY_LIMIT:         ${PHP_MEMORY_LIMIT:-4G}
      PHP_UPLOAD_LIMIT:         ${PHP_UPLOAD_LIMIT:-10G}
      MAIL_FROM_ADDRESS:        ${MAIL_FROM:-nextcloud}
      MAIL_DOMAIN:              ${MAIL_DOMAIN:-example.com}
      SMTP_HOST:                ${SMTP_HOST:-}
      SMTP_PORT:                ${SMTP_PORT:-587}
      SMTP_AUTHTYPE:            ${SMTP_AUTHTYPE:-LOGIN}
      SMTP_NAME:                ${SMTP_USER:-}
      SMTP_PASSWORD:            ${SMTP_PASSWORD:-}
      SMTP_SECURE:              ${SMTP_SECURE:-tls}
      NC_TALK_SIGNALING_SECRET: ${NEXTCLOUD_SIGNALING_SECRET}
      NC_TALK_TURN_SECRET:      ${TALK_TURN_SECRET}
      NC_TALK_TURN_SERVER:      turn:${NEXTCLOUD_DOMAIN}:3478
      NC_TALK_TURN_PROTOCOLS:   udp,tcp
      NC_DEFAULT_PHONE_REGION:  US
      OVERWRITEPROTOCOL:        https
      OVERWRITEHOST:            ${NEXTCLOUD_DOMAIN}
    extra_hosts:
      - "${NEXTCLOUD_DOMAIN}:172.20.0.42"
      - "nc_collabora:172.20.0.10"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/status.php"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 60s

  nc_cron:
    image: nextcloud-custom:${NC_VERSION:-33.0.2}
    container_name: nc_cron
    restart: unless-stopped
    networks:
      - nextcloud-net
    depends_on:
      nextcloud:
        condition: service_healthy
    volumes:
      - ${PROJECT_ROOT:-.}/nextcloud/data:/var/www/html/data
      - ${PROJECT_ROOT:-.}/nextcloud/webroot/config:/var/www/html/config
      - ${PROJECT_ROOT:-.}/nextcloud/webroot/custom_apps:/var/www/html/custom_apps
      - ${PROJECT_ROOT:-.}/nextcloud/webroot/themes:/var/www/html/themes
    environment:
      NEXTCLOUD_DB_TYPE:     mysql
      NEXTCLOUD_DB_HOST:     172.20.0.40
      NEXTCLOUD_DB_NAME:     ${NEXTCLOUD_DB_NAME}
      NEXTCLOUD_DB_USER:     ${NEXTCLOUD_DB_USER}
      NEXTCLOUD_DB_PASSWORD: ${NEXTCLOUD_DB_PASSWORD}
      REDIS_HOST:            172.20.0.41
      REDIS_PORT:            6379
      REDIS_PASSWORD:        ${REDIS_PASSWORD:-}
      SHELL:                 /bin/sh
    command: ["/usr/local/bin/supercrond", "/etc/cron.d/nextcloud"]

  nc_collabora:
    image: collabora/code:latest
    container_name: nc_collabora
    restart: unless-stopped
    privileged: true
    networks:
      nextcloud-net:
        ipv4_address: 172.20.0.10
      frontend: {}
    environment:
      - "aliasgroup1=https://${NEXTCLOUD_DOMAIN}"
      - "aliasgroup2=http://172.20.0.42"
      - "server_name=office.${BASE_DOMAIN:-example.com}"
      - "DONT_GEN_SSL_CERT=YES"
      - "termination=true"
      - "ssl_verify=false"
      - "extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:ssl.verify=false --o:net.proto=IPv4 --o:logging.level=warning --o:security.seccomp=false --o:storage.wopi.host[0]=172.20.0.42 --o:storage.wopi.host[1]=${NEXTCLOUD_DOMAIN}"
    extra_hosts:
      - "${NEXTCLOUD_DOMAIN}:172.20.0.42"
      - "office.${BASE_DOMAIN:-example.com}:172.20.0.10"
    dns:
      - 1.1.1.1
      - 8.8.8.8
    cap_add:
      - MKNOD
      - SYS_ADMIN
    security_opt:
      - apparmor:unconfined

  nc_coturn:
    image: coturn/coturn:latest
    container_name: nc_coturn
    restart: unless-stopped
    network_mode: host
    volumes:
      - ${PROJECT_ROOT:-.}/nextcloud/config/coturn/turnserver.conf:/etc/coturn/turnserver.conf:ro
    environment:
      TURN_SECRET: ${TALK_TURN_SECRET}
    command: -c /etc/coturn/turnserver.conf

  nc_janus:
    image: canyan/janus-gateway:latest
    container_name: nc_janus
    restart: unless-stopped
    networks:
      nextcloud-net:
        ipv4_address: 172.20.0.19
    ports:
      - "30000-30100:30000-30100/udp"
    volumes:
      - ${PROJECT_ROOT:-.}/nextcloud/config/janus/janus.jcfg:/usr/local/etc/janus/janus.jcfg:ro
      - ${PROJECT_ROOT:-.}/nextcloud/config/janus/janus.transport.http.jcfg:/usr/local/etc/janus/janus.transport.http.jcfg:ro
      - ${PROJECT_ROOT:-.}/nextcloud/config/janus/janus.transport.websockets.jcfg:/usr/local/etc/janus/janus.transport.websockets.jcfg:ro
      - ${PROJECT_ROOT:-.}/nextcloud/config/janus/janus.plugin.videoroom.jcfg:/usr/local/etc/janus/janus.plugin.videoroom.jcfg:ro
      - janus_log:/var/log/janus
    environment:
      JANUS_ADMIN_SECRET: ${JANUS_ADMIN_SECRET}
    healthcheck:
      test: ["CMD", "sh", "-c", "kill -0 1"]
      interval: 20s
      timeout: 5s
      retries: 3
      start_period: 15s

  nc_nats:
    image: nats:2.14-alpine
    container_name: nc_nats
    restart: unless-stopped
    networks:
      - nextcloud-net

  nextcloud-talk-signaling:
    image: strukturag/nextcloud-spreed-signaling:latest
    container_name: nextcloud-talk-signaling
    restart: unless-stopped
    networks:
      - nextcloud-net
      - frontend
    ports:
      - "8090:8088"
    volumes:
      - ${PROJECT_ROOT:-.}/nextcloud/config/signaling/server.conf:/config/server.conf:ro
    environment:
      CONFIG:                   /config/server.conf
      NC_TALK_SIGNALING_SECRET: ${NEXTCLOUD_SIGNALING_SECRET}
      JANUS_ADMIN_SECRET:       ${JANUS_ADMIN_SECRET}
    depends_on:
      - nc_redis
      - nc_janus
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:8088/api/v1/welcome"]
      interval: 30s
      timeout: 5s
      retries: 5

  nextcloud-push:
    image: icewind1991/notify_push:latest
    container_name: nextcloud-push
    restart: unless-stopped
    environment:
      - NEXTCLOUD_URL=https://${NEXTCLOUD_DOMAIN}
      - DATABASE_URL=mysql://${NEXTCLOUD_DB_USER}:${NEXTCLOUD_DB_PASSWORD}@172.20.0.40:3306/${NEXTCLOUD_DB_NAME}
      - DATABASE_PREFIX=oc_
      - REDIS_URL=redis://172.20.0.41:6379
      - PORT=7867
    networks:
      - nextcloud-net
    depends_on:
      nc_db:
        condition: service_healthy
      nc_redis:
        condition: service_healthy

  nextcloud-imaginary:
    image: h2non/imaginary:latest
    container_name: nextcloud-imaginary
    restart: unless-stopped
    command: -p 9000
    networks:
      - nextcloud-net

  nextcloud-search:
    image: elasticsearch:8.17.0
    container_name: nextcloud-search
    user: "1000:1000"
    restart: unless-stopped
    environment:
      - discovery.type=single-node
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
      - xpack.security.enabled=false
    volumes:
      - nextcloud_elasticsearch:/usr/share/elasticsearch/data
    networks:
      - nextcloud-net

  nextcloud-clamav:
    image: clamav/clamav:latest
    container_name: nextcloud-clamav
    restart: unless-stopped
    networks:
      nextcloud-net:
        ipv4_address: 172.20.0.30

  nextcloud-appapi-harp:
    image: ghcr.io/nextcloud/nextcloud-appapi-harp:latest
    container_name: nextcloud-appapi-harp
    restart: unless-stopped
    environment:
      - HP_SHARED_KEY=${HARP_SHARED_KEY:-change_me}
      - NC_INSTANCE_URL=https://${NEXTCLOUD_DOMAIN}
      - HP_FOR_NEXTCLOUD_URL=http://nextcloud:80
      - HP_NEXTCLOUD_HOST=nextcloud
      - HP_CERT_PATH_ON_HOST=${PROJECT_ROOT:-.}/harp-certs
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ${PROJECT_ROOT:-.}/harp-certs:/certs
    networks:
      nextcloud-net:
        ipv4_address: 172.20.0.8
      frontend: {}
    extra_hosts:
      - "${NEXTCLOUD_DOMAIN}:172.20.0.42"
    dns:
      - 1.1.1.1
      - 8.8.8.8

  # --------------------------
  # Home Automation Stack
  # --------------------------
  homeassistant:
    image: ghcr.io/home-assistant/home-assistant:stable
    container_name: homeassistant
    restart: unless-stopped
    network_mode: host
    privileged: true
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ${PROJECT_ROOT:-.}/homeassistant/config:/config
      - ${PROJECT_ROOT:-.}/ha_dns.conf:/etc/resolv.conf:ro
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8123"]
      interval: 30s
      timeout: 10s
      retries: 3

  wyze-bridge:
    image: mrlt8/wyze-bridge:latest
    container_name: wyze-bridge
    restart: unless-stopped
    ports:
      - "8554:8554"
      - "8888:8888"
    environment:
      - WYZE_EMAIL=${WYZE_EMAIL}
      - WYZE_PASSWORD=${WYZE_PASSWORD}
      - API_KEY=${WYZE_API_KEY}
    volumes:
      - ${PROJECT_ROOT:-.}/homeassistant/wyze:/config
    networks:
      - backend
      - frontend

  esphome:
    image: ghcr.io/esphome/esphome:latest
    container_name: esphome
    restart: unless-stopped
    ports:
      - "6052:6052"
    privileged: true
    volumes:
      - ${PROJECT_ROOT:-.}/homeassistant/esphome:/config
    networks:
      - backend
      
  # --------------------------
  # Productivity & Knowledge
  # --------------------------
  homebox:
    image: sysadminsmedia/homebox:latest
    container_name: homebox
    restart: unless-stopped
    ports:
      - "3100:7745"
    volumes:
      - ${PROJECT_ROOT:-.}/homebox/data:/data
    networks:
      - frontend
      - backend

  kiwix:
    image: ghcr.io/kiwix/kiwix-serve:latest
    container_name: kiwix
    restart: unless-stopped
    ports:
      - "8085:8080"
    volumes:
      - ${PROJECT_ROOT:-.}/kiwix/zims:/data:ro
    command:
      - /data/ifixit_en_all_2025-06.zim
      - /data/wikipedia_en_all_maxi_2025-08.zim
    networks:
      - frontend
      - backend

  n8n:
    image: n8nio/n8n:latest
    container_name: n8n
    restart: unless-stopped
    user: "${PUID}:${PGID}"
    ports:
      - "5678:5678"
    environment:
      - N8N_HOST=n8n.${BASE_DOMAIN}
      - N8N_PORT=5678
      - N8N_PROTOCOL=http
      - NODE_ENV=production
      - N8N_SECURE_COOKIE=false
      - WEBHOOK_URL=https://n8n.${BASE_DOMAIN}/
      - GENERIC_TIMEZONE=${TZ}
      - HOME=/n8n_data
      - N8N_USER_FOLDER=/n8n_data
    volumes:
      - ${PROJECT_ROOT:-.}/n8n_data:/n8n_data
    networks:
      - frontend
      - backend

  obsidian:
    image: lscr.io/linuxserver/obsidian:latest
    container_name: obsidian
    restart: unless-stopped
    ports:
      - "3030:3000" 
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
      - PORT=3000 
    volumes:
      - ${PROJECT_ROOT:-.}/obsidian/config:/config
      - ${PROJECT_ROOT:-.}/obsidian/config/Notes:/vault
    networks:
      - frontend
      - backend

  obsidian-indexer:
    build: ${PROJECT_ROOT:-.}/obsidian-indexer
    container_name: obsidian-indexer
    restart: unless-stopped
    environment:
      - VAULT_PATH=/vault
      - MAILDIR_PATH=/maildir
      - QDRANT_URL=http://qdrant:6333
      - QDRANT_COLLECTION=obsidian_notes
      - QDRANT_API_KEY=${OBSIDIAN_INDEXER_QDRANT_API_KEY}
      - OLLAMA_BASE_URL=http://ollama:11434
      - EMBEDDING_MODEL=nomic-embed-text:latest
      - CHUNK_SIZE=1500
      - CHUNK_OVERLAP=200
    volumes:
      - ${PROJECT_ROOT:-.}/obsidian/config/Notes:/vault:ro
      - ${PROJECT_ROOT:-.}/maildir:/maildir:ro
    networks:
      - backend
    depends_on:
      - qdrant
      - ollama

  syncthing:
    image: lscr.io/linuxserver/syncthing:latest
    container_name: syncthing
    hostname: cluster-syncthing
    network_mode: host
    environment:
      - PUID=${PUID}
      - PGID=${PGID}
      - TZ=${TZ}
    volumes:
      - ${PROJECT_ROOT:-.}/syncthing/config:/config
      - ${PROJECT_ROOT:-.}/syncthing/data:/data
      - ${PROJECT_ROOT:-.}/paperless/consume:/data/paperless-consume
    restart: unless-stopped

  # --------------------------
  # AI Stack
  # --------------------------
  ollama:
    # [NVIDIA]
    image: ollama/ollama:latest
    # [/NVIDIA]
    # [AMD]
    # image: ollama/ollama:rocm
    # [/AMD]
    # [CPU]
    # image: ollama/ollama:latest
    # [/CPU]
    container_name: ollama
    restart: always
    # [NVIDIA]
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
    # [/NVIDIA]
    # [AMD]
    # devices:
    #   - /dev/kfd:/dev/kfd
    #   - /dev/dri:/dev/dri
    # [/AMD]
    volumes:
      - ${PROJECT_ROOT:-.}/ollama_data:/root/.ollama
    # [NVIDIA]
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    # [/NVIDIA]
    networks:
      - backend

  whisper:
    # [NVIDIA]
    image: ghcr.io/fedirz/faster-whisper-server:latest-cuda
    # [/NVIDIA]
    # [CPU]
    # image: ghcr.io/fedirz/faster-whisper-server:latest-cpu
    # [/CPU]
    container_name: whisper
    restart: always
    # [NVIDIA]
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
      - WHISPER_MODEL=base
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    # [/NVIDIA]
    networks:
      - backend

  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    container_name: open-webui
    # [NVIDIA]
    runtime: nvidia
    # [/NVIDIA]
    restart: always
    ports:
      - "3000:8080"
    volumes:
      - openwebui_data:/app/backend/data
      - ${PROJECT_ROOT:-.}/obsidian/config/Notes:/app/backend/data/docs/obsidian:ro
      - ${PROJECT_ROOT:-.}/openwebui/comfyui_data/output:/app/backend/data/docs/comfy_outputs:ro
      - ${PROJECT_ROOT:-.}/paperless/media/documents/archive:/app/backend/data/docs/paperless:ro
    environment:
      # [NVIDIA]
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=compute,utility
      # [/NVIDIA]
      - OLLAMA_BASE_URL=http://ollama:11434
      - OLLAMA_API_BASE_URL=http://ollama:11434/api
      - WEBUI_SECRET_KEY=${WEBUI_SECRET_KEY}
      - WEBUI_ADMIN_EMAIL=${WEBUI_ADMIN_EMAIL}
      - WEBUI_ADMIN_PASSWORD=${WEBUI_ADMIN_PASSWORD}
      - DATABASE_ENABLE_SESSION_SHARING=false
      - VECTOR_DB=qdrant
      - TEXT_SPLITTER=MarkdownHeaderTextSplitter
      - CHUNK_SIZE=1500
      - CHUNK_MIN_SIZE_TARGET=800
      - QDRANT_URI=http://qdrant:6333
      - QDRANT_API_KEY=${QDRANT_API_KEY}
      - RAG_EMBEDDING_ENGINE=ollama
      - RAG_EMBEDDING_MODEL=nomic-embed-text:latest
      - RAG_TOP_K=5
      - ENABLE_RAG_HYBRID_SEARCH=True
      - CONTENT_EXTRA_ENGINE=tika
      - TIKA_SERVER_URL=http://tika:9998
      - ENABLE_AGENT_CANVAS=True
      - ENABLE_TOOL_CALLING=True
      - RECURSIVE_LLM_MAX_DEPTH=3
      - ENABLE_MEMORIES=True
      - AUDIO_STT_ENGINE=openai
      - AUDIO_STT_OPENAI_API_BASE_URL=http://whisper:9001/v1
      - AUDIO_STT_OPENAI_API_KEY=not-needed
      - AUDIO_TTS_ENGINE=openai
      - AUDIO_TTS_OPENAI_API_BASE_URL=http://kokoro:8880/v1
      - AUDIO_TTS_OPENAI_API_KEY=not-needed
      - AUDIO_TTS_OPENAI_API_VOICE=af_heart
      - ENABLE_IMAGE_GENERATION=True
      - IMAGE_GENERATION_ENGINE=comfyui
      - COMFYUI_BASE_URL=http://comfyui:8188
      - ENABLE_RAG_WEB_SEARCH=True
      - RAG_WEB_SEARCH_ENGINE=duckduckgo
    depends_on:
      - ollama
      - whisper
      - kokoro
      - comfyui
      - qdrant
      - tika
    networks:
      - frontend
      - backend
      - nextcloud-net
    extra_hosts:
      - "host.docker.internal:host-gateway"

  qdrant:
    image: qdrant/qdrant:latest
    container_name: qdrant
    restart: always
    environment:
      - QDRANT__SERVICE__API_KEY=${QDRANT_API_KEY}
    ports:
      - "6333:6333"
    volumes:
      - ${PROJECT_ROOT:-.}/qdrant_data:/qdrant/storage
    networks:
      - backend

  comfyui:
    # [NVIDIA]
    image: yanwk/comfyui-boot:cu121-slim
    # [/NVIDIA]
    # [CPU]
    # image: yanwk/comfyui-boot:cpu-slim
    # [/CPU]
    container_name: comfyui
    restart: always
    ports:
      - "8188:8188"
    environment:
      # [NVIDIA]
      - NVIDIA_VISIBLE_DEVICES=all
      # [/NVIDIA]
      - CLI_ARGS=--listen 0.0.0.0
    volumes:
      - ${PROJECT_ROOT:-.}/openwebui/comfyui_data/models:/root/ComfyUI/models
      - ${PROJECT_ROOT:-.}/openwebui/comfyui_data/input:/root/ComfyUI/input
      - ${PROJECT_ROOT:-.}/openwebui/comfyui_data/output:/root/ComfyUI/output
      - ${PROJECT_ROOT:-.}/openwebui/comfyui_data/custom_nodes:/root/ComfyUI/custom_nodes
    # [NVIDIA]
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    # [/NVIDIA]
    networks:
      - frontend
      - backend

  kokoro:
    # [NVIDIA]
    image: ghcr.io/remsky/kokoro-fastapi-gpu:latest
    # [/NVIDIA]
    # [CPU]
    # image: ghcr.io/remsky/kokoro-fastapi-cpu:latest
    # [/CPU]
    container_name: kokoro
    restart: always
    ports:
      - "8880:8880"
    # [NVIDIA]
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    # [/NVIDIA]
    networks:
      - backend
      - nextcloud-net

  # --------------------------
  # Media & Document Management
  # --------------------------
  immich-server:
    image: ghcr.io/immich-app/immich-server:stable
    container_name: immich_server
    restart: always
    depends_on:
      immich-database:
        condition: service_healthy
      immich-redis:
        condition: service_started
      immich-machine-learning:
        condition: service_started
    ports:
      - "2283:2283"
    environment:
      DB_PASSWORD: ${IMMICH_DB_PASSWORD}
      DB_USERNAME: ${IMMICH_DB_USERNAME}
      DB_DATABASE_NAME: ${IMMICH_DB_DATABASE_NAME}
      DB_HOSTNAME: immich-database
      REDIS_HOSTNAME: immich-redis
      IMMICH_MACHINE_LEARNING_URL: http://immich-machine-learning:3003
    volumes:
      - ${PROJECT_ROOT:-.}/immich/library:/data
      - /etc/localtime:/etc/localtime:ro
      - immich_model_cache:/cache
    networks:
      - frontend
      - backend

  immich-redis:
    image: docker.io/valkey/valkey:alpine
    container_name: immich_redis
    restart: always
    networks:
      - backend

  immich-database:
    image: ghcr.io/immich-app/postgres:14-vector
    container_name: immich_database
    restart: always
    environment:
      POSTGRES_PASSWORD: ${IMMICH_DB_PASSWORD}
      POSTGRES_USER: ${IMMICH_DB_USERNAME}
      POSTGRES_DB: ${IMMICH_DB_DATABASE_NAME}
    volumes:
      - ${PROJECT_ROOT:-.}/immich/postgres:/var/lib/postgresql/data
    networks:
      - backend
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5

  immich-machine-learning:
    container_name: immich_machine_learning
    # [NVIDIA]
    image: ghcr.io/immich-app/immich-machine-learning:stable-cuda
    # [/NVIDIA]
    # [CPU]
    # image: ghcr.io/immich-app/immich-machine-learning:stable
    # [/CPU]
    # [INTEL]
    # image: ghcr.io/immich-app/immich-machine-learning:stable-openvino
    # [/INTEL]
    # [NVIDIA]
    runtime: nvidia
    # [/NVIDIA]
    restart: always
    volumes:
      - immich_model_cache:/cache
    environment:
      # [NVIDIA]
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=compute,utility
      # [/NVIDIA]
    networks:
      - backend
    # [NVIDIA]
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all
              capabilities: [gpu]
    # [/NVIDIA]

  paperless-webserver:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    container_name: paperless-webserver
    restart: unless-stopped
    depends_on:
      - paperless-db
      - paperless-broker
      - tika
      - gotenberg
    ports:
      - "8000:8000"
    volumes:
      - ${PROJECT_ROOT:-.}/paperless/data:/usr/src/paperless/data
      - ${PROJECT_ROOT:-.}/paperless/media:/usr/src/paperless/media
      - ${PROJECT_ROOT:-.}/paperless/consume:/usr/src/paperless/consume
    environment:
      PAPERLESS_USER_ID: ${PUID}
      PAPERLESS_GROUP_ID: ${PGID}
      PAPERLESS_REDIS: redis://paperless-broker:6379
      PAPERLESS_DBHOST: paperless-db
      PAPERLESS_URL: ${PAPERLESS_URL}
      PAPERLESS_TIKA_ENABLED: "true" 
      PAPERLESS_TIKA_ENDPOINT: "http://tika:9998" 
      PAPERLESS_TIKA_GOTENBERG_ENDPOINT: "http://gotenberg:3000"
      PAPERLESS_FILENAME_FORMAT: "${PAPERLESS_FILENAME_FORMAT}"
    networks:
      - frontend
      - backend

  paperless-db:
    image: docker.io/library/postgres:16-alpine
    container_name: paperless-db
    restart: always
    environment:
      POSTGRES_DB: ${PAPERLESS_DB_NAME}
      POSTGRES_USER: ${PAPERLESS_DB_USER}
      POSTGRES_PASSWORD: ${PAPERLESS_DB_PASS}
    volumes:
      - ${PROJECT_ROOT:-.}/paperless/pgdata:/var/lib/postgresql/data
    networks:
      - backend

  paperless-broker:
    image: docker.io/library/redis:7-alpine
    container_name: paperless-broker
    restart: unless-stopped
    volumes:
      - ${PROJECT_ROOT:-.}/paperless/redisdata:/data
    networks:
      - backend

  paperless-ai:
    image: clusterzx/paperless-ai:latest
    container_name: paperless-ai
    restart: unless-stopped
    environment:
      - PAPERLESS_URL=http://paperless-webserver:8000
      - PAPERLESS_API_TOKEN=${PAPERLESS_API_TOKEN}
      - AI_PROVIDER=ollama
      - AI_MODEL=granite3.2-vision:latest
      - AI_ENDPOINT=http://ollama:11434/api/generate
      - OLLAMA_API_URL=http://ollama:11434
      - SCAN_INTERVAL=* * * * *
      - PROCESS_PRE_TAGS=ai-process
      - ADD_AI_PROCESSED_TAG=yes
      - AI_PROCESSED_TAG_NAME=ai-processed
      - DELETE_PRE_TAGS=true
    volumes:
      - paperless-ai-data:/app/data
    networks:
      - backend
      - frontend

  gotenberg:
    image: gotenberg/gotenberg:8
    container_name: gotenberg
    restart: unless-stopped
    command:
      - "gotenberg"
      - "--chromium-disable-javascript=true"
    networks:
      - backend
      
  tika:
    image: apache/tika:latest
    container_name: tika
    restart: unless-stopped
    networks:
      - backend

  # -----------------------------
  # Map & Routing Stack
  # -----------------------------
  map-osrm-prep:
    image: osrm/osrm-backend:latest
    command: >
      bash -lc "
      test -f /data/region.osrm
      || (osrm-extract -p /opt/car.lua /data/region.osm.pbf
      && osrm-partition /data/region.osrm
      && osrm-customize /data/region.osrm)"
    volumes:
      - ${PROJECT_ROOT:-.}/osm-stack/data:/data
    profiles: ["import"]
    
  map-osrm:
    image: osrm/osrm-backend:latest
    container_name: map-osrm
    command: osrm-routed --algorithm mld /data/region.osrm
    restart: always
    volumes:
      - map-osrm-data:/data
    networks:
      frontend: {}
      backend:
        ipv4_address: 172.28.0.52

  map-nominatim:
    image: mediagis/nominatim:4.5
    environment:
      PBF_PATH: /nominatim/pbf/region.osm.pbf
      THREADS: "4"
    shm_size: "2g"
    restart: always
    container_name: map-nominatim
    volumes:
      - map-nominatim-pbf:/nominatim/pbf
      - map-nominatim-data:/var/lib/postgresql/16/main
    dns:
      - 1.1.1.1
      - 8.8.8.8
    networks:
      frontend: {}
      backend:
        ipv4_address: 172.28.0.51

  map-tiles:
    image: overv/openstreetmap-tile-server:latest
    container_name: map-tiles
    restart: always
    volumes:
      - map-osm-db:/data/database
      - map-osm-tiles:/var/cache/renderd/tiles
    shm_size: "2g"
    dns:
      - 1.1.1.1
      - 8.8.8.8
    networks:
      frontend: {}
      backend:
        ipv4_address: 172.28.0.50

  # -----------------------------
  # Monitoring & Infrastructure
  # -----------------------------
  uptime-kuma:
    image: louislam/uptime-kuma:latest
    restart: always
    container_name: uptime-kuma
    ports:
      - "3005:3001"
    volumes:
      - uptimekuma_data:/app/data
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - frontend
      - backend

  cloudflared:
    image: cloudflare/cloudflared:latest
    container_name: cloudflared
    restart: unless-stopped
    command: tunnel --edge-ip-version 4 run
    environment:
      - TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}
    networks:
      - frontend
    volumes:
      - ${PROJECT_ROOT:-.}/cloudflared_dns.conf:/etc/resolv.conf:ro

  cloudflare-ddns:
    image: favonia/cloudflare-ddns:latest
    container_name: nc_ddns
    restart: unless-stopped
    network_mode: host
    environment:
      - CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN}
      - DOMAINS=${DOMAINS}
      - PROXIED=${PROXIED}
      - TTL=${TTL}
      - IP4_PROVIDER=${IP4_PROVIDER}
      - IP6_PROVIDER=${IP6_PROVIDER}
      - UPDATE_CRON=${UPDATE_CRON}
      - WEBHOOK_URL_ON_SUCCESS=${WEBHOOK_URL_ON_SUCCESS}
