# task-2133: InsuRo 구글 트렌드 데이터 파이프라인 구축 (Phase 1 MVP)

## ★ 프로젝트: `/home/jay/projects/InsuRo/`

## 배경
현재 pytrends 실시간 호출 → Google 429 rate limit 반복 발생.
에이전트 미팅(19명, 2026-04-23) 전원 합의로 B안(Cron 데이터 파이프라인) 채택.
미팅 기록: `/home/jay/workspace/memory/meetings/2026-04-23-google-trends-architecture.md`

## 아키텍처 (3레이어)

```
[수집 레이어] systemd timer → pytrends 배치 수집 (매일 새벽 4시)
     ↓
[저장 레이어] Supabase PostgreSQL (trend_keywords + trend_data + trend_collection_runs)
     ↓
[서비스 레이어] FastAPI 엔드포인트 → 프론트엔드 Recharts 차트
```

## Phase 로드맵

### Phase 1 (이번 작업 — MVP)
- 고정 키워드 30개로 매일 새벽 수집
- Supabase에 저장
- 기존 `/api/insuro/google-trends` 엔드포인트를 DB 캐시 우선 조회로 수정
- 프론트엔드 차트 DB 데이터 기반으로 전환

### Phase 2 (향후)
- 카테고리별 그룹핑 (생명/손해/연금/건강/자동차)
- 키워드 관리 UI
- "보험 날씨 지도" (지역별 히트맵)

### Phase 3 (향후)
- 설계사 실제 검색 키워드를 24시간 로그로 수집
- Top 100 자동 추출 → 일일 트렌드 리프레시
- 유료 API(SerpAPI) 전환 대비 Collector 인터페이스 추상화

## 작업 상세

### T1: DB 스키마 (Supabase 마이그레이션)

```sql
-- trend_keywords: 수집 대상 키워드 관리
CREATE TABLE trend_keywords (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  keyword TEXT NOT NULL UNIQUE,
  category TEXT NOT NULL DEFAULT 'general',
  is_active BOOLEAN DEFAULT true,
  priority INT DEFAULT 0,
  created_at TIMESTAMPTZ DEFAULT now()
);

-- trend_data: 시계열 트렌드 데이터
CREATE TABLE trend_data (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  keyword_id UUID REFERENCES trend_keywords(id),
  region TEXT DEFAULT 'KR',
  date DATE NOT NULL,
  value INT NOT NULL CHECK (value >= 0 AND value <= 100),
  source TEXT DEFAULT 'pytrends',
  collected_at TIMESTAMPTZ DEFAULT now(),
  UNIQUE(keyword_id, date, region)
);

-- trend_collection_runs: 수집 실행 이력
CREATE TABLE trend_collection_runs (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  started_at TIMESTAMPTZ NOT NULL,
  finished_at TIMESTAMPTZ,
  status TEXT DEFAULT 'running',
  keywords_count INT DEFAULT 0,
  success_count INT DEFAULT 0,
  error_count INT DEFAULT 0,
  errors JSONB DEFAULT '[]',
  created_at TIMESTAMPTZ DEFAULT now()
);

-- 인덱스
CREATE INDEX idx_trend_data_keyword_date ON trend_data(keyword_id, date);
CREATE INDEX idx_trend_data_date ON trend_data(date);

-- RLS 정책
ALTER TABLE trend_data ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Public read" ON trend_data FOR SELECT USING (true);
ALTER TABLE trend_keywords ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Public read" ON trend_keywords FOR SELECT USING (true);
```

### T1-seed: 초기 키워드 30개 삽입

보험 상품 카테고리별 대표 키워드:

**생명 (4)**: 암보험, 종신보험, 정기보험, 사망보험
**건강 (5)**: 실비보험, 실손보험, 치아보험, 간병보험, 치매보험
**손해 (3)**: 자동차보험, 운전자보험, 화재보험
**연금/저축 (5)**: 연금보험, 연금저축, IRP, ISA, 변액보험
**특수 (3)**: 어린이보험, 태아보험, 펫보험
**행동 (10)**: 보험비교, 보험료계산, 보험청구, 보험해약, 보험리모델링, 보험설계사, 보험상담, 보험추천, 보험가입, 보험료

### T2: 수집기 (Cron Worker)

별도 Python 스크립트 `server/trend_collector.py`:

```python
# 핵심 로직
1. Supabase에서 active 키워드 목록 조회
2. trend_collection_runs에 실행 시작 기록
3. 키워드별 순차 수집 (랜덤 딜레이 30~60초)
   - pytrends.build_payload([keyword], timeframe='today 12-m', geo='KR')
   - interest_over_time() → trend_data에 UPSERT
   - related_queries() → 별도 저장 (선택)
4. 수집 완료 → collection_runs 상태 업데이트
5. 실패 시 → 해당 키워드 스킵 + 에러 로깅
6. 전체 실패 3회 연속 → Telegram 알림 (cokacdir --sendfile)
```

systemd 유닛:
```ini
# /home/jay/.config/systemd/user/insuro-trend-collector.service
[Unit]
Description=InsuRo Google Trends Collector

[Service]
Type=oneshot
WorkingDirectory=/home/jay/projects/InsuRo/server
ExecStart=/usr/bin/python3 trend_collector.py
EnvironmentFile=/home/jay/projects/InsuRo/.env

# /home/jay/.config/systemd/user/insuro-trend-collector.timer
[Unit]
Description=Daily Google Trends Collection

[Timer]
OnCalendar=*-*-* 04:00:00
Persistent=true

[Install]
WantedBy=timers.target
```

### T3: API 수정 (server/main.py)

기존 `/api/insuro/google-trends` 엔드포인트 수정:
```
현재: pytrends 실시간 호출 → 429 에러
수정 후: 
  1. DB 캐시 먼저 조회 (trend_data 테이블)
  2. 캐시 있음 → 즉시 반환 (< 50ms)
  3. 캐시 없음 (미수집 키워드) → "수집 대상에 없는 키워드" 안내
```

응답 형식 유지 (기존 프론트엔드 호환):
```json
{
  "status": "ok",
  "keyword": "실비보험",
  "timeline": [{"date": "2025-04-20", "value": 45}, ...],
  "related_queries": {"top": [...], "rising": [...]},
  "last_updated": "2026-04-23T04:00:00Z",
  "source": "cache"
}
```

### T4: 프론트엔드 수정 (KeywordAnalysis.tsx 구글 트렌드 탭)

- 키워드 입력: 자유 입력 → **Combobox 자동완성** (수집된 키워드 목록에서 선택)
- 키워드 비교: 최대 3개 멀티셀렉트 + 컬러 코딩
- 기간 선택: 프리셋 버튼 (7일/30일/90일/1년)
- 기본 뷰: "인기 키워드 TOP 5" (value 기준)
- 갱신 안내: "최종 업데이트: YYYY-MM-DD HH:MM" 상시 표시
- 차트: Recharts 유지 (ResponsiveContainer로 모바일 대응)
- 사용률 측정: 탭 진입/키워드 선택 이벤트 로깅 (PostHog 또는 Supabase)

## ★ 먼저 읽을 파일
- `/home/jay/projects/InsuRo/server/main.py` — L896~964 (기존 google_trends_proxy)
- `/home/jay/projects/InsuRo/src/pages/KeywordAnalysis.tsx` — 구글 트렌드 탭
- `/home/jay/workspace/memory/meetings/2026-04-23-google-trends-architecture.md` — 미팅 합의

## 검증 시나리오 (이게 되면 성공)

### 시나리오 1: 수집기 동작
```bash
cd /home/jay/projects/InsuRo/server && python3 trend_collector.py
```
→ 30개 키워드 수집 완료, trend_data에 데이터 적재, collection_runs에 이력 기록

### 시나리오 2: API 캐시 응답
```bash
curl -s -X POST http://localhost:8001/api/insuro/google-trends \
  -H "Authorization: Bearer <JWT>" \
  -H "Content-Type: application/json" \
  -d '{"keyword":"실비보험"}'
```
→ DB 캐시 데이터 반환, `source: "cache"`, 응답 < 100ms

### 시나리오 3: 프론트엔드 차트
insuro.biz → AI 키워드 분석 → 구글 트렌드 탭 → Combobox에서 "실비보험" 선택 → 차트 표시

### 시나리오 4: systemd timer
```bash
systemctl --user enable insuro-trend-collector.timer
systemctl --user start insuro-trend-collector.timer
systemctl --user list-timers | grep trend
```

### 시나리오 5: 미수집 키워드 안내
Combobox에 없는 키워드 → "수집 대상에 없는 키워드입니다" 표시

## 완료 시그니처
- DB 3테이블 생성 + 키워드 30개 시드
- 수집기 1회 실행 성공 (30개 키워드 데이터 적재)
- systemd timer 등록 (매일 04:00)
- API 캐시 응답 < 100ms
- 프론트엔드 Combobox + 차트 표시
- 429 에러 완전 해소
- insuro.biz에서 구글 트렌드 탭 정상 동작 스크린샷

## 레벨
- critical (Lv.4)

## 프로젝트
- insuro
