# /api/webai/* rate limit — web-ai pull worker (60 req/min, burst 20)
limit_req_zone $binary_remote_addr zone=webai:5m rate=60r/m;

server {
  listen 80;
  server_name _;

  # Security headers
  add_header X-Frame-Options "SAMEORIGIN" always;
  add_header X-Content-Type-Options "nosniff" always;
  add_header Referrer-Policy "strict-origin-when-cross-origin" always;

  root /usr/share/nginx/html;
  index index.html;

  # index.html은 캐시 금지 (배포 반영 핵심)
  location = /index.html {
    add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
    try_files $uri =404;
  }

  # 정적 리소스는 장기 캐시 (Vite 해시 파일)
  location /assets/ {
    add_header Cache-Control "public, max-age=31536000, immutable";
    try_files $uri =404;
  }

  # music media — Nginx가 직접 오디오 파일 서빙
  location ^~ /media/music/ {
    alias /data/music/;

    expires 30d;
    add_header Cache-Control "public, max-age=2592000" always;
    add_header Accept-Ranges bytes always;  # 오디오 스트리밍 범위 요청 지원

    autoindex off;
  }

  # video media — Nginx 직접 mp4 서빙
  location ^~ /media/video/ {
    alias /data/video/;

    expires 1d;
    add_header Cache-Control "public, max-age=86400" always;
    add_header Accept-Ranges bytes always;

    autoindex off;
  }

  # image-render 결과 정적 서빙 (Video Studio)
  location ^~ /media/image/ {
    alias /data/image/;

    expires 1d;
    add_header Cache-Control "public, max-age=86400" always;

    autoindex off;
  }

  # music videos — Nginx가 직접 비디오 파일 서빙
  location ^~ /media/insta/ {
    alias /data/insta_cards/;
    expires 1h;
    add_header Cache-Control "public";
    try_files $uri =404;
  }

  location ^~ /media/videos/ {
    alias /data/videos/;

    expires 1d;
    add_header Cache-Control "public, max-age=86400" always;
    add_header Accept-Ranges bytes always;  # 비디오 스트리밍 범위 요청 지원

    autoindex off;
  }

  # music API — 변수 기반 proxy_pass + $request_uri로 전체 경로 전달
  location /api/music/ {
    resolver 127.0.0.11 valid=10s;
    set $music_backend music-lab:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 660s;
    proxy_pass http://$music_backend$request_uri;
  }

  # video-lab — 영상 생성 gateway
  location /api/video/ {
    resolver 127.0.0.11 valid=10s;
    set $video_backend video-lab:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://$video_backend$request_uri;

    proxy_read_timeout 120s;
    proxy_connect_timeout 10s;
  }

  # image-lab — 이미지 생성 gateway (Video Studio)
  location /api/image/ {
    resolver 127.0.0.11 valid=10s;
    set $image_backend image-lab:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://$image_backend$request_uri;

    proxy_read_timeout 120s;
    proxy_connect_timeout 10s;
  }

  # realestate API
  location /api/realestate/ {
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://realestate-lab:8000/api/realestate/;
  }

  # travel thumbnails (generated by travel-proxy, stored in /data/thumbs)
  location ^~ /media/travel/.thumb/ {
    alias /data/thumbs/;

    expires 30d;
    add_header Cache-Control "public, max-age=2592000, immutable" always;

    autoindex off;
  }

  # travel media (images) - nginx가 직접 파일 서빙
  location ^~ /media/travel/ {
    alias /data/travel/;   # ✅ /media/travel/... -> /data/travel/...

    expires 7d;
    add_header Cache-Control "public, max-age=604800" always;

    # 옵션: 폴더리스팅 막기
    autoindex off;
  }

  # 기타 정적 파일(예: vite.svg 등) 기본 캐시(원하면 조정)
  location ~* \.(?:ico|png|jpg|jpeg|gif|svg|webp|css|js)$ {
    add_header Cache-Control "public, max-age=604800";
    try_files $uri =404;
  }

  # todos API → personal
  location /api/todos {
    resolver 127.0.0.11 valid=10s;
    set $personal_backend personal:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://$personal_backend$request_uri;
  }

  # blog API → personal
  location /api/blog/ {
    resolver 127.0.0.11 valid=10s;
    set $personal_backend personal:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://$personal_backend$request_uri;
  }

  # travel API
  location /api/travel/ {
	proxy_http_version 1.1;
	proxy_set_header Host $host;
	proxy_set_header X-Real-IP $remote_addr;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Forwarded-Proto $scheme;
	proxy_read_timeout 600s;
	proxy_pass http://travel-proxy:8000/api/travel/;
  }

  # webai API — rate limited web-ai pull worker
  location /api/webai/ {
    limit_req zone=webai burst=20 nodelay;
    limit_req_status 429;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-WebAI-Key $http_x_webai_key;
    proxy_pass http://stock:8000;
  }

  # stock API
  location /api/stock/ {
	proxy_http_version 1.1;
	proxy_set_header Host $host;
	proxy_set_header X-Real-IP $remote_addr;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Forwarded-Proto $scheme;
	proxy_pass http://stock:8000/api/stock/;
  }
  
  # trade API (Stock Proxy)
  location /api/trade/ {
	proxy_http_version 1.1;
	proxy_set_header Host $host;
	proxy_set_header X-Real-IP $remote_addr;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Forwarded-Proto $scheme;
	proxy_pass http://stock:8000/api/trade/;
  }

  # insta API
  location /api/insta/ {
    resolver 127.0.0.11 valid=10s;
    set $insta_backend insta-lab:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 300s;
    proxy_pass http://$insta_backend$request_uri;
  }

  # Plan-B-Insta — Windows worker → NAS internal webhook (3-layer 차단)
  # Layer 1·2: nginx IP 화이트리스트 (LAN + Tailscale)
  # Layer 3: X-Internal-Key (FastAPI dependency)
  location /api/internal/insta/ {
    allow 192.168.45.0/24;     # LAN 화이트리스트
    allow 100.64.0.0/10;       # Tailscale CGNAT
    allow 127.0.0.1;           # NAS 내부
    deny all;

    resolver 127.0.0.11 valid=10s;
    set $insta_internal_backend insta-lab:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Internal-Key $http_x_internal_key;
    proxy_pass http://$insta_internal_backend$request_uri;
  }

  # Plan-B-Music — Windows music-render → NAS music-lab internal webhook
  # Layer 1·2: nginx IP 화이트리스트 (LAN + Tailscale)
  # Layer 3: X-Internal-Key (FastAPI dependency)
  location /api/internal/music/ {
    allow 192.168.45.0/24;     # LAN 화이트리스트
    allow 100.64.0.0/10;       # Tailscale CGNAT
    allow 127.0.0.1;           # NAS 내부
    deny all;

    resolver 127.0.0.11 valid=10s;
    set $music_internal_backend music-lab:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Internal-Key $http_x_internal_key;
    proxy_pass http://$music_internal_backend$request_uri;
  }

  # Plan-B-Video — Windows video-render → NAS video-lab internal webhook
  # Layer 1·2: nginx IP 화이트리스트 (LAN + Tailscale)
  # Layer 3: X-Internal-Key (FastAPI dependency)
  location /api/internal/video/ {
    allow 192.168.45.0/24;     # LAN 화이트리스트
    allow 100.64.0.0/10;       # Tailscale CGNAT
    allow 127.0.0.1;           # NAS 내부
    deny all;

    resolver 127.0.0.11 valid=10s;
    set $video_internal_backend video-lab:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Internal-Key $http_x_internal_key;
    proxy_pass http://$video_internal_backend$request_uri;
  }

  # Video Studio — Windows image-render → NAS image-lab internal webhook
  # Layer 1·2: nginx IP 화이트리스트 (LAN + Tailscale)
  # Layer 3: X-Internal-Key (FastAPI dependency)
  location /api/internal/image/ {
    allow 192.168.45.0/24;     # LAN 화이트리스트
    allow 100.64.0.0/10;       # Tailscale CGNAT
    allow 127.0.0.1;           # NAS 내부
    deny all;

    resolver 127.0.0.11 valid=10s;
    set $image_internal_backend image-lab:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Internal-Key $http_x_internal_key;
    proxy_pass http://$image_internal_backend$request_uri;
  }

  # portfolio API (Stock) — trailing slash 유무 모두 매칭
  location /api/portfolio {
	proxy_http_version 1.1;
	proxy_set_header Host $host;
	proxy_set_header X-Real-IP $remote_addr;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header X-Forwarded-Proto $scheme;
	proxy_pass http://stock:8000/api/portfolio;
  }


  # profile API (Personal Service)
  location /api/profile/ {
    resolver 127.0.0.11 valid=10s;
    set $personal_backend personal:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://$personal_backend$request_uri;
  }

  # packs-lab — admin upload (5GB body limit, request buffering off)
  location ^~ /api/packs/upload {
    resolver 127.0.0.11 valid=10s;
    set $packs_backend packs-lab:8000;
    client_max_body_size 5G;
    proxy_request_buffering off;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass http://$packs_backend$request_uri;
    proxy_read_timeout 1800s;
    proxy_send_timeout 1800s;
  }

  # packs-lab — 사용자 다운로드 + list/sign-link
  location /api/packs/ {
    resolver 127.0.0.11 valid=10s;
    set $packs_backend packs-lab:8000;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass http://$packs_backend$request_uri;
  }

  # tarot-lab API (agent-office에서 분리)
  # Claude Sonnet 3-card 해석은 30~90초 + truncation reroll 시 추가. 600s 안전 마진.
  location /api/tarot/ {
    resolver 127.0.0.11 valid=10s;
    set $tarot_backend tarot-lab:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_read_timeout 600s;
    proxy_send_timeout 600s;
    proxy_connect_timeout 60s;
    proxy_pass http://$tarot_backend$request_uri;
  }

  # saju-lab API
  location /api/saju/ {
    resolver 127.0.0.11 valid=10s;
    set $saju_backend saju-lab:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_read_timeout 300s;
    proxy_send_timeout 300s;
    proxy_connect_timeout 60s;
    proxy_pass http://$saju_backend$request_uri;
  }

  # agent-office API + WebSocket
  location /api/agent-office/ {
    resolver 127.0.0.11 valid=10s;
    set $agent_office_backend agent-office:8000;

    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 86400s;
    proxy_send_timeout 300s;
    proxy_connect_timeout 60s;
    proxy_pass http://$agent_office_backend$request_uri;
  }

  # API 프록시 (여기가 포인트: /api/ 중복 제거)
  location /api/ {
    proxy_http_version 1.1;

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_pass http://lotto:8000;
  }

  # Fear & Greed Index (CNN 공개 API)
  # 프로덕션 nginx에서는 아래 proxy_pass 추가 필요:
  location /ext/feargreed {
    proxy_pass https://production.dataviz.cnn.io/index/fearandgreed/graphdata;
    proxy_set_header Host production.dataviz.cnn.io;
  }

  # VIX (CBOE 변동성 지수) — Yahoo Finance 공개 API
  # 프로덕션 nginx에서는 아래 proxy_pass 추가 필요:
  location /ext/vix {
    proxy_pass https://query1.finance.yahoo.com/v8/finance/chart/%5EVIX?interval=1d&range=1d;
    proxy_set_header Host query1.finance.yahoo.com;
  }

  # 미국 10년물 국채 금리 (^TNX) — Yahoo Finance
  # 프로덕션 nginx 설정 필요:
  location /ext/treasury {
    proxy_pass https://query1.finance.yahoo.com/v8/finance/chart/%5ETNX?interval=1d&range=1d;
    proxy_set_header Host query1.finance.yahoo.com;
  }

  # WTI 원유 선물 (CL=F) — Yahoo Finance
  # 프로덕션 nginx 설정 필요:
  location /ext/wti {
    proxy_pass https://query1.finance.yahoo.com/v8/finance/chart/CL%3DF?interval=1d&range=1d;
    proxy_set_header Host query1.finance.yahoo.com;
  }

  # Brent 원유 선물 (BZ=F) — Yahoo Finance
  # 프로덕션 nginx 설정 필요:
  location /ext/brent {
    proxy_pass https://query1.finance.yahoo.com/v8/finance/chart/BZ%3DF?interval=1d&range=1d;
    proxy_set_header Host query1.finance.yahoo.com;
  }

  # webhook receiver (handle both /webhook and /webhook/)
  location = /webhook {
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_pass http://deployer:9000/webhook;
  }

  location /webhook/ {
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_pass http://deployer:9000/webhook;
  }

  # SPA 라우팅 (마지막에 두는 게 안전)
  location / {
    try_files $uri $uri/ /index.html;
  }

  # gzip (옵션)
  gzip on;
  gzip_types text/plain text/css application/json application/javascript application/xml+rss;
  gzip_min_length 1024;
}

