본문으로 건너뛰기

Platform RAG 일상 운영 (ADR 0021)

전 tenant 공용 판례·법령 RAG (publicDocuments) 의 수집·임베딩·재처리·장애 대응 절차. ADR 0021 + architecture/platform-rag.md 가 SSoT, 본 문서는 운영 측 절차.

1. 데이터 흐름 (한 그림)

법제처 OPEN API

├── 매일 02:00 KST: scheduledFetchLawGoKr (Cloud Scheduler)
├── ops 수동: fetchAndIngestLawGoKr (단건 / 벌크)
└── 스크립트: download-law-go-kr-bulk.ts → upload-public-raw-to-firestore.ts


publicDocumentsRaw (원본 보존, masterAdmin 만 read, Admin SDK only write)
│ (linkedPublicDocId 양방향)

publicDocuments (인증 tenant read, masterAdmin write)


onPublicDocumentCreated trigger (Cloud Function)

├── prepareEmbedInput (정제, tenant RAG 와 동일)
├── Vertex AI text-embedding-004 (768-dim)
└── meanPoolVectors (다중 chunk 평균)


publicDocuments.embedding {version, dims, vector, generatedAtIso, chunkCount}

2. 일상 모니터링

2.1 매일 09:00 KST

Firebase Console → Firestore → publicDocuments:

  • 어제(02:00 KST 기준) 신규 문서 +30 ± 변동 = 정상 (core 21 카테고리 × page 1 × display 20 = 최대 420 후보, 멱등 skip 후 30 내외)
  • 0 건 = scheduler 실패 의심 (§4 절차)

2.2 임베딩 누락 점검

# 임베딩 안 된 문서 (embeddedAt: null)
firebase firestore:export \
--project <projectId> \
--collection-ids publicDocuments \
| jq '[.[] | select(.embeddedAt == null)] | length'
  • 누락 0~5 = 일시적 (재시도 trigger 자동 처리)
  • 누락 10+ = embeddingError 누적 → §5 절차

2.3 Sentry alert (TODO)

  • onPublicDocumentCreated 임베딩 실패 임계값
  • scheduledFetchLawGoKr 실패

3. 수집 경로 3 종

3.1 Cloud Scheduler (자동, 매일 02:00 KST)

  • 함수: scheduledFetchLawGoKr
  • 범위: core 21 카테고리 (대여금·공사대금·구상금·약정금·임대차·양수금·이혼·부동산·상속·계약 등)
  • 페이지: page 1 × display 20
  • 멱등: (court + caseNumber) 키, 기존 문서 skip
  • secret: LAW_GO_KR_OC (Firebase Secret Manager)

3.2 Ops 수동 (UI)

  • 위치: apps/ops/app/(ops)/public-rag/
  • 단건: 유형·출처·타이틀·본문·메타 입력 → addDoc
  • 벌크: law.go.kr API JSON 응답 paste → 어댑터가 정규화 + skip 이유 수집 + 일괄 addDoc
  • 어댑터: normalizeDecisionDate · parseCitedStatutes · pickContent (판례내용 > 판결요지 > 판시사항)

3.3 스크립트 bulk

# 다운로드 (로컬 JSON)
NODE_PATH=apps/web/node_modules \
npx tsx scripts/download-law-go-kr-bulk.ts \
--query "대여금" --pages 5 --display 50

# 검증
npx tsx scripts/verify-downloaded-data.ts <output-dir>

# 업로드 (publicDocumentsRaw → publicDocuments cascade)
NODE_PATH=apps/web/node_modules \
npx tsx scripts/upload-public-raw-to-firestore.ts <output-dir>

→ 임베딩은 onPublicDocumentCreated trigger 가 자동.

4. 장애 대응 — Cloud Scheduler 실패

증상: 어제 신규 0 건

Step 1: scheduler 로그

Firebase Console → Functions → scheduledFetchLawGoKr → Logs

  • Error: 401 → secret 만료 (LAW_GO_KR_OC 재발급)
  • Error: 429 → rate limit (자동 재시도 다음 날까지 대기)
  • Error: domain check failed → Referer 헤더 검증 실패 (settings 변경 여부 확인)

Step 2: 재실행

# 수동 트리거 (gcloud)
gcloud scheduler jobs run firebase-schedule-scheduledFetchLawGoKr-asia-northeast3 \
--location=asia-northeast3 \
--project=<projectId>

Step 3: 멱등성 확인

publicDocuments 에 동일 (court + caseNumber) 중복 없는지 firestore-rules-invariants test 통과 확인.

5. 임베딩 누락 복구

5.1 단건 재시도

# ops 콘솔 → public-rag → 해당 문서 → "재시도" 버튼
# 또는 onCall 함수 직접 호출
firebase functions:shell
> retryPublicDocEmbedding({docId: "<id>"})

5.2 대량 재처리

scripts/reembed-public-docs.ts 4 모드:

# (A) 임베딩 실패한 문서만
NODE_PATH=apps/web/node_modules \
npx tsx scripts/reembed-public-docs.ts --only-failed

# (B) 임베딩 누락 (embeddedAt: null) 만
npx tsx scripts/reembed-public-docs.ts --only-missing

# (C) 모델 버전 불일치 (예: text-embedding-004 → 005 마이그레이션)
npx tsx scripts/reembed-public-docs.ts --model-version-mismatch

# (D) 전체 재임베딩 (low priority, 비용 주의)
npx tsx scripts/reembed-public-docs.ts --all

6. 재파싱 (HTML 정제·스키마 확장)

원본이 publicDocumentsRaw.raw 에 보존되어 있어 네트워크 재호출 없이 publicDocuments 재구축 가능.

# 어댑터 변경 후
NODE_PATH=apps/web/node_modules \
npx tsx scripts/rebuild-public-docs-from-raw.ts

→ 변환 로직은 scripts/lib/law-go-kr-convert.ts (scripts 경로) + functions/src/law-go-kr-adapter.ts (Cloud Function 경로) 양쪽에 복제. 의미 변경 시 양쪽 동시 수정 필수. 회귀 가드:

  • apps/web/__tests__/scripts-law-go-kr-convert.test.ts
  • functions/__tests__/law-go-kr-adapter.test.ts

7. Secret Manager

# OC 키 갱신
firebase functions:secrets:set LAW_GO_KR_OC --project <projectId>

# Referer 변경
firebase apphosting:secrets:set LAW_GO_KR_REFERER --project <projectId>

→ Secret 변경 후 functions 재배포 필요.

8. 도메인 검증 우회 (참고)

Cloud Functions outbound IP 가 동적이므로 법제처 OPEN API 도메인 등록 불가. 대신:

  • 법제처 OPEN API 신청 시 "도메인 없음" 으로 신청
  • Referer 헤더만 검증
  • IP 화이트리스트 불필요

9. 권한·격리 모델

publicDocuments (tenant path 밖)
├── allow read: if isAuthenticated() # 모든 tenant 읽기 OK
└── allow write: if isAuthenticated() &&
exists(/databases/$(database)/documents/masterAdmins/$(request.auth.token.email))

publicDocumentsRaw (원본 보존)
├── allow read: if masterAdmin
└── allow write: if false # Admin SDK only

cross-tenant 유출 우려 없음 — 공공 데이터.

10. 관련 PR (구현 이력)

PhasePR핵심 산출물
1#712download-law-go-kr-bulk.ts · verify-downloaded-data.ts — 4,054 건 시드
2#713민법·상법·민사소송/집행법 등 3,589 조문
3#721retryPublicDocEmbedding onCall + 30일 누적 그래프
4a#722opsGenerateTestDoc
4b#723opsRagChat
5a#724/library 판례·법령 검색
5b#725/library AI 대화
6#726scheduledFetchLawGoKr Cloud Scheduler
7#727rebuild-public-docs-from-raw.ts · reembed-public-docs.ts
8#728architecture/platform-rag.md SSoT 정리

관련 문서