o2o-negosium-original/lps/config/config.prod.toml.example
민헌 b7fc327779 refactor(lps): 사문화된 네이버 오픈API 어댑터 제거 + 낡은 테스트 계약 갱신
**낡은 테스트**: test_handler_skips_record_on_negative_cache_hit 는 '캐시 히트면 이력을
남기지 않는다'를 검증했는데, 그 동작은 실측 버그였다 — 잡은 DONE 인데 price_history 에
새 행이 없어 이를 폴링하는 소비자(negodata 최저가 모달)가 결과를 영영 못 받고 로딩만 돌았다.
코드는 이미 '캐시 히트도 이 잡의 결과이므로 기록한다'로 고쳐져 있었고 테스트만 남아 있었다.
→ 현재 계약(not_found 스냅샷 1건 기록, 가격은 null)을 검증하도록 다시 씀. 전체 220 passed·0 failed.

**오픈API 어댑터 제거**: shop.json 이 2026-07-31 종료돼 404 SE05 만 반환하고, 파이프라인은
naver_shop(크롤)로 옮겨 갔다. 되살릴 수 없는 코드를 남겨두면 다음 사람이 "키를 넣으면 되나"
하고 시간을 쓴다.
- services/search/naver/ (adapter·transform) 삭제
- NaverConfig 모델·로더·설정 섹션 3개 파일에서 제거(죽은 키)
- test_naver_transform 삭제, test_alerts 는 NaverAdapter 대신 스텁 사용
  (검증 대상인 recent_stats/_note_result 는 베이스 SearchAdapter 계약이라 무관)

**문서 정합화**: architecture(네이버 안티봇=WTM, 통과 3조건) · api(배송비가 이제 채워짐,
가격은 즉시판매가·쿠폰가 제외) · operations(kr_host·naver_ip_request_budget) · README 트리.

source 이름 "naver" 는 그대로다 — price_history·by_mall·프론트 계약은 구현 교체와 무관하다.
2026-08-05 13:26:10 +09:00

81 lines
3.0 KiB
Plaintext

# 배포서버용. 복사해서 사용: cp config.prod.toml.example config.prod.toml
# 실제 config.prod.toml 은 시크릿 포함이라 커밋하지 않는다.
#
# ⚠️ 로드 경로 주의 — docker-compose.prod.yml 이 이 파일을 config.local.toml 자리에 마운트한다:
# ./lps/config/config.prod.toml : /app/config/config.local.toml : ro
# 컨테이너는 APP_ENV=local 로 뜨므로 코드가 읽는 파일명은 config.local.toml 이지만
# 내용은 이 파일이다. 파일명만 보고 "prod 설정이 안 읽힌다"고 오해하기 쉽다.
#
# 로컬(config.local.toml.example)과 다른 항목만 ★ 로 표시했다.
[WebServerConfig]
server_name = "LpsServer"
port = 9600
process_count = 1
is_ssl = false # 리버스프록시 뒤 — TLS 는 프록시가 종단
is_test = false # ★ prod
cors_origins = [] # ★ 브라우저가 직접 호출하지 않으면 비움
api_keys = ["<API_KEY>"] # ★ prod 는 반드시 채운다(비면 무인증 개방). openssl rand -hex 32
[LogConfig]
print_console = true
log_level = "info" # ★ prod
[MainDBConfig]
db_type = "postgresql"
name = "lps_db"
write_host = "host.docker.internal" # ★ 컨테이너 → 호스트 DB (compose extra_hosts)
write_port = 5432
write_id = "<DB_USER>"
write_pw = "<DB_PASSWORD>"
read_host = "host.docker.internal" # ★
read_port = 5432
read_id = "<DB_USER>"
read_pw = "<DB_PASSWORD>"
show_log = false
pool_size = 10
max_overflow = 20
connection_budget = 40
sslmode = "" # 관리형 DB 면 "require"
[WorkerConfig]
concurrency = 1 # ★ 동시성을 올리면 차단 시 IP 소모도 비례해 늘어난다
fallbacks = []
profile_dir = "/profiles" # ★ 필수 — compose 가 lps-profiles 볼륨을 여기에 마운트한다.
# ".profiles" 로 두면 컨테이너 레이어에 쌓여 재생성마다 쿠키가 날아간다.
job_deadline_sec = 300
shutdown_grace_sec = 60
chrome_channel = "chrome"
chrome_executable = "/opt/google/chrome/chrome" # ★ 컨테이너 필수(설정 시 --no-sandbox 가 함께 붙음)
heartbeat_file = "/tmp/lps_worker_heartbeat"
[AlertConfig]
webhook = "" # ★ Slack 호환 웹훅. 비우면 로그로만 알림
cooldown_min = 30
dead_1h = 20
blocks_1h = 80
queue_lag_sec = 300
pool_pct = 90
source_fail_30m = 5
deadline_1h = 5
cost_1h_usd = 1.0
ports_low_pct = 30
block_sessions_6h = 1
# ── 시크릿 ──
[OpenAIConfig]
api_key = "<OPENAI_API_KEY>" # 소진되면 크롤이 성공해도 AI 판정 실패로 잡이 DEAD 된다
model = "gpt-4o-mini"
[DecodoConfig]
host = "gate.decodo.com"
username = "<DECODO_USERNAME>"
password = "<DECODO_PASSWORD>"
port_start = 10001
port_end = 10100
session_minutes = 10
cost_per_gb = 3.0
ip_request_budget = 3 # IP당 요청 예산. 차단이 ip_req#1 에 몰리면 이 값과 무관한 문제다
port_cooldown_sec = 0 # 0=자동 max(sticky, 30분)