# 12. Analysis Job Pipeline

## 목적

개발요청서의 OCR+LLM 분석 구조를 기존 시험지 첨삭 솔루션에 반영하기 위해 `AnalysisJob` 중심 파이프라인을 추가한다. 실제 OCR 모델이 없어도 mock pipeline으로 업로드부터 교사 승인, 오버레이 렌더링까지 검증한다.

## 사용자 표시 순서

홈페이지 연구내용의 시험지 이미지 순서를 산출물 표시 기준으로 고정한다.

| display_order | artifactType | 표시 단계 | 상태 |
|---:|---|---|---|
| 1 | `original_exam` | 원본 시험지 | 업로드 직후 생성 |
| 2 | `printed_layer_restored` | 문제 레이어 복원 | mock pipeline 생성 |
| 3 | `problem_grid_preview` | 문제 격자 인식 | mock pipeline 생성 |
| 4 | `printed_layer` | 문제 레이어 분리 | mock pipeline 생성 |
| 5 | `student_grid_alignment` | 풀이 격자 적용 | mock pipeline 생성 |
| 6 | `student_layer` | 풀이 레이어 분리 | mock pipeline 생성 |
| 7 | `solution_analysis` | 풀이 분석 | evidence/diagnosis 생성 |
| 8 | `approved_overlay_preview` | 첨삭 오버레이 | 교사 승인 후 render 생성 |

`page_artifacts.metadata.display_order`와 `page_artifacts.metadata.research_stage_key`는 필수값이다.

2단계 `printed_layer_restored`는 원본 시험지에서 정형화된 인쇄 폰트 영역을 시험지 문제 레이어로 분리하고, 지워져 인식이 약한 획은 원본 대비 정보를 사용해 보강한 뒤 시험지만 남긴 결과여야 한다. 격자와 좌표 표시는 3단계 `problem_grid_preview`에서만 다룬다.

## 상태 전이

```text
uploaded
-> normalized
-> layers_extracted
-> printed_restored
-> grid_ready
-> student_aligned
-> ocr_done
-> evidence_ready
-> diagnosis_ready
-> review_pending
-> approved
-> rendered
```

## API

| API | 설명 |
|---|---|
| `POST /api/exam-annotation/jobs` | 프로젝트 기준 분석 job 생성 |
| `GET /api/exam-annotation/projects/:projectId/jobs` | 프로젝트의 분석 job 목록 |
| `GET /api/exam-annotation/jobs/:jobId` | job 상세, artifact, evidence, diagnosis |
| `POST /api/exam-annotation/jobs/:jobId/run` | mock pipeline 실행 |
| `GET /api/exam-annotation/jobs/:jobId/artifacts` | display_order 기준 산출물 목록 |
| `GET /api/exam-annotation/jobs/:jobId/problems` | 문제별 token/cell 상태 |
| `GET /api/exam-annotation/problems/:problemId/evidence?jobId=:jobId` | evidence package 조회 |
| `POST /api/exam-annotation/jobs/:jobId/review` | 교사 승인/수정/거절 |
| `POST /api/exam-annotation/jobs/:jobId/render` | ExportGuard 통과 후 오버레이 생성 |
| `GET /api/exam-annotation/jobs/:jobId/download/:artifactId` | mock artifact 다운로드 |

## ExportGuard 조건

다음 조건이 있으면 렌더링과 프로젝트 export를 차단한다.

- `unresolved` OCR token 존재
- evidence audit 실패 diagnosis 존재
- 교사 승인 전 diagnosis 존재
- 기존 인식불가영역 미해결
- 기존 `DRAFT` 또는 `REVIEW_REQUIRED` annotation 존재

## Local Agent 대응 endpoint

| Endpoint | 역할 |
|---|---|
| `POST /scan/normalize` | 정규화/품질 점수 |
| `POST /scan/separate-layers` | 인쇄문항/학생필기/교사표식 분리 |
| `POST /scan/restore-template` | 템플릿 정합과 복원 |
| `POST /scan/build-grid` | 문제영역 격자 생성 |
| `POST /solution/recognize` | 기존 풀이 인식 후보 |
| `POST /reasoning/diagnose` | evidence 기반 진단 |
| `POST /reasoning/audit` | evidence_refs 감사 |
| `POST /annotation/render-handwriting` | 손글씨형 annotation 렌더링 |
| `POST /export/render-pdf` | PDF export alias |

## 테스트

- `apiSmoke.test.js`: job 생성, mock pipeline, 8단계 artifact 정렬, 교사 승인, render 검증
- `exportGuard.test.js`: 기존 인식불가/DRAFT 차단과 analysis guard reason 차단 검증
