# task-937.2: OpenDataLoader PDF 환경 구축 + PDF 스킬 업그레이드

- **작성자**: 오딘 (개발2팀장)
- **팀원**: 토르(백엔드), 미미르(UX/UI), 헤임달(테스터)
- **작성일**: 2026-03-25

---

## SCQA

**S**: task-937.1에서 OpenDataLoader PDF(ODL) 분석 완료. B안(하이브리드 도입) 채택됨. 시스템에 Java 8만 설치되어 있고, ODL Python SDK(v2.0.2)는 설치 완료 상태.

**C**: ODL은 Java 11+을 요구하나 시스템에 Java 8만 존재. sudo 접근 불가로 apt 설치 불가. 또한 기존 PDF 스킬에 ODL 통합 가이드와 래핑 스크립트가 없어, Claude가 ODL 기능을 활용할 수 없는 상태.

**Q**: sudo 없이 Java 11을 설치하고, ODL 래핑 스크립트 4개와 SKILL.md 업데이트를 완료하여 PDF 스킬에서 즉시 ODL을 활용할 수 있는가?

**A**: OpenJDK 11을 사용자 공간(`~/.local/jvm/`)에 직접 다운로드·설치하여 해결. ODL 래핑 스크립트 4개 작성, SKILL.md에 ODL 섹션 추가, hybrid 서버 스크립트 작성 완료. 12건 테스트 전체 PASS, pyright 에러 0건.

---

## 작업 내용

### Step 1: Java 11+ 설치
- sudo 접근 불가 → OpenJDK 11.0.2를 사용자 공간에 설치
- 경로: `/home/jay/.local/jvm/jdk-11.0.2/`
- `~/.bashrc`에 `JAVA_HOME`/`PATH` 영구 등록
- 기존 Java 8 보존 (공존 가능)
- 검증: `java -version` → `openjdk version "11.0.2" 2019-01-15`

### Step 2: ODL 동작 검증
- `opendataloader-pdf` v2.0.2 이미 설치됨
- Python import: `from opendataloader_pdf import convert` → OK
- 실제 변환 테스트: 테스트 PDF → Markdown/JSON 출력 정상 확인
  - Markdown: 제목, 테이블(4행×2열) 올바르게 추출
  - JSON: kids 배열에 heading, paragraph, table 구조 포함

### Step 3: Hybrid 서버 스크립트
- `hybrid_server.py`: FastAPI + docling DocumentConverter 싱글턴 패턴
- `start-hybrid-server.sh`: GPU 감지, 포트 충돌 검사, PID 관리, 로그 로테이션
- `stop-hybrid-server.sh`: PID 파일 기반 안전 종료
- 실제 기동 테스트: 약 6초 후 health check PASS → 정상 종료 확인

### Step 4: PDF 스킬 업그레이드

**SKILL.md 업데이트** (기존 314줄 → 398줄):
- 기존 내용 100% 보존
- "Document Understanding / Extraction (OpenDataLoader PDF)" 섹션 추가
- 하위 섹션: Overview, When to Use ODL vs Existing Tools, Quick Start, Options Reference, Hybrid Mode, OCR, Requirements

**래핑 스크립트 4개**:
1. `extract_text_odl.py` (126줄) — PDF→Markdown/Text 추출, XY-Cut++ 읽기 순서
2. `extract_table_odl.py` (116줄) — JSON에서 table 타입만 필터링 출력
3. `ocr_pdf_odl.py` (156줄) — hybrid 자동 설정, force-ocr, 한국어 에러 메시지
4. `convert_pdf_odl.py` (316줄) — convert() 전 파라미터 20+개 argparse 노출

### Step 5: 테스트 검증 (12건 전체 PASS)

- T1: extract_text_odl.py markdown 출력 — **PASS**
- T2: extract_text_odl.py text 출력 — **PASS**
- T3: extract_table_odl.py JSON 테이블 추출 — **PASS**
- T4: convert_pdf_odl.py JSON 변환 — **PASS**
- T5: convert_pdf_odl.py markdown 변환 — **PASS**
- T6: convert_pdf_odl.py --output-dir 파일 저장 — **PASS**
- T7: ocr_pdf_odl.py hybrid 미실행 에러 핸들링 — **PASS** (한국어 에러 메시지, exit 1)
- T8: 존재하지 않는 PDF 에러 핸들링 — **PASS** (exit 1)
- T9: --help 옵션 — **PASS**
- T10: 기존 폼 스크립트 8개 회귀 테스트 — **PASS** (변경 없음)
- T11: SKILL.md 기존 섹션 보존 검증 — **PASS**
- T12: pyright 타입 체크 — **PASS** (0 errors, 0 warnings)

---

## 발견 이슈 및 해결

### 자체 해결 (4건)

1. **sudo 접근 불가로 Java 11 시스템 설치 불가** — OpenJDK 11 tarball을 `~/.local/jvm/`에 직접 다운로드·압축 해제로 해결
2. **수동 생성 PDF의 xref 테이블 오류** — fpdf2 패키지 설치 후 올바른 테스트 PDF 생성으로 해결
3. **JAVA_HOME 미설정 시 Java 8이 기본 사용되는 문제** — `.bashrc`에 JAVA_HOME 등록 + 래핑 스크립트에 기본값 `/home/jay/.local/jvm/jdk-11.0.2` 폴백 적용
4. **PATH 설정 시 python3 경로 누락** — 환경변수 설정 순서 정리하여 기존 PATH 보존

### 범위 외 미해결 (1건)

1. **OCR 실제 테스트 미수행** — 범위 외 사유: 한국어 스캔 PDF 샘플 부재 + hybrid 서버 상시 실행 비용. OCR 에러 핸들링은 검증 완료.

---

## 생성/수정 파일 목록

**신규 생성 (7개)**:
- `/home/jay/.claude/skills/pdf/scripts/extract_text_odl.py` — ODL 텍스트 추출 래핑
- `/home/jay/.claude/skills/pdf/scripts/extract_table_odl.py` — ODL 테이블 추출 래핑
- `/home/jay/.claude/skills/pdf/scripts/ocr_pdf_odl.py` — ODL OCR 래핑
- `/home/jay/.claude/skills/pdf/scripts/convert_pdf_odl.py` — ODL 범용 변환 래핑
- `/home/jay/workspace/scripts/hybrid_server.py` — docling-fast FastAPI 서버
- `/home/jay/workspace/scripts/start-hybrid-server.sh` — hybrid 서버 시작 스크립트
- `/home/jay/workspace/scripts/stop-hybrid-server.sh` — hybrid 서버 종료 스크립트

**수정 (2개)**:
- `/home/jay/.claude/skills/pdf/SKILL.md` — ODL 섹션 추가 (314줄→398줄, 기존 내용 보존)
- `/home/jay/.bashrc` — JAVA_HOME/PATH 환경변수 추가 (4줄)

**미수정 (보존 확인)**:
- 기존 PDF 스킬 폼 스크립트 8개 전체 미변경

---

## 머지 판단

- **머지 필요**: No (시스템 작업, 프로젝트 git repo 아님)

---

## QC 자동 검증

- **overall**: PASS (WARN 1건 → black 포매팅 적용 후 해결)
- **file_check**: PASS (6/6 파일 존재, 크기 정상)
- **data_integrity**: PASS
- **test_runner**: SKIP (관련 테스트 파일 0개, 정당한 SKIP)
- **tdd_check**: SKIP (스킬 파일/설정 작업)
- **pyright_check**: PASS (0 errors, 0 warnings)
- **style_check**: WARN → black 적용 후 해결 (4파일 reformatted)
- **critical_gap**: PASS
- **spec_compliance**: PASS
- **duplicate_check**: PASS (최대 유사도 6.1%)

Gate PASS → .done 파일 자동 생성 완료
