# task-161.1 완료 보고서 — 약관AI Phase 2: 인프라 고도화 + 모니터링

**팀:** dev2-team (오딘 팀장)
**담당:** 토르(백엔드), 헤임달(테스트), 마아트(QC)
**완료일:** 2026-03-03

---

## 작업 내용

### 작업 1: Blue-Green 재인덱싱
현재 재인덱싱 시 기존 chunks 삭제 → 새 chunks 생성 사이 검색 공백 문제를 해결합니다.

- **reindex/route.ts 수정**: insurance_metadata 조회를 where 쿼리로 전환 (Phase 1 스키마 대응), job 생성 시 `blueGreenMode: true` + `targetCollection: 'insurance_chunks_staging'` 추가, 기존 staging 잔여 데이터 자동 정리
- **switch/route.ts 신규 생성**: POST /api/admin/insurance/reindex/switch — staging → production 원자적 스위칭. 기존 production 청크를 archive(7일 보관)로 이동 → staging을 production으로 승격 → staging 삭제. 전 과정 Firestore 배치(400개 제한) 준수
- **pdfIndexing.ts 수정**: `blueGreenMode` 분기 추가 — true이면 staging 컬렉션에 저장, false이면 기존 로직 유지 (하위 호환). 청킹 함수(structureAwareChunk 등) 일절 미수정

### 작업 2: 비용 모니터링
- **costMonitor.ts 신규 생성**: `api_usage_daily` 컬렉션에 Firestore 읽기/쓰기, Gemini 임베딩/생성 API 호출 횟수 + 예상 비용 원자적 추적 (FieldValue.increment). 시간대별 쿼리 카운트 기록. 일일/주간/월간 사용량 조회. 쿼리당 비용 추정 (캐시 히트/미스 분기)
- **alerting.ts 신규 생성**: 일일 비용 $5 초과 경고, 일일 쿼리 5000건 초과 경고, 시간당 쿼리 3배 급증 이상 트래픽 감지. division by zero 방지 처리
- **monitoring/route.ts 신규 생성**: GET /api/admin/monitoring?period=daily|weekly|monthly&date=YYYY-MM-DD — 어드민 인증 + 사용량/경고 통합 응답 (Promise.all 병렬 실행)

### 작업 3: 재인덱싱 이력 강화
- **history/route.ts 수정**: index_logs 컬렉션 조회 추가, 버전별 diff 정보(이전 청크 수, 청크 변화량, 추가/삭제 조항 수), 인덱싱 품질 지표(평균 청크 크기, 단서조항 보존율, Blue-Green 스위칭 시각) 응답에 포함
- **indexLogger.ts 신규 생성**: 인덱싱 완료 시 호출할 로깅 유틸리티. 평균 청크 크기, 단서조항 보존율(8개 키워드), 조항 수("제N조" 패턴), 추가/삭제 조항 비례 추정 계산 후 index_logs에 저장

### 타입 및 컬렉션 추가
- **firestore.ts 수정**: InsuranceChunkArchive, IndexLog, ApiUsageDaily 타입 추가. COLLECTIONS에 INSURANCE_CHUNKS_STAGING, INSURANCE_CHUNKS_ARCHIVE, INDEX_LOGS, API_USAGE_DAILY 등록

---

## 생성/수정 파일 목록

### 신규 생성 (5개)
- `nextapp/src/app/api/admin/insurance/reindex/switch/route.ts` — Blue-Green 스위칭 API (113줄)
- `nextapp/src/lib/monitoring/costMonitor.ts` — 비용 모니터링 (237줄)
- `nextapp/src/lib/monitoring/alerting.ts` — 경고 시스템 (133줄)
- `nextapp/src/app/api/admin/monitoring/route.ts` — 모니터링 API (96줄)
- `nextapp/src/lib/monitoring/indexLogger.ts` — 인덱싱 로그 (132줄)

### 수정 (4개)
- `nextapp/src/app/api/admin/insurance/reindex/route.ts` — Blue-Green 모드 적용 (88줄)
- `functions/src/pdfIndexing.ts` — Blue-Green 컬렉션 분기 (885줄)
- `nextapp/src/app/api/admin/insurance/terms/[productId]/history/route.ts` — 이력 강화 (114줄)
- `nextapp/src/types/firestore.ts` — 신규 타입/컬렉션 추가 (492줄)

### 테스트 파일 (3개)
- `nextapp/src/lib/monitoring/__tests__/costMonitor.test.ts` (361줄)
- `nextapp/src/lib/monitoring/__tests__/alerting.test.ts` (238줄)
- `nextapp/src/lib/monitoring/__tests__/indexLogger.test.ts` (331줄)

---

## 테스트 결과

### 헤임달 테스트 (1차)
- TypeScript 컴파일 (nextapp): Phase 2 대상 에러 2건 발견 → 즉시 수정 (암묵적 any 타입)
- TypeScript 컴파일 (functions): 에러 0건
- Vitest 단위 테스트: **54/54 PASS** (241ms)
  - costMonitor.test.ts: 22 PASS
  - alerting.test.ts: 14 PASS
  - indexLogger.test.ts: 18 PASS
- 코드 리뷰 검증: A~I 전 항목 (30개 이상) 모두 PASS

### 마아트 QC (독립 재검증)
- Vitest 재실행: **54/54 PASS** (241ms) — 헤임달 보고와 완전 일치
- TypeScript 컴파일: 에러 0건 (nextapp, functions 양쪽 확인)
- 파일 경로/존재: 12개 파일 전부 정상
- 작업 지시서 체크리스트: 전 항목 구현 확인
- 주의사항 준수: vector-search 미수정, 청킹 로직 미수정 확인
- 경미한 이슈 1건 발견: firestore.ts ApiUsageDaily 필드명 불일치 → **즉시 수정 완료** (queryCount→queryCalls, cacheHitCount→cacheHits, cacheMissCount→cacheMisses)
- **종합 판정: APPROVED**

---

## 버그 유무

- 마아트가 발견한 firestore.ts 필드명 불일치 → 즉시 수정 완료
- 그 외 버그 없음

---

## 주의사항

- `insurance_chunks_staging`, `insurance_chunks_archive`, `index_logs`, `api_usage_daily` 컬렉션은 Firestore Rules에 서버 전용 규칙 추가 필요 (후속 작업)
- `insurance_chunks_archive`에 Firestore TTL 정책 설정 필요 (`archiveExpireAt` 필드 기준 7일 후 자동 삭제)
- `indexLogger.logIndexingResult()`는 pdfIndexing.ts Cloud Function에서 직접 호출하기엔 경로 차이(nextapp vs functions)가 있으므로, functions에서 별도 구현하거나 공유 패키지화 필요 (후속 작업)
- 1팀이 작업 중인 vector-search/route.ts, answerValidator.ts는 일절 미수정
- pdfIndexing.ts의 청킹 로직(structureAwareChunk 등)은 일절 미수정

---

## 비고

- Blue-Green 스위칭 중 기존 production 컬렉션은 온전히 유지되므로 검색 공백 없음
- costMonitor의 trackApiUsage는 다른 API 핸들러에서 `import { trackApiUsage } from '@/lib/monitoring/costMonitor'`로 호출하여 사용
- 비용 상수: Firestore 읽기 $0.036/100K, 쓰기 $0.108/100K, Gemini Embedding $0.001/1K tokens, Gemini Generation $0.0075/1K tokens
