name: webpage

services:
  lotto:
    build:
      context: ./lotto
      args:
        APP_VERSION: ${APP_VERSION:-dev}
    container_name: lotto
    restart: unless-stopped
    ports:
      - "18000:8000"
    environment:
      - TZ=${TZ:-Asia/Seoul}
      - LOTTO_ALL_URL=${LOTTO_ALL_URL:-https://smok95.github.io/lotto/results/all.json}
      - LOTTO_LATEST_URL=${LOTTO_LATEST_URL:-https://smok95.github.io/lotto/results/latest.json}
    volumes:
      - ${RUNTIME_PATH}/data:/app/data
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 60s
      timeout: 5s
      retries: 3

  stock:
    build:
      context: ./stock
      args:
        APP_VERSION: ${APP_VERSION:-dev}
    container_name: stock
    restart: unless-stopped
    ports:
      - "18500:8000"
    environment:
      - TZ=${TZ:-Asia/Seoul}
      - WINDOWS_AI_SERVER_URL=${WINDOWS_AI_SERVER_URL:-http://192.168.0.5:8000}
      - GEMINI_API_KEY=${GEMINI_API_KEY:-}
      - GEMINI_MODEL=${GEMINI_MODEL:-gemini-1.5-flash}
      - ADMIN_API_KEY=${ADMIN_API_KEY:-}
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
      - ANTHROPIC_MODEL=${ANTHROPIC_MODEL:-claude-haiku-4-5-20251001}
      - LLM_PROVIDER=${LLM_PROVIDER:-claude}
      - OLLAMA_URL=${OLLAMA_URL:-http://192.168.45.59:11435}
      - OLLAMA_MODEL=${OLLAMA_MODEL:-qwen3:14b}
      - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080}
      - WEBAI_API_KEY=${WEBAI_API_KEY:-}
    volumes:
      - ${RUNTIME_PATH}/data/stock:/app/data
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 60s
      timeout: 5s
      retries: 3

  music-lab:
    build:
      context: ./music-lab
    container_name: music-lab
    restart: unless-stopped
    ports:
      - "18600:8000"
    environment:
      - TZ=${TZ:-Asia/Seoul}
      - MUSIC_AI_SERVER_URL=${MUSIC_AI_SERVER_URL:-}
      - MUSIC_MEDIA_BASE=${MUSIC_MEDIA_BASE:-/media/music}
      - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080}
      - PEXELS_API_KEY=${PEXELS_API_KEY:-}
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
      - OPENAI_API_KEY=${OPENAI_API_KEY:-}
      - YOUTUBE_OAUTH_CLIENT_ID=${YOUTUBE_OAUTH_CLIENT_ID:-}
      - YOUTUBE_OAUTH_CLIENT_SECRET=${YOUTUBE_OAUTH_CLIENT_SECRET:-}
      - YOUTUBE_OAUTH_REDIRECT_URI=${YOUTUBE_OAUTH_REDIRECT_URI:-}
      - CLAUDE_HAIKU_MODEL=${CLAUDE_HAIKU_MODEL:-claude-haiku-4-5-20251001}
      - CLAUDE_SONNET_MODEL=${CLAUDE_SONNET_MODEL:-claude-sonnet-4-6}
      - VIDEO_DATA_DIR=${VIDEO_DATA_DIR:-/app/data/videos}
      - WINDOWS_VIDEO_ENCODER_URL=${WINDOWS_VIDEO_ENCODER_URL:-}
      - NAS_VIDEOS_ROOT=${NAS_VIDEOS_ROOT:-/volume1/docker/webpage/data/videos}
      - NAS_MUSIC_ROOT=${NAS_MUSIC_ROOT:-/volume1/docker/webpage/data/music}
      - REDIS_URL=${REDIS_URL:-redis://redis:6379}
      - INTERNAL_API_KEY=${INTERNAL_API_KEY:-}
      - MUSIC_RENDER_URL=${MUSIC_RENDER_URL:-http://192.168.45.59:18711}
    volumes:
      - ${RUNTIME_PATH}/data/music:/app/data
      - ${RUNTIME_PATH:-.}/data/videos:/app/data/videos
    depends_on:
      - redis
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 60s
      timeout: 5s
      retries: 3

  insta-lab:
    build:
      context: ./insta-lab
    container_name: insta-lab
    restart: unless-stopped
    ports:
      - "18700:8000"
    environment:
      - TZ=${TZ:-Asia/Seoul}
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
      - ANTHROPIC_MODEL_HAIKU=${ANTHROPIC_MODEL_HAIKU:-claude-haiku-4-5-20251001}
      - ANTHROPIC_MODEL_SONNET=${ANTHROPIC_MODEL_SONNET:-claude-sonnet-4-6}
      - NAVER_CLIENT_ID=${NAVER_CLIENT_ID:-}
      - NAVER_CLIENT_SECRET=${NAVER_CLIENT_SECRET:-}
      - YOUTUBE_DATA_API_KEY=${YOUTUBE_DATA_API_KEY:-}
      - INSTA_DATA_PATH=/app/data
      - CARD_TEMPLATE_DIR=/app/app/templates
      - INSTA_DEFAULT_THEME=${INSTA_DEFAULT_THEME:-default}
      - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080}
      - REDIS_URL=${REDIS_URL:-redis://redis:6379}
      - INTERNAL_API_KEY=${INTERNAL_API_KEY:-}
    volumes:
      - ${RUNTIME_PATH}/data/insta:/app/data
    depends_on:
      - redis
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 60s
      timeout: 5s
      retries: 3

  realestate-lab:
    build:
      context: ./realestate-lab
    container_name: realestate-lab
    restart: unless-stopped
    ports:
      - "18800:8000"
    environment:
      - TZ=${TZ:-Asia/Seoul}
      - DATA_GO_KR_API_KEY=${DATA_GO_KR_API_KEY:-}
      - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080}
      - AGENT_OFFICE_URL=${AGENT_OFFICE_URL:-http://agent-office:8000}
    volumes:
      - ${RUNTIME_PATH}/data/realestate:/app/data
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 60s
      timeout: 5s
      retries: 3

  agent-office:
    build:
      context: ./agent-office
    container_name: agent-office
    restart: unless-stopped
    ports:
      - "18900:8000"
    environment:
      - TZ=${TZ:-Asia/Seoul}
      - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080}
      - STOCK_URL=http://stock:8000
      - MUSIC_LAB_URL=http://music-lab:8000
      - INSTA_LAB_URL=http://insta-lab:8000
      - REALESTATE_LAB_URL=http://realestate-lab:8000
      - REALESTATE_DASHBOARD_URL=${REALESTATE_DASHBOARD_URL:-http://localhost:8080/realestate}
      - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-}
      - TELEGRAM_CHAT_ID=${TELEGRAM_CHAT_ID:-}
      - TELEGRAM_WEBHOOK_URL=${TELEGRAM_WEBHOOK_URL:-}
      - TELEGRAM_WIFE_CHAT_ID=${TELEGRAM_WIFE_CHAT_ID:-}
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
      - CLAUDE_HAIKU_MODEL=${CLAUDE_HAIKU_MODEL:-claude-haiku-4-5-20251001}
      - CLAUDE_SONNET_MODEL=${CLAUDE_SONNET_MODEL:-claude-sonnet-4-6}
      - LOTTO_BACKEND_URL=${LOTTO_BACKEND_URL:-http://lotto:8000}
      - LOTTO_CURATOR_MODEL=${LOTTO_CURATOR_MODEL:-claude-sonnet-4-5}
      - CONVERSATION_MODEL=${CONVERSATION_MODEL:-claude-haiku-4-5-20251001}
      - CONVERSATION_HISTORY_LIMIT=${CONVERSATION_HISTORY_LIMIT:-20}
      - CONVERSATION_RATE_PER_MIN=${CONVERSATION_RATE_PER_MIN:-6}
      - YOUTUBE_DATA_API_KEY=${YOUTUBE_DATA_API_KEY:-}
    volumes:
      - ${RUNTIME_PATH:-.}/data/agent-office:/app/data
    depends_on:
      - stock
      - music-lab
      - insta-lab
      - realestate-lab
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 60s
      timeout: 5s
      retries: 3

  personal:
    build:
      context: ./personal
    container_name: personal
    restart: unless-stopped
    ports:
      - "18850:8000"
    environment:
      - TZ=${TZ:-Asia/Seoul}
      - PORTFOLIO_EDIT_PASSWORD=${PORTFOLIO_EDIT_PASSWORD:-}
      - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080}
    volumes:
      - ${RUNTIME_PATH:-.}/data/personal:/app/data
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 60s
      timeout: 5s
      retries: 3

  packs-lab:
    build:
      context: ./packs-lab
    container_name: packs-lab
    restart: unless-stopped
    ports:
      - "18950:8000"
    environment:
      - TZ=${TZ:-Asia/Seoul}
      - DSM_HOST=${DSM_HOST:-}
      - DSM_USER=${DSM_USER:-}
      - DSM_PASS=${DSM_PASS:-}
      - DSM_VERIFY_SSL=${DSM_VERIFY_SSL:-true}
      - BACKEND_HMAC_SECRET=${BACKEND_HMAC_SECRET:-}
      - SUPABASE_URL=${SUPABASE_URL:-}
      - SUPABASE_SERVICE_KEY=${SUPABASE_SERVICE_KEY:-}
      - UPLOAD_TOKEN_TTL_SEC=${UPLOAD_TOKEN_TTL_SEC:-1800}
      - PACK_BASE_DIR=${PACK_BASE_DIR:-/app/data/packs}
      - PACK_HOST_DIR=${PACK_HOST_DIR:-${PACK_DATA_PATH:-./data/packs}}
    volumes:
      - ${PACK_DATA_PATH:-./data/packs}:${PACK_BASE_DIR:-/app/data/packs}
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 60s
      timeout: 5s
      retries: 3

  travel-proxy:
    build: ./travel-proxy
    container_name: travel-proxy
    restart: unless-stopped
    user: "${PUID}:${PGID}"
    ports:
      - "19000:8000"
    environment:
      - TZ=${TZ:-Asia/Seoul}
      - TRAVEL_ROOT=${TRAVEL_ROOT:-/data/travel}
      - TRAVEL_THUMB_ROOT=${TRAVEL_THUMB_ROOT:-/data/thumbs}
      - TRAVEL_MEDIA_BASE=${TRAVEL_MEDIA_BASE:-/media/travel}
      - TRAVEL_DB_PATH=${TRAVEL_DB_PATH:-/data/thumbs/travel.db}
      - CORS_ALLOW_ORIGINS=${CORS_ALLOW_ORIGINS:-http://localhost:3007,http://localhost:8080}
    volumes:
      - ${PHOTO_PATH}:/data/travel:ro
      - ${RUNTIME_PATH}/travel-thumbs:/data/thumbs:rw
    healthcheck:
      test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"]
      interval: 60s
      timeout: 5s
      retries: 3

  frontend:
    image: nginx:alpine
    container_name: frontend
    restart: unless-stopped
    depends_on:
      - lotto
      - stock
      - music-lab
      - insta-lab
      - realestate-lab
      - agent-office
      - personal
      - packs-lab
      - travel-proxy
    ports:
      - "8080:80"
    volumes:
      - ${FRONTEND_PATH}:/usr/share/nginx/html:ro
      - ${RUNTIME_PATH}/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
      - ${PHOTO_PATH}:/data/travel:ro
      - ${RUNTIME_PATH}/travel-thumbs:/data/thumbs:ro
      - ${RUNTIME_PATH}/data/music:/data/music:ro
      - ${RUNTIME_PATH}/data/videos:/data/videos:ro
      - ${RUNTIME_PATH}/data/insta/insta_cards:/data/insta_cards:ro
    extra_hosts:
      - "host.docker.internal:host-gateway"
    healthcheck:
      test: ["CMD", "wget", "-q", "--spider", "http://localhost:80/"]
      interval: 60s
      timeout: 5s
      retries: 3

  deployer:
    build: ./deployer
    container_name: webpage-deployer
    restart: unless-stopped
    ports:
      - "127.0.0.1:19010:9000"
    environment:
      - TZ=${TZ:-Asia/Seoul}
      - WEBHOOK_SECRET=${WEBHOOK_SECRET}
      - PUID=${PUID:-1026}
      - PGID=${PGID:-100}
    volumes:
      - ${REPO_PATH}:/repo:rw
      - ${RUNTIME_PATH}:/runtime:rw
      - ${RUNTIME_PATH}/scripts:/scripts:ro
      - /var/run/docker.sock:/var/run/docker.sock

  redis:
    image: redis:7-alpine
    container_name: redis
    restart: unless-stopped
    ports:
      - "6379:6379"
    volumes:
      - ${RUNTIME_PATH}/redis-data:/data
    command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 60s
      timeout: 5s
      retries: 3
