# InsuRo 개인정보 P0-1 Drive 공개제거→서버프록시 Phase 1 백엔드코어 (task-2927, 260808)

> 팀 dev1-team(헤르메스/불칸/아르고스). 프로젝트 InsuRo(remote `JonghyukJeon/InsuRo`).
> 브랜치 `task/task-2927-dev1` head **8f6692a**(원격 동기 확인), base **f2b282e**. restore 태그 `restore-260808-pre-p0-1`.

## 배경/결정
증권 PDF·소식지·보험료 업로드가 Google Drive `anyone/reader` 공개 → 링크 유출 시 제3자 PII 접근(개인정보 최우선 리스크). **회장 결정: Drive 유지(대량저장 비용), Supabase Storage 이관 안 함.** 공개 제거 + 서버 프록시 접근통제. task-2927 = **Phase 1(백엔드 코어)** = 엔드포인트/컬럼 추가 + 내부전환만(기존 동작 무변경, 신규 anyone 유지·구 `/view` 병행). 신규 공개제거·프론트 7곳 교체·소급회수는 Phase 2/3.

## Phase 1 구현 (9파일 +941/-22)
- 마이그레이션 `20260808120000_drive_file_id_normalization.sql`: `drive_file_id` 정규화 컬럼(newsletters/premium_data)+`drive_file_ids text[]`(policy_analyses 멀티), file_url서 substring 백필, 인덱스 3종. 멱등.
- `server/gdrive.py` `extract_drive_file_id()` 단일 파서(삭제/재분석/프록시 공유)+`iter_drive_file()` 청크 스트리밍.
- `POST /api/insuro/file-ticket`(main.py:5856, verify_jwt): 등급별 소유권 인가 — FA소유(user_id≠sub→**403 IDOR**)→관리자(system_admin 없으면 403)→공개(fcpa)→없으면 **404**. 성공시 1회용 ticket(TTL 5분).
- `GET /api/insuro/file/{ticket_id}`(main.py:5933, 무인증 capability): ticket 1회소비→스트리밍(run_in_executor, OOM 방지)+보안헤더(nosniff/no-referrer/attachment).
- `server/file_ticket_store.py`: 인메모리·스레드안전·TTL5분·pop 1회소비(replay 방지). 단일워커 전제.
- `parse_premium_file` file_id 전환(하위호환)→`/view` HTML 오수신 버그 동시 해소.
- JWT ES256 전용(main.py:856 `["ES256"]`, JWKS 기반 안전). ★잔존: main.py:377 multi_account_detect_middleware HS256(인가무관 로깅, 범위밖).
- 예외 `pass` 삼킴 5곳→감사로그. `_validate_file_url` SSRF 화이트리스트 존치.

## ANU 독립검증 (260808)
- 브랜치/원격 head 8f6692a 동기·restore 태그·9파일·핵심 엔드포인트(5856/5933/856) 전부 확인.
- **아누 직접 재현: 신규 보안테스트 48개 전부 PASS**(worktree, PYTHONPATH 지정) — IDOR 403·ES256 HS256거부·ticket replay 404 핵심 포함.
- 봇 보고: 회귀 0(전체 1347 passed, 1 failed=pre-existing CORS `test_cors_fail_closed_when_ext_origin_unset` base 재현·무관). L1 실서버 스모크 200/401/404 통과.

## 회장 확정 반영
- **FCPA(금소법 전문) 공개등급 = 🟢 공개 확정** ("금소법전문은 누구나봐도 됨", 260808). 보고서의 "FCPA 회장 확인요망"은 **해소**. 프록시 등급표 확정: 금소법PDF=공개 / 소식지·보험료=관리자 / 증권PDF(PII)=FA소유.

## HOLD (머지+배포 회장/ANU 조율 대기)
Phase 1은 추가+내부전환만이라 MERGE-READY(검증완료). 단 머지+배포는 코드검증만으로 완결 안 됨:
1. **DB 마이그레이션 실적용 필요**(백필). `jsonb_typeof(result)` = policy_analyses.result가 jsonb 전제 → json 타입이면 실패, 배포 전 실 스키마 컬럼타입 확인 권장.
2. **배포 = systemd insuro-api.service 재기동**(프로덕션).
3. **InsuRo PR ruleset 데드락 이력** → 머지 경로 주의.
정직보고: L1 스모크 정리 중 광범위 `pgrep -f "uvicorn main:app"`가 production PID(8001)까지 종료→systemd 즉시 자동승계(etimes 14s)·api.insuro.biz 200 확인·무중단 복구·코드/데이터 무영향. 이후 광범위 pkill 미사용.

## 후속
- 남은 회장 확인: **소급 회수 범위**(전 파일 기본 vs 고민감 증권만) — Phase 3 착수 전 결정.
- Phase 2 = 프론트 7곳 file-ticket 배선 + E2E. Phase 3 = 신규 anyone 제거 + 소급회수 + 함께 배포(공백 0).
- 상세 보고서 `memory/reports/task-2927.md`.
