{
  "pass": true,
  "risks": [
    {
      "severity": "high",
      "description": "Phase 2의 `push_to_insuwiki` 설계가 실제로는 non-blocking 보장을 하지 못합니다. `async def` 안에서 동기 `requests.post()`를 사용하면 `await` 시 업로드 요청을 최대 10초까지 직접 블로킹하고, 반대로 `await` 없이 호출하면 코루틴이 실행되지 않아 push가 아예 누락될 수 있습니다."
    },
    {
      "severity": "high",
      "description": "push 실패를 `try/except`로 무시만 하고 재시도·큐·outbox 저장이 없어, InsuWiki 동기화가 영구 유실될 수 있습니다. 설계 목표는 '업로드에 영향 없음'이지만 현재 방식은 '실패 시 조용한 데이터 손실 허용'에 가깝습니다."
    },
    {
      "severity": "high",
      "description": "`newsletter_updates` 컬렉션의 읽기 정책이 설계에 명확히 정의되어 있지 않습니다. 현재 `firestore.rules`에는 해당 컬렉션 규칙이 없어서 클라이언트 Firestore 조회는 기본적으로 실패하고, 반대로 급하게 공개 규칙을 추가하면 `extracted_text` 원문이 과도하게 노출될 위험이 있습니다."
    },
    {
      "severity": "medium",
      "description": "InsuWiki UI가 Firestore를 직접 조회하는 구조로 가면, 목록 화면에 필요 없는 `extracted_text` 전체가 브라우저로 내려갑니다. 접기 UI를 써도 데이터는 이미 클라이언트에 노출되므로, 민감 정보·저작권 텍스트·과도한 페이로드 문제가 남습니다."
    },
    {
      "severity": "medium",
      "description": "수신 API는 `body` 검증이 없어 `company_name`, `month_key`, `source`, `source_id` 형식 오류나 비정상 대용량 payload를 그대로 저장할 수 있습니다. 공유 API 키만 맞으면 임의 데이터 주입도 가능해 운영 데이터 품질이 쉽게 깨집니다."
    },
    {
      "severity": "medium",
      "description": "문서 ID를 `source_id` 단독으로 사용하면 `newsletters`와 `premium_data`가 서로 다른 테이블이어도 동일 ID 체계일 경우 충돌할 수 있습니다. 충돌 시 한 소스가 다른 소스 업데이트를 덮어쓸 수 있습니다."
    },
    {
      "severity": "low",
      "description": "`extracted_text[:10000]`처럼 앞부분만 잘라 보내면 핵심 정보가 후반부에 있는 문서에서 잘못된 요약·오해를 유발할 수 있습니다. 특히 '최근 업데이트' 기능에서 사용자가 원문 일부만 보고 전체 문서 의미로 받아들일 가능성이 있습니다."
    }
  ],
  "suggestions": [
    "InsuRo 쪽은 HTTP 호출을 직접 `await`하지 말고 작업 큐, outbox 테이블, 또는 FastAPI `BackgroundTasks` + 재시도 가능한 비동기 클라이언트(`httpx.AsyncClient`)로 분리하세요.",
    "push 실패는 최소한 outbox에 적재하고 재시도 상태를 남기세요. '업로드 성공'과 '동기화 성공'을 분리 추적해야 운영 중 누락을 복구할 수 있습니다.",
    "`newsletter_updates`는 클라이언트 직접 조회보다 Next.js 서버 API/Server Component를 통해 필요한 필드만 내려주는 방식이 안전합니다. 목록에는 요약 필드만, 원문은 권한 확인 후 별도 조회로 분리하는 편이 낫습니다.",
    "`newsletter_updates`용 Firestore 규칙을 명시적으로 설계하세요. 누가 읽을 수 있는지, 원문(`extracted_text`)을 모두 볼 수 있는지, 관리자만 원문 접근 가능한지 먼저 결정해야 합니다.",
    "수신 API에 스키마 검증을 추가하세요. `source` enum, `month_key` 형식, 문자열 길이 제한, 필수 필드 검증은 최소 필요사항입니다.",
    "문서 ID는 `source + ':' + source_id` 같은 복합 키로 저장해 소스 간 충돌을 막으세요.",
    "원문 전체를 저장해야 한다면 PII/민감정보 마스킹 규칙을 먼저 두고, UI에는 원문 대신 요약/발췌본을 우선 노출하는 방향을 권장합니다."
  ],
  "source": "codex_companion",
  "fallback_reason": null,
  "error": null,
  "task_id": "task-2232",
  "timestamp": "2026-04-27T02:34:47.657570+00:00"
}