# 맥락노트: InsuWiki 협업 검토 시스템 + 신뢰도 UX

**작성일**: 2026-04-11 (v3: PRD 검증 미팅 반영)
**근거**: Agent Meeting v2 합의 + PRD 검증 미팅 (task-1639.1) 합의 22건

## 결정 근거

### 보안 결정

**SEC-01 재정의: 팬텀 위험**
- 결정: `/api/wiki/entries/{id}/approve` API가 실제로 존재하지 않음 확인. "현재 미존재, 향후 생성 시 인증 필수"로 재작성.
- 근거: 코드베이스 전수 검색으로 해당 API 미존재 확인. PRD 작성 시 코드 감사 불완전.

**SEC-02 신규: API 인증 부재 (CRITICAL)**
- 결정: index-wiki/search-wiki/invalidate-cache 즉시 인증 추가.
- 근거: search-wiki는 인증 완전 부재, invalidate-cache는 Bearer 존재만 확인(verifyIdToken 미호출). 로키가 "SEC-01보다 현실적 위험"으로 판정.
- 공격 벡터: 검색 인덱스 오염, 무인증 위키 크롤링, 캐시 무효화 DoS.

**서버 사이드 상태 머신 (Security Rules 대신)**
- 결정: 상태 전이 로직을 CF/API Route에서 구현. Security Rules는 불변식만.
- 근거: Rules에서 상태 머신 구현 시 (a) get() 10회 제한에 근접 (b) 리뷰 수 카운팅 불가 (c) 디버깅 극난 (PERMISSION_DENIED만 반환) (d) 테스트 복잡도 기하급수 증가.
- 불칸, 헤임달 일치 의견.
- Rules에서 할 일: `approved`로의 직접 전이를 차단. 나머지 상태 전이는 CF/Admin SDK가 수행.

**Custom Claims 도입**
- 결정: Firebase Auth Custom Claims로 역할을 토큰에 포함. Rules에서 get() 없이 역할 확인 가능.
- 근거: 헤임달 분석 — get() 10회 제한에서 역할 조회 1회 절약이 핵심. 4역할+2단계 승인에서 get() 최소 4회 필요한데, Claims로 0회로 절약 가능.
- 트레이드오프: Claims 전파 지연(최대 1시간). 문서 기반 역할 조회와 이중 관리로 해결 (Security Rules에서는 Claims, 클라이언트 UI에서는 Firestore 문서).

**경량 수정 면제 7조건**
- 결정: 7개 조건 모두 충족 시에만 경량 면제. CF 서버사이드 판정.
- 근거: 로키 공격 벡터 — 숫자 교체("20%"→"2.0%"), 부정어 삽입("보장함"→"보장하지 않음"), 점진적 의미 전복(salami attack). 클라이언트 측 판정은 조작 가능.
- 고위험 카테고리(court_ruling, regulation, policy_pdf)는 경량 면제 완전 제외.

**점진적 마이그레이션 (Big Bang 기각)**
- 결정: wiki-statuses.json이 존재하지 않으므로 Big Bang 대상 자체가 없음. 기존 문서에 Optional 필드를 추가하는 점진적 방식.
- 근거: 불칸 분석 — 상태는 TypeScript 타입으로만 관리. 기존 문서에 status 필드 없으면 `status ?? 'published'`로 처리.
- 실제 필요한 작업: 스키마 마이그레이션(필드 추가), 타입 확장, authorityTier 백필.

### UX 결정

**TrustBadge 3단계 + VerificationTag 분리**
- 결정: 정보의 성격(what)과 프로세스 상태(where)를 분리.
- 근거: 아테나 분석 — "검토대기"를 4번째 단계로 넣으면, 전문가가 쓴 미검토 문서가 블로그 발췌보다 낮게 보이는 역설 발생. 3중 인코딩(아이콘+색상+텍스트)은 배지 3단계에만 적용하고, 검토 상태는 서브텍스트/오버레이로 분리.
- 기각 대안: 4단계 통합 배지 — 두 차원(성격+상태) 혼합으로 혼란 유발.

**정적 기본 필터 (동적 필터 기각)**
- 결정: 모든 카테고리에서 기본 필터 "전체". 미검증 문서는 시각적 구분(배경색/보더). "검증만 보기" 세션 토글.
- 근거: 아테나 분석 — 동적 필터는 "영리하지만 불투명". 카테고리 전환 시 기본값이 변해 "내 목록이 왜 달라졌지?" 혼란. 교육이 필요한 필터는 좋은 필터가 아님. 5~8명 규모에서 예측 가능성이 UX 핵심.
- DA(헤임달) 후회 시나리오: 300건 이상에서 정보 과부하 → `useWikiFilter` 훅으로 전환 비용 최소화.
- 기각 대안: 동적 기본 필터 (0/1~4/5+ 3단계) — 시스템 예측 가능성 파괴.

**카테고리 칩 + 정렬 (교차 필터 기각)**
- 결정: 카테고리 칩 단일 선택 + 신뢰도순 정렬 옵션. 교차 필터는 30건+ 시 재검토.
- 근거: 아테나 분석 — 카테고리당 5~20건이면 눈으로 배지 구분이 필터 조작보다 빠름. 불칸 확인 — Firestore 인덱스 3개면 충분.
- 기각 대안: 카테고리 × 신뢰도 매트릭스 필터 — 현 규모에서 과잉 엔지니어링.

**오류 신고: 선택형 사유 + "정보 수정 요청"**
- 결정: 사전 정의 사유 4개(정보변경/수치오류/불완전/기타) + 선택적 메모 1줄. 레이블 "신고" 대신 "정보 수정 요청". 자동 상태 변경 금지.
- 근거: 아테나 — 5~8명에서 악용보다 허들 최소화가 우선. 로키 — censorship-by-report 공격 방어를 위해 자동 상태 변경 없이 admin 큐에만 표시. 헤임달 — Rate Limiting 필수(동일 유저×문서 1회/24h, 전체 10건/일).

**검색 종합 정리: 명시적 버튼 트리거**
- 결정: 검색 결과 상단에 "종합 정리 보기" 버튼. 결과 3건 이상일 때만 표시. 자동 아님.
- 근거: 아테나 — 검색의 80%는 탐색적이 아닌 내비게이션. 매번 LLM 호출은 불필요. 로키 — Prompt Injection 방어 3중(새니타이징+검증+면책) 필수.

### 기각된 대안 (v3 추가)

**Security Rules 상태 머신**
- 기각 사유: get() 10회 제한, 리뷰 카운팅 불가, 디버깅 극난, 테스트 복잡도.

**동적 기본 필터**
- 기각 사유: 카테고리 전환 시 기본값 변동으로 사용자 혼란. 예측 불가능성.

**TrustBadge 4단계 통합**
- 기각 사유: 정보 성격과 프로세스 상태 혼합. 전문가 미검토 문서의 역설.

**교차 필터 UI**
- 기각 사유: 50~200건 규모에서 과잉. 카테고리당 5~20건은 시각적 스캔으로 충분.

**경량 수정 면제 폐기 (DA 제안)**
- 기각 사유: 검토자 1~2명 부담 과다. 모든 수정을 큐에 넣으면 제도 형해화.
- 부분 반영: Phase 3 검토 UI에 diff 크기순 정렬 추가.

**LLM-Native Knowledge Base (비관습적 대안)**
- 기각 사유: 법규/판례 도메인 LLM 환각 리스크 수용 불가. 감사 추적 불가.
- 부분 반영: Phase 3 LLM 응답에 원문 링크+문단 하이라이트 필수.

## 주의사항

### 리뷰어 고갈 위험
- 경량 면제 7조건으로 오타/포맷 수정 부담 제거
- 리뷰어 풀 최소 3명 정책
- 적체 모니터링 SLA (Phase 3)

### Custom Claims 전파 지연
- Claims 최대 1시간 전파 지연
- 문서 기반 역할 조회와 이중 관리: Rules=Claims, UI=Firestore 문서
- 역할 변경 시 기존 토큰 강제 갱신 필요

### TIER_MAP 코드 vs PRD 불일치 해결
- 코드 기준 통일: regulation=1.5, court_ruling=2, kakao_expert=3.5
- PRD 값(regulation=1, kakao_expert=3) 폐기. 운영 데이터에 코드 값이 이미 반영.

### Phase 2a/2b 분리 이유
- 아테나: 동시 UX 변경의 "동시 충격" 문제. 시각적 변화 먼저, 기능 변화 나중.
- Phase 2a(1주): 시각적 변화만. Phase 2b(1.5주): 기능 변화.

### useWikiFilter 캡슐화 이유
- DA(헤임달): 300건 이상 도달 시 필터 전략 전환 필요. 훅 캡슐화로 전환 비용 최소화.

### UserRole 타입 단일 소스화
- 코드에 firestore.ts + AuthContext.tsx 중복 정의 발견. 마이그레이션 시 단일 소스로 통합 필수.
- 권장: shared/types/roles.ts에서 export, 양쪽에서 import.
