docs: pipeline improvement plan with 15 work packages and verification checklist

Comprehensive audit of discover→collect→generate pipeline found:
- 16 silent failures, 8 data quality issues, 0 error recovery, 6 API issues
- Organized into 4 sprints (15 WPs, ~11h total)
- Each WP has file locations, changes, and verification criteria
- Checkbox format for progress tracking

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
claude/bold-hawking
Haewon Kam 2026-04-04 23:26:22 +09:00
parent 29c1faf49e
commit 1071328574
1 changed files with 150 additions and 0 deletions

View File

@ -0,0 +1,150 @@
# 검색/분석 파이프라인 종합 개선 계획
**작성일**: 2026-04-04
**상태**: 계획 완료, 구현 대기
## Context
현재 파이프라인의 3-phase 아키텍처(discover → collect → generate)는 구조적으로는 괜찮으나, **실행 신뢰성**에 심각한 문제가 있음. 3개 병렬 코드 탐색 결과:
- **Silent failure 16건**: 모든 catch 블록이 에러를 삼킴
- **데이터 품질 8건**: 잘못된 URL, 동명이인 병원, 평점 스케일 혼동
- **에러 복구 0건**: 재시도 로직 없음, 새로고침 시 데이터 유실
- **API 불안정 6건**: 타임아웃, 쿼터 소진, 인증 실패 미감지
**목표**: 검색 정확도 + 에러 회복력 + UX 투명성을 대폭 개선
---
## 진행 상태 체크리스트
### Sprint 1: 데이터 품질 Quick Wins (~2.5h)
- [ ] **WP-1**. YouTube Channel ID 정규식 수정 (20min)
- 파일: `discover-channels/index.ts`, `verifyHandles.ts`
- 변경: `/^UC[a-zA-Z0-9_-]{20,}$/``/^UC[a-zA-Z0-9_-]{22}$/`
- 검증: 24자가 아닌 channel ID가 reject되는지 확인
- [ ] **WP-2**. Naver Place 동명이인 방지 (30min)
- 파일: `enrich-channels/index.ts` lines 319-343
- 변경: 카테고리 필터링 (성형/피부) + 검색어에 "성형외과" 추가
- 검증: "아이디병원" 검색 → "아이디마곡치과" 아닌 성형외과 반환
- [ ] **WP-3**. Google Maps URL 수정 (20min)
- 파일: `collect-channel-data/index.ts`, `enrich-channels/index.ts`
- 변경: `place.website`(병원 사이트) 대신 `maps.google.com/search` URL
- 검증: 기타 채널의 구글 지도 링크가 Google Maps로 이동
- [ ] **WP-4**. Naver Blog 공식 블로그 분리 (30min)
- 파일: `collect-channel-data/index.ts`
- 변경: verified_channels 핸들로 `blog.naver.com/{handle}` 생성, 검색 결과는 `blogMentions`
- 검증: 네이버 블로그 링크가 공식 블로그로 이동
- [ ] **WP-5**. 강남언니 평점 정규화 (30min)
- 파일: `collect-channel-data/index.ts`, `enrich-channels/index.ts`
- 변경: `rawRating` + `normalizedRating` 분리, ≤5.0이면 ×2
- 검증: 강남언니 평점이 `/10`으로 일관되게 표시
- [ ] **WP-6**. Perplexity 모델 상수화 (20min)
- 파일: 새 `_shared/config.ts`
- 변경: 환경변수 `PERPLEXITY_MODEL` 또는 기본값 `"sonar"`
- 검증: 모든 Edge Function에서 하드코딩 `"sonar"` 제거됨
- [ ] **WP-7**. Apify 타임아웃 증가 (10min)
- 파일: `discover-channels/index.ts`
- 변경: `waitForFinish=30``waitForFinish=45`
- 검증: Instagram 프로필 스크래핑 성공률 향상
---
### Sprint 2: 에러 가시성 (~2.25h)
- [ ] **WP-8**. 채널 수집 에러 추적 ⭐ 핵심 (1.5h)
- 파일: `collect-channel-data/index.ts`
- DB: `ALTER TABLE marketing_reports ADD COLUMN IF NOT EXISTS channel_errors JSONB DEFAULT '{}';`
- 변경:
- [ ] HTTP 상태 코드 체크 (429, 403, 500)
- [ ] `Promise.allSettled` 결과 순회 → `channelErrors` 기록
- [ ] 부분 성공이어도 항상 DB 저장 (unconditional save)
- [ ] status: `"collected"` vs `"partial"` vs `"collection_failed"`
- [ ] 응답: `{ channelData, channelErrors, partialFailure }`
- 검증: API 토큰 무효화 시 에러가 기록되는지 확인
- [ ] **WP-9**. Instagram/Facebook 검증 개선 (45min)
- 파일: `_shared/verifyHandles.ts`
- 변경:
- [ ] `verified` 타입: `boolean | "unverifiable"`
- [ ] Instagram: 로그인 리다이렉트 감지
- [ ] Facebook: HEAD → GET, 실패 시 `"unverifiable"`
- [ ] `collect-channel-data`에서 `"unverifiable"` 포함
- 검증: Facebook 핸들이 "unverifiable"로 표시되고 수집은 시도됨
---
### Sprint 3: 에러 회복 (~5.25h)
- [ ] **WP-10**. API 재시도 유틸리티 (2h)
- 파일: 새 `_shared/retry.ts`
- 변경: `fetchWithRetry()` — 지수 백오프, 429 존중, AbortController 타임아웃
- 검증: 429 응답 시 자동 재시도 후 성공
- [ ] **WP-11**. 부분 실패 복구 (1h)
- 파일: `collect-channel-data/index.ts`
- 변경: `Promise.allSettled` 직후 무조건 중간 DB 저장
- 검증: 일부 채널 실패해도 나머지 데이터 보존
- [ ] **WP-12**. 파이프라인 이어하기 (1.5h)
- 파일: `AnalysisLoadingPage.tsx`, `supabase.ts`
- 변경:
- [ ] `sessionStorage`에 reportId 저장
- [ ] URL에 reportId 포함
- [ ] DB status 폴링
- [ ] status별 이어하기 로직
- 검증: 분석 중 새로고침 → 이어서 진행
- [ ] **WP-13**. Enrichment 재시도 버튼 (45min)
- 파일: `useEnrichment.ts`, `EmptyState.tsx`
- 변경: `retry()` 함수 + "다시 시도" 버튼 (최대 2회)
- 검증: Enrichment 실패 후 버튼 클릭 → 재시도 성공
---
### Sprint 4: UX 마무리 (~50min)
- [ ] **WP-14**. EmptyState 상태별 UI (20min)
- 파일: `EmptyState.tsx`
- 변경: `loading | error | not_found` 상태별 다른 UI
- 검증: 각 상태에 맞는 아이콘/메시지/버튼 표시
- [ ] **WP-15**. Firecrawl Rate Limiting (30min)
- 파일: `_shared/retry.ts`에 추가
- 변경: 도메인별 500ms 간격 강제
- 검증: Firecrawl 429 에러 발생 안 함
---
## 핵심 파일 목록
| 파일 | Sprint | 설명 |
|------|--------|------|
| `supabase/functions/discover-channels/index.ts` | 1 | 채널 발견 |
| `supabase/functions/collect-channel-data/index.ts` | 1, 2, 3 | 데이터 수집 |
| `supabase/functions/enrich-channels/index.ts` | 1 | 레거시 enrichment |
| `supabase/functions/generate-report/index.ts` | - | 리포트 생성 (수정 없음) |
| `supabase/functions/_shared/verifyHandles.ts` | 1, 2 | 핸들 검증 |
| `supabase/functions/_shared/config.ts` (신규) | 1 | 공유 설정 |
| `supabase/functions/_shared/retry.ts` (신규) | 3 | 재시도 유틸 |
| `supabase/migrations/20260404_channel_errors.sql` (신규) | 2 | DB 마이그레이션 |
| `src/pages/AnalysisLoadingPage.tsx` | 3 | 로딩 페이지 |
| `src/hooks/useEnrichment.ts` | 3 | Enrichment 훅 |
| `src/components/report/ui/EmptyState.tsx` | 4 | 빈 상태 UI |
| `src/lib/supabase.ts` | 3 | API 클라이언트 |
## 총 예상 소요 시간
| Sprint | 시간 | 배포 범위 |
|--------|------|---------|
| Sprint 1: Quick Wins | ~2.5h | Edge Functions × 3 |
| Sprint 2: 에러 가시성 | ~2.25h | DB + Edge Functions |
| Sprint 3: 에러 회복 | ~5.25h | Edge Functions + Frontend + Vercel |
| Sprint 4: UX 마무리 | ~50min | Frontend + Vercel |
| **합계** | **~11h** | |