# InsuWiki 하이브리드 RAG 아키텍처 (대안 F) 마스터 플랜

## ⚠️ 2026-02-25 설계 확장 결정 (ADR-260225-B 참고)

Option F에 **질의 유형 분류기(Query Router)** 레이어를 추가 확장하기로 결정.

```
설계사 질문 → [규칙 기반 분류기 → 불명확 시 Gemini Flash]
    ├── 유형 A (수치 조회형) → Firestore 구조화 쿼리 (insurance_tables)
    ├── 유형 B (횡단 검색형) → Vector RAG (insurance_chunks)
    └── 유형 C (심층 분석형) → Long-Context Cloud Functions (현행 Option F)
```

- **Spec 문서**: `docs/specs/260225-Insuwiki-rag-spec-update.md` ✅ 확정
- **ADR**: `docs/decisions/260225-rag-query-router-architecture.md`

---

## 1. 개요 및 목적
- **목표**: 3대 한계(비용 폭탄, 타임아웃, 보안/캐시 누락)를 모두 극복하고 실전 배포 가능한 완벽한 InsuWiki AI 검색 시스템 구축.
- **핵심 사상**: **"데이터 특성에 따른 다원화 파이프라인(Hybrid) + 엄격한 비용/에러 통제"**

## 2. 데이터 흐름(Data Flow) 및 파이프라인

### 2.1 위키 본문/소식지 (경량 Text)
- **저장소**: InsuWiki Firestore (Markdown 원본)
- **파이프라인**: Dify.ai API 연동 또는 Firestore 내장 Vector Search.
- **특징**: 빠르고 저렴한 전통적 RAG 방식.

### 2.2 보험료 표 (정밀 Table)
- **과제**: "1원의 오차도 허용되어서는 안 됨"
- **조치 1 (Phase 0 선행 검증)**: 수동 PoC 선행. (생보사, 손보사, 변액/특약 등 최악의 레이아웃 3종 샘플). 정확도 0% 오차 통과 시에만 자동화 진행.
- **파이프라인 (자동 통과 시)**: 
  - (Drive 업로드) -> (Cloud Functions에서 페이지별 이미지 추출) -> (Gemini Vision API 추출) -> (JSON 변환) -> (Firestore `insurance_tables` 적재)
- **파이프라인 (실패 시 Plan B)**:
  - (수동 엑셀 타이핑) -> (Google Sheets) -> (Cloud Functions 동기화) -> (Firestore `insurance_tables` 적재)
- **조회 방식**: 사용자 질문 시 Firestore 직접 조건 쿼리로 100% 무결점 조회.

### 2.3 약관 PDF 본문 (초대용량 Document)
- **과제**: "10초 타임아웃, 보안, 좀비 캐시 방어"
- **저장소**: Google Drive (원본 유지)
- **인덱싱**: 파일 업로드 시 기본 메타데이터(회사명/상품명/연도)만 Firestore에 경량 저장.
- **데이터 흐름 (검색 및 질의)**:
  1. (UX 통제): 사용자가 UI에서 먼저 (회사/상품)을 특정하여 대상 PDF를 1개로 선별.
  2. (프론트 요청): 사용자가 질문 시, 프론트엔드는 Vercel API에 "이 상품 약관에 대해 물어봐줘" 요청.
  3. (비동기 중계): Vercel API는 즉시 `jobId`를 발급하고 1초 내에 프론트와 접속 끊음(타임아웃 회피). 프론트는 3~5초 단위로 이 `jobId` 상태를 Polling(HTTP REST) 조회. (연결 유지 비용 방어).
  4. (백엔드 처리): 뒤에서 **Firebase Cloud Functions 2세대(Blaze 플랜, 타임아웃 9분 확보)** 워커가 `jobId`를 물고 가동. 안전한 서버 환경 변수에서 Gemini API Key 꺼냄.
  5. (캐시 체크): Firestore `gemini_file_cache` 조회. 동일 PDF의 살아있는 `file_id`가 있으면 (6)번 생략.
  6. (업로드): Drive에서 PDF 다운 -> Gemini File API 업로드 -> 받은 `file_id`를 Firestore에 캐싱 (`expiresAt: 현재 + 48시간`).
  7. (추론): 롱 컨텍스트 활용, `file_id` 와 사용자 프롬프트를 Gemini 1.5 Pro 에 던져 답변 생성.
  8. (결과 저장): Firestore `job` 문서에 `result: "답변내용"`, `status: "complete"` 업데이트.

## 3. 리스크 통제 및 에러 방어(Fail-Safes) 체계

### 3.1 타임아웃 및 무한 로딩 방어
- 프론트엔드는 `job` 문서 상태(`pending/complete/failed`)를 Polling 하되, **최대 3분 초과 시 즉시 로컬 에러(Timeout) 처리** (`failed` 간주) 및 사용자 에러 알림 제공.
- Cloud Functions 워커는 `try/catch` 블록으로 에러 발생 시 즉시 `job` 상태를 `failed`로 기록.

### 3.2 고아(Orphan) 좀비 Job 방어
- Cloud Functions 2세대의 9분 타임아웃 조차 초과하여 앱이 뻗거나 강제 종료되어 `failed` 기록조차 안 되는 극단적 상황 대비.
- Firestore `job` 컬렉션에 **10분 TTL 정책 설정**. 생성 후 10분경과 시 구글 인프라가 찌꺼기 문서를 흔적 없이 강제 완전 삭제(소각). 프론트는 3분 로컬 타임아웃으로 빠져나갔고, DB 잔류 데이터도 없는 완벽한 클린업.

### 3.3 무결성 파괴 (좀비 캐시) 방어
- 48시간 캐싱의 빈틈 방어. 약관이 업데이트(Drive에 덮어쓰기)될 경우 동기화 트리거 혹은 Webhook 발동.
- 즉시 Firestore의 매칭되는 `gemini_file_cache` 문서를 100% 강제 삭제(Cache Invalidation). 다음 질문 시 낡은 좀비 캐시 없이 최신 원본 다시 업로드 보장.

### 3.4 API 한도 및 통신 비용 방어
- (Client) 실시간 소켓(`onSnapshot`)을 버리고 Polling 주기를 3~5초로 대체하여 엄청난 비용 절감 및 무한 대기 연결 끊김 스파이크 차단.
- (Server) Cloud Functions 전환(Blaze 요금제 필수)에 대한 과금 리스크 인지. 200만 회 기본 무료 호출 규모를 신뢰하여 서버리스 한계 극복.
