o2o-negosium-original/lps/docs/2026-08-07-session-notes.md
민헌 7dc925bcd4 docs(lps): 2026-08-07 세션 기록 — IP 로테이션 검수·네이버 UA 규명·결과 상태 정의
다음 세션이 이어받을 수 있게 남긴다.

- docs/2026-08-07-session-notes.md 신규: 세 덩어리(IP 로테이션 결함 6개, 네이버 컨테이너 차단이
  실은 UA 플랫폼 토큰이었다는 규명, '못 봤다'를 '없다'고 말하던 문제의 4단계 해결)와
  **되돌리기 전에 볼 근거**(예산을 IP 에 묶는 이유, 태우지 않는 판정, 임대 없이 크롤 금지,
  UA 는 플랫폼만 바꾸고 버전은 실값, 상태는 하나로 저장하고 표시에서 접기).
- 미해결: 쿠팡 간헐 차단 — IP 에 따라 갈리므로 환경이 아니라 평판. 쿠팡만 gate(해외 IP)를 쓰는 게
  유력한 원인이고, 네이버처럼 kr_host 로 바꾸는 검증이 중단된 상태.
- 다음 할 일 5가지(운영 마이그레이션 → 쿠팡 KR 검증 → 예산 튜닝 → AI 매칭 정확도 → admin 잡목록).
- 주의사항 5가지: **마이그레이션→코드 순서 강제**(역순이면 최저가 조회가 통째로 실패, 재현 확인),
  워커 켜고 pytest 하면 test_job_queue 3개 깨짐, JS 지문 위장은 patchright 가 막아 불가,
  로컬 negodata-front 는 node_modules 가 named volume 이라 재빌드로 의존성이 안 늘어남.
- README 문서 표에 링크 추가.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 15:02:25 +09:00

6.6 KiB
Raw Permalink Blame History

2026-08-07 작업 기록 — IP 로테이션 검수 · 네이버 컨테이너 차단 규명 · 결과 상태 정의

다음 세션이 이어받을 수 있도록 무엇이 왜 바뀌었고, 무엇이 남았는지만 적는다. 상태 정의는 result-states.md, 운영 절차는 operations.md 가 소스다.

1. 무슨 일이 있었나

세 덩어리다. 앞의 둘은 "고장 났다"에서 출발했고, 셋째는 그 과정에서 드러난 설계 문제다.

① IP 로테이션이 설계대로 안 돌고 있었다. 검수해 보니 결함이 6개였고, 그중 하나는 bot_detection.ip_request_no 를 항상 1 로 만들어 과거 진단 결론까지 오염시켰다.

② 컨테이너에서 네이버만 막혔다. 원인은 컨테이너가 아니라 UA 의 플랫폼 토큰이었다. 네이버는 리눅스 데스크톱 Chrome 을 HTTP 405 로 거부한다.

③ '못 봤다'를 '없다'고 말하고 있었다. 차단당해 확인 못 한 몰이 화면에서 '없음(–)'과 구분되지 않았다. 상태를 정의하고 4단계로 화면까지 연결했다.

2. 지금 상태

항목 상태
네이버 컨테이너에서 정상(UA 보정). 검색당 40건
쿠팡 간헐적 차단 — 해외 IP(gate) 사용이 원인으로 추정(아래 4번)
IP 로테이션 예산·회전·소각이 모두 의도대로. 서킷브레이커가 풀 고갈 차단
결과 상태 몰별 7상태 → 운영자 화면은 그대로, 사용자 화면은 3가지로 접음
잡 한 소스가 막혀도 정상 종료(DEAD 아님)
테스트 lps 292 · negodata 107 passed
배포 로컬 전체 재빌드·기동 완료. 운영은 마이그레이션 미적용(아래 5번)

3. 이번에 정한 것 (되돌리려면 근거부터 볼 것)

  • 예산은 브라우저가 아니라 IP 에 묶는다. 유휴 정리(120s)는 브라우저만 닫고 같은 IP 로 돌아오는데, 브라우저 기준으로 세면 카운터가 매번 초기화돼 예산이 영영 발화하지 않는다 (실측: 6회 검색이 전부 같은 포트·ip_req#1). 시계도 하나(_session_started_at)로 통일했다.
  • 회전해도 소용없는 차단은 IP 를 태우지 않는다. 서로 다른 IP 3개가 연속으로 첫 요청부터 막히면 IP 문제가 아니다(평판이면 몇 개는 통과하고, 과사용이면 뒤쪽에서 막힌다). 임계 없이 태우면 잡 16건에 100포트가 30분 쿨다운으로 묶인다. 성공 1회로 자동 해제된다.
  • 임대 없이는 크롤하지 않는다. 풀이 마르면 예전엔 계산식으로 포트를 골라 남이 쥔 IP 를 같이 썼다(실측 재현). 장부가 막으려던 바로 그 문제라, 못 잡으면 실패하는 게 맞다.
  • UA 는 플랫폼 토큰만 바꾸고 버전은 실제 값을 쓴다. 통째로 하드코딩하면 컨테이너 Chrome 이 업데이트될 때 UA 와 엔진이 어긋나 그 불일치가 새 봇 신호가 된다. 쿠팡은 잘 통과하므로 안 건드린다.
  • 상태는 하나로 정의·저장하고 표시 단계에서 접는다. 저장을 단순화하면 운영자가 원인을 못 보고, 표시를 상세화하면 사용자가 못 읽는다. partial 을 컬럼으로 둔 것도 같은 이유 — 소비자가 '어떤 상태가 확인된 것인가'라는 판단 규칙까지 알면 상태 정의가 두 곳으로 흩어진다.
  • 부분 실패의 not_found 는 네거티브 캐시에 넣지 않는다. 못 본 몰에 있었을 수 있는데 '없음'으로 굳히면 TTL 동안 재검색이 막힌다(사용자가 '다시 검색'을 눌러도 캐시 히트).

4. 미해결 — 쿠팡 간헐적 차단

사용권한이 제한된(3.4KB)·errors.edgesuite.net(0.4KB) 마커로 막히는데 IP 에 따라 갈린다 (일부는 통과 → 서킷브레이커가 자동 해제). 즉 환경이 아니라 IP 평판 쪽이다.

유력한 원인: 쿠팡만 gate(국가 무지정 = 해외 IP)를 쓴다. 네이버는 kr_host(한국 IP)로 바꾼 뒤 안정됐다. 같은 처방이 통할 가능성이 높다.

검증하려던 스크립트가 도구 시간 제한으로 중단됐다. 컨테이너에서 gate vs kr 통과율을 IP 3개씩 비교하면 된다(네이버 UA 검증과 같은 방식).

⚠️ 맥 컨테이너는 amd64 를 Rosetta 로 에뮬레이션한다. 여기서 쿠팡이 막히는 건 실서버와 다를 수 있다 — 실서버에선 쿠팡이 60건 정상이었다. 판단은 실서버 로그로 한다.

5. 다음에 할 일 (우선순위)

  1. 운영 DB 마이그레이션 적용 — 아직 안 됐다. 순서가 중요하다(아래 6번). 6_lps_2026-08_dbeaver.sql(lps_db) · 2026-08-07-iilp-source-state.sql(negosium_db)
  2. 쿠팡 KR 게이트웨이 검증 — 4번. 지금 최저가 커버리지의 최대 구멍이다.
  3. 예산 튜닝 — F1 수정으로 ip_request_no 가 처음으로 실제 사용량을 반영한다. ip_req#1 위주면 IP 평판, 2 이상이면 예산 하향. 2026-08-06 이전 데이터는 쓰지 말 것.
  4. AI 매칭 정확도 측정 — 세션 초반에 접근법만 논의하고 미착수. 정답 세트 20~30개로 "몇 % 맞나"를 재야 한다. 지금도 최저가 품질의 최대 병목이다.
  5. lps-admin 잡 목록에 몰별 상태 노출(상품 화면엔 이미 있음, 우선순위 낮음).

6. 작업 시 주의

  • 마이그레이션 → 코드 순서를 지킬 것. negodata 가 ORM 전체 엔티티를 조회하므로 (lps_sync_crud.py:96), 컬럼이 없는 DB 에 새 코드가 붙으면 최저가 조회가 통째로 실패한다 (재현 확인). 역순(마이그레이션 후 옛 코드)은 안전하다 — 옛 컨테이너로 실증했다.
  • 워커를 켜 둔 채 pytest 하면 test_job_queue 3개가 깨진다. 워커가 테스트 잡을 집어가서다. 코드 문제가 아니다 — docker compose stop lps-worker 후 돌리면 292 passed.
  • JS 로 브라우저 지문을 덮는 방법은 이 스택에서 통하지 않는다. patchright 가 add_init_script(CDP 주입)를 무력화하고, MV3 확장도 값이 안 바뀐다. 다시 시도하기 전에 services/search/fingerprint.py docstring 을 볼 것.
  • 로컬 dev 의 negodata-front 는 node_modules 가 named volume 이다. 의존성이 늘면 이미지를 다시 빌드해도 반영되지 않는다 — 컨테이너 안에서 npm install 해야 한다(prod 은 Dockerfile.prod 라 해당 없음).
  • 테스트가 실DB를 TRUNCATE 하는 문제는 그대로다(price_history·job·ip_session·bot_detection).