# InsuRo PDF 편집기 — 맥락 노트

## 핵심 의도
- 보험 설계사가 PDF 서류를 InsuRo 안에서 합치고, 서명하고, 변환하는 올인원 도구
- 외부 도구(iLovePDF, SmallPDF 등) 대체

## 기술 결정
- pdf-lib 중심: 합치기/나누기/서명삽입/폼채우기/오버레이 전부 클라이언트에서 처리
- Word↔PDF만 서버 필요 (LibreOffice + PyMuPDF)
- react-pdf(pdfjs-dist)로 뷰어: Mozilla의 53K stars 라이브러리

## UI 위치
- InsuRo 메뉴: 분석 & 도구 > PDF 편집기
- 라우트: /tools/pdf-editor
- DashboardLayout 래퍼 사용

## 서버 의존성 (Phase 3)
- LibreOffice headless: apt install libreoffice
- PyMuPDF: pip install pymupdf
- python-docx: pip install python-docx

## Phase 1 구현 기록 (2026-04-25, task-2193)

### 3 Step Why
- A. 왜 이 기능이 필요한가? → 보험 설계사가 외부 도구(iLovePDF 등) 없이 InsuRo 내에서 PDF 합치기/나누기/편집을 처리하기 위해
- B. 왜 클라이언트 사이드 처리인가? → pdf-lib가 브라우저에서 동작하므로 서버 부하 없이 즉시 처리 가능. 서버는 Word↔PDF 변환(Phase 3)에만 필요
- C. 왜 react-pdf를 선택했는가? → pdfjs-dist 기반 53K stars 라이브러리로 안정성/호환성 검증됨. TypeScript 지원

### 기술 결정 사항
- pdfjs worker: unpkg CDN 방식 (`//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`)
- 썸네일 lazy 렌더링: IntersectionObserver 기반
- 페이지 재정렬: @dnd-kit/sortable (이미 프로젝트에 설치됨)
- PdfEditor 청크 크기: ~900KB (react-pdf + pdf-lib 포함). code-split 이미 적용 (lazy import)

### 발견 이슈 및 해결
1. Uint8Array BlobPart 타입 불일치 → `as BlobPart` 캐스팅으로 해결
2. numPages state 미사용 경고 → 제거 (pageOrder.length로 대체)
3. .env 파일 worktree에 미복사 → 수동 복사 (worktree_manager에서 자동화 검토 필요)

## Phase 2 구현 기록 (2026-04-26, task-2196)

### 3 Step Why
- A. 왜 서명/오버레이 기능이 필요한가? → 보험 설계사가 PDF에 서명/도장/텍스트를 삽입해야 하는 업무가 빈번. 외부 도구 없이 InsuRo 내에서 처리
- B. 왜 클라이언트 사이드 처리인가? → pdf-lib가 브라우저에서 embedPng/drawText/drawImage를 지원. 서버 불필요
- C. 왜 react-signature-canvas를 선택했는가? → MIT 라이선스, 터치/마우스 지원, toDataURL()로 PNG 데이터 URL 즉시 추출 가능

### 기술 결정 사항
- 서명 컴포넌트: react-signature-canvas (v1.1.0-alpha.2)
- 오버레이 좌표: % 기반 (DOM 좌상단 원점), pdf-lib 적용 시 Y축 반전 변환
- 훅 분리: usePdfSignature.ts (302줄) — 오버레이/폼 로직 전담
- UI 분리: SignaturePanel.tsx (571줄) — 4탭 UI (서명/텍스트/이미지/폼)
- PdfEditor.tsx에 sign 모드 추가 (Mode 타입 확장)

### 발견 이슈 및 해결
1. pdf-lib `degrees()` 함수 타입: `{ type: 'degrees', angle }` 직접 생성 시 TS 에러 → `degrees()` 헬퍼 함수 import로 해결
2. SignaturePanel의 totalPages prop 미사용 경고 → props 구조 분해에서 제외 (인터페이스는 유지)
3. JPG/PNG 판별: dataUrl MIME 타입에서 자동 판별 → embedJpg/embedPng 분기 처리
