# Task 241.1 보고서: InfoKeyword Worker 크롤러 정확도 문제 원인 분석 및 수정

## 작업 내용

제이회장님이 "가공육 암" 키워드로 직접 확인한 네이버 실제 데이터와 InfoKeyword Worker 분석 결과 불일치 문제를 조사하고 수정했습니다.

### 원인 분석 결과

**step2 (연관 검색어)**: 자기 자신 키워드를 제외하는 필터링 로직이 없었음. "가공육 암" 키워드 자체가 연관 검색어에 포함될 수 있는 구조적 문제.

**step3 (자동완성)**: 네이버 자동완성 API가 입력 키워드 자체를 suggestion으로 반환함. Firestore 확인 결과 `suggestions: ["가공육 암"]` → 자기 자신이 포함되어 pass=true로 오판. 실제 네이버에서는 자동완성 결과 없음.

**step4 (검색량)** — 2중 버그:
- **Bug A (공백 문제)**: 네이버 Search Ad API의 `hintKeywords` 파라미터가 공백 포함 키워드를 허용하지 않음 (HTTP 400 에러 반환). "가공육 암" → 400 에러 → stub `{pc:0, mobile:0, total:0}` 반환.
- **Bug B (파싱 문제)**: `_parse_count()` 함수가 네이버 API의 `"< 10"` 문자열을 0으로 변환. 네이버 키워드 도구 UI는 이를 10으로 표시하므로 일치하지 않음.

### Firestore 저장 데이터 (수정 전, 문서 ID: CCQSDNfQZABqvr1GOyS6)
- step2_related: `{"pass": false, "related_keywords": []}`
- step3_autocomplete: `{"pass": true, "suggestions": ["가공육 암"]}` ← 잘못됨
- step4_search_volume: `{"pass": false, "pc_volume": 0, "mobile_volume": 0, "total_volume": 0}` ← 잘못됨

### 네이버 실제 데이터 (제이회장님 확인)
- 연관 검색어: 자기 자신만 → 제외 시 0개
- 자동완성: 없음
- 검색량: PC 10 / 모바일 60 / Total 70

## 수정 내용

### 1. related_keywords.py (step2)
- `get_related_keywords()` 함수에 자기 자신 키워드 제외 로직 추가
- 공백 제거 + 소문자 정규화 비교로 `keyword.replace(" ", "").lower()` 기반 필터링
- script 추출 결과와 DOM 추출 결과 각각에 적용

### 2. autocomplete.py (step3)
- `get_autocomplete()` 함수에 자기 자신 키워드 제외 로직 추가
- 동일한 정규화 비교 방식 사용

### 3. search_ad.py (step4)
- `_fetch_search_volume()`: API 호출 전 `keyword.replace(" ", "")`로 공백 제거
- `_fetch_search_volume()`: 응답 relKeyword 매칭 시에도 공백 제거 비교
- `_parse_count()`: `"< 10"` → `int("10")` = 10 반환으로 수정 (네이버 UI와 일치)

### 4. page.tsx (프론트엔드)
- STEP_LABELS: `"연관 키워드"` → `"연관 검색어"` 변경
- 빈 상태 메시지: `"연관 키워드 없음"` → `"연관 검색어 없음"` 변경

## 생성/수정 파일 목록

- `/home/jay/projects/InfoKeyword/worker/crawler/related_keywords.py` — 수정
- `/home/jay/projects/InfoKeyword/worker/crawler/autocomplete.py` — 수정
- `/home/jay/projects/InfoKeyword/worker/crawler/search_ad.py` — 수정
- `/home/jay/projects/InfoKeyword/src/app/report/[id]/page.tsx` — 수정

## 테스트 결과

### 수정 후 실제 API 호출 테스트 ("가공육 암" 키워드)

**step2 (연관 검색어)**:
- 결과: `keywords: []`, count: 0, pass: False ✅
- 기대값 일치: 연관 검색어 없음

**step3 (자동완성)**:
- 결과: `suggestions: []`, count: 0, pass: False ✅
- 기대값 일치: 자기 자신 제외 → 자동완성 없음

**step4 (검색량)**:
- 결과: `{'pc': 10, 'mobile': 60, 'total': 70}`, pass: True ✅
- 기대값 일치: PC 10 / 모바일 60 / Total 70

**_parse_count 엣지 케이스 테스트**:
- `_parse_count("< 10")` = 10 ✅
- `_parse_count("<10")` = 10 ✅
- `_parse_count(10)` = 10 ✅
- `_parse_count(60)` = 60 ✅
- `_parse_count(None)` = 0 ✅
- `_parse_count("1,234")` = 1234 ✅

**프론트엔드 빌드**: `npm run build` 성공 ✅

## 버그 유무
- 발견된 버그 3건 모두 수정 완료
- 수정 후 네이버 실제 데이터와 정확히 일치

## 비고
- 데이터 모델(출력 구조)은 변경 없음. 크롤러 내부 로직만 수정.
- 기존 키워드 분석에도 동일한 자기 자신 제외 로직이 적용되어 정확도 향상 예상.
- `.git` 없으므로 커밋 불필요.

## 자동 검증 결과 (qc_verify.py)
```json
{
  "task_id": "task-241.1",
  "overall": "WARN",
  "checks": {
    "api_health": {"status": "SKIP"},
    "file_check": {"status": "PASS", "details": "6/6 checks passed"},
    "data_integrity": {"status": "WARN", "details": "task-timers.json status 불일치 (타이머 미종료)"},
    "test_runner": {"status": "SKIP"},
    "schema_contract": {"status": "SKIP"}
  }
}
```

## 마아트 독립 검증 결과
- step2 자기 자신 제외 (related_keywords.py): **PASS**
- step3 자기 자신 제외 (autocomplete.py): **PASS**
- step4 공백 제거 API 호출 (search_ad.py): **PASS**
- step4 "< 10" 파싱 (_parse_count): **PASS**
- 공백/대소문자 정규화 일관성: **PASS**
- 프론트엔드 라벨 변경 (page.tsx): **PASS**
- qc_verify file_check: **PASS**
- 실제 라이브 API 호출 검증: 네이버 실제 데이터와 일치 확인
- **코드 품질 최종 판정: PASS**
- 재작업 요청: 없음
