# InsuRo 트렌드 인사이트 — Phase 2~5 한정승인

## 작업 레벨: Lv.4 (5팀 한정승인 — Phase 2~5 전체를 팀장이 순차 일괄 진행)

## 프로젝트
- InsuRo 서버: `/home/jay/projects/InsuRo/server`
- InsuRo 프론트: `/home/jay/projects/InsuRo`

## 트렌드 인사이트 3문서 (필수 참조)
- 계획서: `/home/jay/workspace/memory/plans/insuro-trend-insight/plan.md`
- 맥락노트: `/home/jay/workspace/memory/plans/insuro-trend-insight/context-notes.md`
- 체크리스트: `/home/jay/workspace/memory/plans/insuro-trend-insight/checklist.md`
- 에이전트 미팅 기록: `/home/jay/workspace/memory/meetings/2026-04-29-keyword-ranking-redesign.md`

★ 위 3문서를 반드시 읽고 전체 맥락을 파악한 뒤 작업할 것.

## Phase 1 완료 상태 (선행 작업)
- DB 5테이블 생성 완료 (keywords, keyword_trends, keyword_saturation, keyword_rankings, failed_batches)
- keywords 테이블 현재 0건 (keyword_pool_refresh.py 미실행 상태)
- keyword_pool_refresh.py 구현 완료 (시드 30개 → SearchAd 확장 → 2,000개)
- keyword-seeds.json (6카테고리 30개) 완료
- 크론 등록 완료 (매월 1일 03:00)
- DataLab API 키: .env.keys에 NAVER_CLIENT_ID, NAVER_CLIENT_SECRET 등록 완료
- SearchAd API 키: .env.keys에 NAVER_SEARCHAD_CUSTOMER_ID, NAVER_SEARCHAD_API_KEY, NAVER_SEARCHAD_SECRET_KEY 등록 완료

## 한정승인 범위

5팀 팀장이 아래 Phase를 **순차적으로** 진행합니다. 각 Phase 완료 시 중간 보고 없이 다음 Phase로 진행. 전체 완료 후 최종 보고 1회.

---

### Phase 2: 데이터 수집 배치 (체크리스트 1-2, 1-3)

#### 2-1. keyword_pool_refresh.py 실 실행
- SearchAd API로 실제 2,000개 키워드 수집
- keywords 테이블에 INSERT 확인
- Telegram 알림 연동 추가 (cokacdir --sendmsg)

#### 2-2. DataLab 트렌드 수집 스크립트
파일: `server/scripts/daily_trend_collect.py`

- 앵커 키워드 "보험" 고정 포함 (배치: 앵커 + 4개 = 5개/요청)
- keywords 테이블에서 is_active=true인 키워드 로드
- DataLab API (POST https://openapi.naver.com/v1/datalab/search) 호출
  - startDate: 10주 전, endDate: 오늘
  - timeUnit: "week"
  - 배치당 5개 키워드 (앵커 "보험" 포함)
- 응답 상대값을 앵커("보험") 기준으로 정규화
- keyword_trends 테이블에 저장 (period_start, period_end, trend_ratio)
- rate limit: 200ms 간격
- 429 응답 시 1분 대기 후 재시도, 3회 실패 시 failed_batches 기록
- 크론 등록: 매일 06:00

#### 2-3. Blog Search 포화도 수집 스크립트
파일: `server/scripts/daily_saturation_collect.py`

- keywords 테이블에서 is_active=true인 키워드 로드
- Blog Search API (GET https://openapi.naver.com/v1/search/blog.json?query={keyword}&display=1) 호출
- `total` 필드 (총 블로그 발행 수) 추출
- keyword_saturation 테이블에 저장 (total_blog_count, collected_at)
- rate limit: 100ms 간격
- 크론 등록: 매일 06:30

★ SearchAd/DataLab/Blog API 인증: .env.keys에서 로드. 기존 main.py의 _get_naver_search_volume 함수(라인 1921 부근) 인증 로직 참조.
★ DataLab API: Client ID/Secret 사용 (X-Naver-Client-Id, X-Naver-Client-Secret 헤더)
★ Blog Search API: 동일한 Client ID/Secret 사용

---

### Phase 3: 랭킹 산출 + API (체크리스트 1-4, 1-5, 1-7)

#### 3-1. 랭킹 산출 스크립트
파일: `server/scripts/daily_ranking_calc.py`

- 급상승 점수: (최근2주평균 - 이전8주평균) / max(이전8주평균, 1) × 100
- 포화지수: blog_count / max(search_volume, 1) × 10, 클램핑 0~100
- 이슈성 지수: surge × log10(max(search_volume, 10)), 정규화 0~100
- 복합 스코어: 기회도(100-포화)(0.40) + 급상승(0.35) + 이슈성(0.25)
- 변동 판정: surge(+50%↑)/up(+20~49%)/steady(-19~+19%)/down(-20%↓)/new
- 포화 뱃지: blue(0~30)/yellow(30~70)/red(70+)
- 이슈 라벨: stable(<3%)/moderate(3~10%)/volatile(10%+)
- keyword_rankings 테이블에 저장
- 선행 작업 완료 확인 (trend + saturation 수집 완료 여부)
- 크론 등록: 매일 07:00

#### 3-2. 헬스체크 + 알림
파일: `server/scripts/daily_health_check.py`

- 트렌드 수집 건수 1,800 미만 시 알림
- 포화도 수집 건수 1,800 미만 시 알림
- 랭킹 산출 건수 0 시 알림
- 미해결 failed_batches 50건 초과 시 알림
- Telegram 알림 (cokacdir --sendmsg)
- 크론 등록: 매일 07:30

#### 3-3. API 엔드포인트
main.py에 라우터 추가:

- `GET /api/insuro/trend-insight` — 최신 TOP 20 랭킹 (카테고리 필터, 정렬 파라미터)
- `GET /api/insuro/trend-insight/{keyword}` — 개별 키워드 상세 (히스토리, 점수 breakdown)
- `GET /api/insuro/trend-insight/categories` — 카테고리 목록 + 각 건수
- `POST /api/insuro/admin/trend-insight/refresh` — 수동 갱신 트리거 (어드민)

---

### Phase 4: 프론트엔드 UI (체크리스트 2-1 ~ 2-6)

#### 4-1. "트렌드 인사이트" 탭
- KeywordAnalysis.tsx에서 "키워드 순위" TabsTrigger → "트렌드 인사이트" 변경
- TrendInsightTab 컴포넌트 신규 (`src/components/keyword/TrendInsightTab.tsx`)
- TOP 20 카드 리스트 (순위, 등락, 키워드명, 검색량 바, 포화뱃지, 이슈라벨, 7일 스파크라인, [글쓰기] CTA)
- 카테고리 필터 (8개)
- 모바일 반응형 (md 이상: 테이블, md 미만: 카드)

#### 4-2. 안내 페이지
- 상단 안내 배너 (dismiss 가능, localStorage)
- 지표 설명 팝오버 (급상승, 기회도, 이슈성)
- 포화뱃지 클릭 시 설명
- 하단 활용법 3단계 (트렌드 확인 → 기회 발견 → 바로 글쓰기)
- 갱신 시각 표시

#### 4-3. "오늘의 추천" 배너
- 복합 스코어 1위 키워드 자동 선정
- 추천 이유 규칙 기반 자연어 생성
- [글쓰기 →] CTA

#### 4-4. 글쓰기 연결
- /generate 페이지에서 searchParams.keyword 읽어 초기값 세팅
- source=trend-insight 파라미터 전달

#### 4-5. 플랜 차등
- 무료: "마지막 업데이트: 월요일" + "프리미엄은 매일 업데이트" 배지
- 맥스: "마지막 업데이트: 오늘 07:00"

---

### Phase 5: 통합 검증 + 배포 (체크리스트 3-1, 3-2)

- keyword_pool_refresh.py 실행 → 2,000개 확인
- DataLab 수집 → 1,800개+ 성공
- Blog API 수집 → 1,800개+ 성공
- 랭킹 산출 → TOP 20 정상
- [글쓰기] CTA → /generate 프리필 정상
- 안내 배너 dismiss + 재방문 유지
- 모바일 레이아웃 정상
- npm run build 성공
- Cloudflare 배포
- 크론 5개 정상 실행 확인

## affected_files (전체)
- `server/scripts/daily_trend_collect.py` (신규)
- `server/scripts/daily_saturation_collect.py` (신규)
- `server/scripts/daily_ranking_calc.py` (신규)
- `server/scripts/daily_health_check.py` (신규)
- `server/scripts/keyword_pool_refresh.py` (수정 — Telegram 알림 추가)
- `server/main.py` (수정 — trend-insight API 라우터 추가)
- `src/pages/KeywordAnalysis.tsx` (수정 — 탭명 변경)
- `src/components/keyword/TrendInsightTab.tsx` (신규)
- 서브 컴포넌트 다수 (신규)

## 검증 시나리오
- 위 Phase 5 참조