# 아키텍처

## 기본 원칙
- 1차 목표는 UI가 아니라 안정적인 CLI/라이브러리 변환 엔진이다.
- PDF parser는 `Marker`를 기본 엔진으로 사용한다.
- 변환 파이프라인은 Marker 출력에 직접 결합하지 않고 내부 중간 표현(Document Model)을 거친다.
- 출력은 Obsidian 친화 Markdown을 우선하되, 표준 Markdown과의 호환성을 가능한 한 유지한다.
- 긴 문서는 20페이지 단위 chunk로 처리하고, chunk별 상태/캐시/로그를 남겨 재시도가 가능해야 한다.

## 목표 디렉토리 구조
```
venv/                       # 가상 환경
samples/                    # 품질 검증용 샘플 PDF
src/
├── converter/              # PDF to Markdown 변환 핵심
│   ├── engines/            # Marker 및 향후 parser adapter
│   ├── model/              # 내부 Document Model
│   ├── renderers/          # Obsidian Markdown 출력
│   ├── indexer/            # index 파일 생성
│   └── diagnostics/        # 로그, 경고, 변환 상태
├── ui/                     # 2차 목표: PyQt UI 컴포넌트
└── utils/                  # 유틸리티 + 헬퍼
```

## 주요 컴포넌트
### Converter Core
- PDF 입력, 사전 분석, chunk 분할, parser 실행, 중간 표현 생성, 출력 렌더링을 조율한다.
- UI와 분리되어 CLI와 테스트에서 직접 호출 가능해야 한다.

### Parser Engine Adapter
- 1차 구현은 `MarkerEngine`만 대상으로 한다.
- 향후 `Nougat`, `Docling`, `PyMuPDF` 등 다른 엔진을 붙일 수 있도록 adapter 경계를 둔다.
- parser adapter는 원본 parser 결과와 프로젝트 내부 Document Model 사이의 변환을 담당한다.

### Document Model
내부 중간 표현은 최소한 다음 정보를 담아야 한다.
- document id, title, source path, output slug
- chunk id, page range, conversion status
- block id, block type, text/content
- heading level, paragraph, list, quote, equation, table, figure
- source page, bbox, confidence, parser metadata
- image/table asset path
- warnings/errors

### Obsidian Renderer
- Document Model을 Obsidian 친화 Markdown 파일로 렌더링한다.
- 수식은 `$ ... $`, `$$ ... $$` 형식을 지킨다.
- 이미지는 Obsidian 내부 링크 또는 프로젝트에서 정한 표준 이미지 링크 형식으로 연결한다.
- 복잡한 표는 Markdown table에 억지로 맞추지 않고 HTML table 또는 별도 CSV 링크를 허용한다.

### Index Builder
- 단순 목차가 아니라 AI Agent가 문서 내부로 진입하기 위한 탐색 index를 만든다.
- heading, 주요 문단, 표, 그림, 수식에 대해 Markdown 파일, heading, line 위치, 원본 page 정보를 연결한다.
- 가능한 경우 block id와 bbox를 metadata에 보존한다.

### Diagnostics & Recovery
- 변환 설정, Marker 버전, GPU/CPU 사용 여부, 처리 시간, 경고, 실패 chunk를 기록한다.
- 완료된 chunk는 재사용하고 실패한 chunk만 재시도할 수 있어야 한다.
- 원본 Marker 결과와 내부 Document Model snapshot은 디버깅 가능한 형태로 보존한다.

## 프로그램 흐름
```
PDF 파일 입력
-> 사전 분석: 페이지 수, 텍스트 포함 여부, 스캔 여부, 예상 chunk 수 확인
-> 20페이지 단위 chunk 분할
-> chunk별 Marker 변환
-> Marker 결과를 내부 Document Model로 변환
-> reading order, paragraph stitching, semantic mapping 보정
-> 이미지/표/수식 asset 정리
-> Obsidian 친화 Markdown 렌더링
-> index 파일 생성
-> metadata/log 저장
```

## 상태 관리
- 문서 단위 상태와 chunk 단위 상태를 분리한다.
- chunk 상태는 `pending`, `running`, `completed`, `error`, `skipped` 같은 값으로 관리한다.
- 변환 중 실패가 발생해도 완료된 chunk 결과는 유지한다.
- 최종 index는 chunk 결과를 기준으로 재생성 가능해야 한다.

## 변환 결과 출력 구조
```
output/
└── document-slug/
    ├── document-slug_index.md
    ├── document-slug_001.md
    ├── document-slug_002.md
    ├── document-slug_003.md
    ├── images/
    │   ├── page-001_fig-001.png
    │   └── page-012_fig-003.png
    ├── tables/
    │   ├── page-005_table-001.csv
    │   └── page-008_table-002.html
    └── metadata/
        ├── document.json
        ├── chunks.json
        ├── parser-output/
        └── conversion.log
```

## Obsidian 출력 규칙
- 파일명은 Windows와 Obsidian에서 안전한 slug 기반 이름을 사용한다.
- 원본 PDF 파일명은 metadata에 보존한다.
- heading은 Obsidian 내부 링크 대상이 될 수 있도록 안정적으로 생성한다.
- 이미지는 상대 경로 또는 Obsidian 내부 링크 중 프로젝트 표준을 정해 일관되게 사용한다.
- index 파일은 각 chunk 파일과 주요 heading으로 이동할 수 있어야 한다.
- 수식은 Obsidian에서 렌더링 가능한 Markdown math 문법을 사용한다.

## 검증 전략
- TDD를 기본으로 한다.
- 전체 Markdown snapshot 비교보다 부분 품질 검증을 우선한다.
- 샘플 PDF별로 heading 추출, 수식 block 수, 이미지 파일 생성, 표 구조 보존, index 링크 생성, 예외 발생 여부를 확인한다.
- Windows native, 한글 경로, 긴 파일명, 8GB VRAM 제한을 검증 항목에 포함한다.
