# 복사해서 사용: cp config.local.toml.example config.local.toml # 실제 config.local.toml 은 시크릿 포함이라 커밋하지 않는다(.gitignore: *.toml). # # ── 설정 소스는 TOML 하나다(2026-07-13 협의 — env/.env 이중 관리 제거) ── # 호스트 실행: APP_ENV=local(기본) → 이 파일 # Docker : APP_ENV=dev|prod → config.dev.toml / config.prod.toml 을 컨테이너에 마운트 # (각 example 참고, 실행은 ../run_docker.sh 대화형 권장) # env 는 APP_ENV·PROCESS_COUNT/WORKER_CONCURRENCY(실행 스크립트 대화형 입력)·LPS_LIVE(테스트)만 남는다. [WebServerConfig] server_name = "LpsServer" port = 9600 process_count = 1 is_ssl = false is_test = true # CORS 허용 오리진(프론트). 비우면 [] (CORS 미적용). 5173=vite dev. cors_origins = ["http://localhost:5173", "http://127.0.0.1:5173"] # API guard 키 — 비우면 개방 모드(개발). prod 는 채운다(복수 등록 = 무중단 키 교체). # 생성 예: openssl rand -hex 32. 호출자(negodata)도 같은 키를 설정해야 한다. api_keys = [] [LogConfig] print_console = true log_level = "debug" # DB Read/Write 분리. 관리형 DB(RDS/Aurora/Azure)는 host 에 엔드포인트, sslmode="require". # LPS 도메인 로직/테이블이 생기기 전까지는 접속하지 않으므로(엔진 lazy) placeholder 여도 부팅된다. [MainDBConfig] db_type = "postgresql" name = "lps_db" write_host = "127.0.0.1" write_port = 5432 write_id = "" write_pw = "" read_host = "127.0.0.1" read_port = 5432 read_id = "" read_pw = "" show_log = false pool_size = 10 # connection_budget>0 이면 무시(자동 산정). budget=0 일 때만 이 값 사용. max_overflow = 20 # 〃 # 커넥션 예산(자동 산정). process_count 에 맞춰 pool_size/max_overflow 를 자동 계산: # (pool+overflow) × 2엔진 × process_count ≤ connection_budget. # 'lps API 가 쓸 총 커넥션 상한' — 공유 PG(max_connections)·동거 서비스(worker 등)를 고려한 값. # 예) 전용 PG(max_connections=100)면 90 근처, 공유 PG면 40 권장. 0 이면 자동 끔(위 pool 값 사용). connection_budget = 40 sslmode = "" # 로컬: "" / 관리형 DB: "require"|"verify-ca"|"verify-full" # 워커 런타임 (worker_main.py). 동시성만 실행 시 WORKER_CONCURRENCY env 로 임시 override 가능. [WorkerConfig] concurrency = 1 # 상품 동시 검색 수(워커별 브라우저 세트, Chrome 최대 4×N). 로컬 권장 2~3 fallbacks = [] # 오픈마켓 폴백(기본 OFF). 예: ["gmarket", "auction", "st11"] — 켜기 전 라이브 스모크 # Chrome 프로필 베이스. 영속 경로면 재시작에도 쿠키 유지(재웜업 회피). # ⚠️ 컨테이너로 띄우면 반드시 "/profiles" — compose 가 lps-profiles 볼륨을 그 경로에 마운트한다. # ".profiles" 로 두면 /app/.profiles(컨테이너 레이어)에 쌓여 재생성 때마다 쿠키가 전부 날아가고, # 볼륨은 붙어만 있고 아무 일도 하지 않는다(2026-07-28 로컬·배포서버 양쪽에서 실측). # 호스트 직접 실행(run_local_worker.sh)일 때만 ".profiles" 를 쓴다. profile_dir = ".profiles" job_deadline_sec = 300 # 잡 1건 처리 상한(크롤 행 방어). 0=무제한(테스트용) shutdown_grace_sec = 60 # graceful 종료 유예 — docker stop_grace_period 를 이보다 길게 chrome_channel = "chrome" # 로컬: 실제 Chrome chrome_executable = "" # 컨테이너: "/opt/google/chrome/chrome" (설정 시 channel 무시) heartbeat_file = "/tmp/lps_worker_heartbeat" # Docker HEALTHCHECK 가 신선도 확인 # 임계 알림 (AlertManager — 룰 의미는 docs/operations.md 표) [AlertConfig] webhook = "" # Slack 호환 웹훅 URL. 비우면 로그로만 알림 cooldown_min = 30 # 같은 룰 재발송 억제(분). 해소 알림은 즉시 dead_1h = 20 # 최근 1h DEAD 잡 수 blocks_1h = 80 # 최근 1h 봇 감지 수 queue_lag_sec = 300 # 가장 오래된 PENDING 대기 초 pool_pct = 90 # DB 커넥션 풀 포화율(%) source_fail_30m = 5 # 소스별 30분 내 시도 N회 이상 & 성공 0건 deadline_1h = 5 # 최근 1h 잡 데드라인 강제종료 수 cost_1h_usd = 1.0 # 최근 1h 검색원가 합($) ports_low_pct = 30 # 가용 프록시 포트 비율(%) block_sessions_6h = 1 # 최근 6h '예산 회전에도 차단된' IP 세션 수 # ── 시크릿(API 키 등)도 이 파일에서 통합 관리 (미커밋). ── [NaverApiHubConfig] base_url = "https://naverapihub.apigw.ntruss.com" client_id = "" client_secret = "" timeout_sec = 10.0 # AI 유사도 판정/검색어 생성 (OpenAI) [OpenAIConfig] api_key = "" model = "gpt-4o-mini" # DECODO residential 프록시 (쿠팡 전용, 포트기반 sticky). 값 다 채우면 활성(비면 프록시 미사용). [DecodoConfig] host = "" # 예: gate.decodo.com kr_host = "kr.decodo.com" # 한국 타깃 게이트웨이(네이버용). 비우면 host 사용 username = "" # 대시보드 USERNAME (예: sppd6a3ze3) password = "" # 대시보드 PASSWORD port_start = 0 # 예: 10001 port_end = 0 # 예: 10010 — 포트를 늘리면(계약 변경) 이 범위만 넓히면 됨(코드 무변경) session_minutes = 10 # 대시보드 Sticky 지속시간(분)과 일치 cost_per_gb = 0.0 # DECODO 요금($/GB) — 검색 원가의 대역폭 비용 산정용(플랜에 맞게, 예 3.0) ip_request_budget = 3 # IP당 요청 예산 — 도달 시 차단 전 선제 회전(0=비활성). 튜닝은 docs/database.md naver_ip_request_budget = 10 # 네이버는 IP 당 12회까지 무차단 실측 → 여유 둔 10 port_cooldown_sec = 0 # 차단 감지 포트 격리 초. 0=자동 max(sticky, 30분)