# plan-task-136.1: InsuWiki YouTube 파이프라인 버그 4건 수정

## 작업 개요
- 작업 ID: task-136.1
- 팀: dev3-team (라 팀장 + GLM-5)
- 대상 파일: `/home/jay/projects/insuwiki/functions/src/crawlYoutubeChannels.ts`
- 목표: 잔여 버그 4건 수정

---

## 서브태스크 분해

### Bug 1: findNearest 에러 처리 (담당: GLM-5)
- 위치: crawlYoutubeChannels.ts 491-512행
- 현상: `.where().findNearest({...}).get()` 체이닝 시 TypeScript 타입 오류
  (Firestore Admin SDK에서 `where()`는 `Query`를 반환하나 `findNearest`는 `CollectionReference`에만 존재)
- 수정 방향: findNearest를 직접 CollectionReference에 호출하고, where 조건은 결과 필터링으로 처리하거나,
  에러 시 더 명확한 로그와 함께 graceful degradation 보장

### Bug 2: conflictDetail undefined (담당: GLM-5)
- 위치: crawlYoutubeChannels.ts 543행
- 현상: `conflictDetail: conflictDetail || undefined` — Firestore Admin SDK에
  `undefined` 값을 document field로 전달 시 "Unsupported value type: undefined" 에러 발생 가능
- 수정 방향: `conflictDetail`이 빈 문자열일 때는 필드 자체를 제외하는 방식으로 수정
  (conditional spread 또는 `delete` 패턴 사용)

### Bug 3: 환경변수명 fallback (담당: GLM-5)
- 위치: crawlYoutubeChannels.ts 346-348행, 357-362행
- 현상: Drive OAuth2 인증에 필요한 `DRIVE_CLIENT_ID`, `DRIVE_CLIENT_SECRET`, `DRIVE_REFRESH_TOKEN`이
  필수 환경변수 검증 블록에 포함되지 않아 런타임 에러가 발생해도 감지 불가
- 수정 방향: 초기 환경변수 검증 블록에 Drive 관련 변수 추가, 없을 시 early return

### Bug 4: secrets 배열 추가 (담당: GLM-5)
- 위치: crawlYoutubeChannels.ts 319행
- 현상: Cloud Functions `secrets` 설정에 `GEMINI_API_KEY`, `YOUTUBE_API_KEY`만 등록됨
  `DRIVE_CLIENT_ID`, `DRIVE_CLIENT_SECRET`, `DRIVE_REFRESH_TOKEN`이 누락 → 런타임에 undefined
- 수정 방향: `secrets` 배열에 Drive 관련 3개 시크릿 추가

---

## 팀원 배정
- GLM-5 (오픈클로): 위 4건 모두 단독 순차 처리
- 라 팀장: 결과 검토 및 셀프 QC

## 실행 순서
1. Bug 4 수정 (secrets 배열) — 가장 기초, 다른 버그와 독립
2. Bug 3 수정 (환경변수 검증) — 4 수정 후 자연스럽게 이어짐
3. Bug 1 수정 (findNearest 에러 처리) — 로직 수정
4. Bug 2 수정 (conflictDetail undefined) — 마지막 document 저장 수정
5. TypeScript 빌드 검증 (`npx tsc --noEmit`)
6. glm-checklist.py 실행

---

## 예상 위험 및 대안

### 위험 1: findNearest API 시그니처 변경
- Firestore Admin SDK 버전마다 `findNearest` 파라미터 형식이 다를 수 있음
- 대안: 기존 `.where().findNearest()` 구조를 유지하되 타입 캐스팅으로 해결하거나,
  `findNearest` 전 CollectionReference에서 직접 호출

### 위험 2: conditional spread로 Firestore 타입 충돌
- `...(conflictDetail ? { conflictDetail } : {})` 패턴이 Firestore 타입과 충돌 가능
- 대안: 조건부 필드 객체를 미리 구성하거나 `FieldValue.delete()` 사용

### 위험 3: secrets 추가 후 로컬 에뮬레이터 영향
- 로컬에서 해당 secrets가 없으면 에뮬레이터 실행 실패 가능
- 대안: 검증 블록에 `NODE_ENV === 'development'` 예외 처리 고려

---

## 실패 시나리오 체크리스트

1. **비정상 입력/상태**
   - `findNearest`에 잘못된 차원의 임베딩 벡터가 전달될 경우: try-catch로 감지하여 스킵 처리 필요
   - `conflictDetail`이 null이 아닌 NaN/object 등 비정상값일 경우: string 타입 강제 변환 고려

2. **동시성/경쟁 조건**
   - 해당 없음: 단일 Cloud Function 내 순차 실행이므로 공유 자원 경합 없음
   - 단, 동일 비디오를 두 런이 동시 처리 시 중복 저장 가능 — 기존 `existing` 체크가 방어하나 완전하지 않음

3. **비정상 종료/타임아웃**
   - 수정 중 Cloud Function 타임아웃(540s) 초과 시 secrets/env 수정 후 재배포로 복구 가능
   - `conflictDetail undefined` 에러로 Firestore 쓰기 실패 시, 처리된 비디오가 `youtube_knowledge`에 미저장될 위험 있음

4. **스테일 데이터**
   - Drive credentials (refresh_token 만료) 시 Drive 업로드 전체 실패 가능
   - 해당 없음: secrets 배열 추가는 메타데이터 수정이며 데이터 TTL 영향 없음

5. **통합 시 충돌**
   - `crawlYoutubeChannels.ts`만 수정: index.ts에서 re-export되므로 다른 파일 영향 없음
   - `secrets` 배열 변경은 Cloud Functions 배포 시 Secret Manager IAM 권한 필요 (배포 담당자 확인 필요)
