# TheRoad Scene Lab - 파이프라인 아키텍처 개요

> 시나리오(대본) PDF를 입력받아 웹북용 이미지를 자동 생성하는 분석+이미지 파이프라인.
> 단일 진실 소스: `backend/app/core/step_manifest.py`
>
> **현황 (v0.6.0, 2026-04-21):**
> - **shot-more 시리즈** (v0.5.0~v0.5.2): `scene_camera_flow`, `scene_consistency`, `character_state_variant`, `shot_validator` 신규 step.
> - **이미지 품질 시리즈** (v0.5.7~v0.5.14): shot_selection 2중 캡(v4), scene_detail v9(zoom_in_detail + 복장 명기), location_consistency 롤백, shot_dependency_t2i v5.
> - **프롬프트 범용화** (v0.5.11): 시나리오 의존 표현 전수 중립화 (혈흔·빙의·피멍 등 7개 프롬프트).
> - **Frontend 리팩토링 Phase 5** (v0.5.25~v0.5.31): React Query 전환 **완료**. `EpisodeDetail.tsx` **1,358 → 148 LOC (−89%)**, useState **34 → 1 (−97%)**. 17 query 훅 + 7 mutation 파일 (27 mutation) + 4 sub-component (Header/WorldGuide/ActionBar/Stills). 상세: `06-data-contracts.md` §Frontend 데이터 계약.
> - **Backend 관찰성** (v0.6.0): `except: pass` **38건 → 0건** (LOG 25 / INTENTIONAL 13). 모든 silent failure 제거 → 로깅/주석 명시.
> - **문서 신설**: `frontend/public/pipeline_explained.html` (일반인용 시각화), `docs/architecture-easy/` (비전문가용 가이드 8개), `docs/product-roadmap-discussion.md` (제품 방향 논의 자료).
>
> **Phase 5 완결 = v0.6.0 태그 (`631a082`)**.

## Active vs Legacy 구분표

| 구분 | 정의 | 위치 |
|------|------|------|
| **Active** | 실제 파이프라인에서 순서대로 실행되는 step | `step_manifest.py`에 `applicability: "always"` 또는 `if_*` |
| **Legacy** | `applicability: "on_demand"` 또는 `"disabled"`. 실제 실행 경로에 없음 | 문서 끝 "참고: 레거시" 섹션 |
| **Dead code** | STEP_CLASSES 미등록, 코드만 잔존 | `analysis_steps_legacy.py` 등 |

## Active 파이프라인 흐름

```mermaid
flowchart TD
    subgraph Phase1["Phase 1: 텍스트 전처리"]
        A1[text_cleanup] --> A2[scene_segmentation]
        A2 --> A3[scene_save]
        A1 --> A4[episode_summary]
        A4 --> A5[visual_world_rules]
        A3 --> A6[entity_character_list]
        A5 --> A6
        A3 --> A7[scene_summary]
        A4 --> A7
        A5 --> A7
    end

    subgraph Phase2["Phase 2: 엔티티 추출"]
        B1[entity_all_character] --> B2[entity_extract_character]
        B3[entity_all_location] --> B4[entity_extract_location]
        B5[entity_all_prop] --> B6[entity_extract_prop]
        B2 --> B7[entity_merge]
        B4 --> B7
        B6 --> B7
        B7 --> B8[entity_relation]
        B8 --> B9[entity_filter]
        B9 --> B10[entity_detail]
        B10 --> B11[entity_t2i]
    end

    subgraph Phase3["Phase 3: 샷/비트 분석"]
        C1[beat_extract] --> C2[shot_extract]
        C2 --> C2v["shot_validator (신규)"]
        C2v --> C3[shot_selection]
    end

    subgraph Phase4["Phase 4: 씬 연출"]
        D1[scene_director] --> D2[shot_director]
        C3 --> D2
        D1 --> D3[outlook_phase1]
        D3 --> D4[outlook_phase2]
        D4 --> D5[outlook_phase3]
        D1 --> D6["scene_camera_flow (신규)"]
        D6 --> D7[shot_staging]
        D7 --> D9["scene_consistency (신규)"]
        D2 --> D10[scene_detail]
        D5 --> D10
        D7 --> D10
        D9 --> D10
        D1 --> D11[shot_dependency]
        D11 --> D10
        D10 --> D12[shot_dependency_t2i]
        D10 --> D13[t2i_review]
    end

    subgraph Phase5["Phase 5: 이미지 생성"]
        E1[world_guide]
        E2[ref_image_gen] --> E3[composite_image_gen]
        E3 --> E4["character_state_variant (신규)"]
        E4 --> E5[scene_image_pipeline]
        E1 --> E5
        E3 --> E5
    end

    Phase1 --> Phase2
    Phase1 --> Phase3
    Phase2 --> Phase4
    Phase3 --> Phase4
    Phase4 --> Phase5

    style Phase1 fill:#e8f4fd,stroke:#2196F3
    style Phase2 fill:#fff3e0,stroke:#FF9800
    style Phase3 fill:#e8f5e9,stroke:#4CAF50
    style Phase4 fill:#fce4ec,stroke:#E91E63
    style Phase5 fill:#f3e5f5,stroke:#9C27B0
    style D6 fill:#fff59d,stroke:#f57f17
    style D9 fill:#fff59d,stroke:#f57f17
    style E4 fill:#fff59d,stroke:#f57f17
    style C2v fill:#fff59d,stroke:#f57f17
```

> 노란색 박스(`shot_validator`, `scene_camera_flow`, `scene_consistency`, `character_state_variant`) = shot-more 브랜치 신규 단계.

## 실행 순서 (order 기준)

```
1    text_cleanup                gemini-lite
2    scene_segmentation          gemini-flash
3    episode_summary             gpt-mini
4    visual_world_rules          gpt
6    scene_save                  (코드)
6.5  entity_character_list       gemini-pro
7    scene_summary               gpt-mini (병렬)
7.1  beat_extract                gemini-pro (번들 병렬)
7.2  shot_extract                gemini-pro (순차 번들)
7.25 shot_validator              gemini-pro (병렬)  ← 신규 v0.5.4
8    entity_all_character        gemini-pro
9    entity_extract_character    gpt
10   entity_all_location         gpt
11   entity_extract_location     gemini-pro
12   entity_all_prop             gpt
13   entity_extract_prop         gemini-pro
13.5 entity_merge                gpt
13.6 entity_relation             gpt
13.7 entity_filter               gpt-mini
14   entity_detail               gpt
15   entity_t2i                  gemini-pro (병렬)
15.5 shot_selection              gpt-mini (병렬)  ← 2중 캡 v0.5.8
16   scene_director              gemini-pro
16.5 shot_director               gpt
17.05 scene_camera_flow          gemini-pro (병렬)  ← 신규 v0.5.0
18.1 shot_dependency             (코드 기반, LLM 없음)
19   outlook_phase1              gemini-pro
19.1 outlook_phase2              gemini-pro
19.2 outlook_phase3              gemini-pro
19.5 shot_staging                gpt  ← scene_camera_flow 파생 v0.5.0
19.9 scene_consistency           gemini-pro  ← 신규 v0.5.0
20   scene_detail                gpt (병렬)  ← 핵심: C## 규칙, 고정 요소 통합, zoom_in_detail
20.5 shot_dependency_t2i         gpt-mini  ← LLM 기반, shot_dependency 덮어씀
20.7 t2i_review                  gemini-flash  (editorial)
22   world_guide                 gpt
23   ref_image_gen               gemini-image (병렬)
24   composite_image_gen         gemini-image (병렬)
24.5 character_state_variant     gemini-image  ← 신규 v0.5.0
25   scene_image_pipeline        compound (mixed models)
```

> shot_validator는 shot_extract 직후 실행되어 "한 찰나" 원칙 위반 shot을 재작성하고 `shot_extract` 체크포인트를 덮어쓰지 않고 별도 `shot_validator` 체크포인트로 저장한다. 다운스트림(`entity_all_*`, `shot_selection`, `scene_camera_flow`, `shot_staging`, `scene_consistency`, `scene_detail`)은 `shot_validator` 체크포인트를 읽는다.

## 5개 Phase 요약

| Phase | 이름 | 역할 | Active 단계 수 |
|-------|------|------|---------|
| 1 | **텍스트 전처리** | PDF → 텍스트 정리, 씬 분할, 요약, 세계관 규칙, 기획서 분석 | 8 |
| 2 | **엔티티 추출** | 인물/배경/소품 3단계 분리 추출, 병합/필터/T2I 프롬프트 | 11 |
| 3 | **샷/비트 분석** | 씬 → beat(상태변화) → shot(스틸컷) → validator → selected | 4 |
| 4 | **씬 연출** | VE 판정, 카메라 플로우, 아웃룩, 연출, 일관성, 상세, 검수 | 12 |
| 5 | **이미지 생성** | 참조, 합성, state variant, 씬 이미지 | 5 |

**Active 단계 총 40개** = `applicability: "always"`(38) + `if_planning_doc`(1) + `if_has_outlooks`(1).
`STEP_MANIFEST` 전체 **48단계** 중 Active 40 + `on_demand` 4 + `disabled` 4. (set_design은 2026-04-27 제거)

> 정확한 실측: `docs/architecture/_step_manifest.generated.md` (스크립트 생성). 문서 숫자와 drift 발생 시 generated 파일이 진실.

**공식 실행 경로**: `StepRunner` (`backend/app/core/step_runner.py`). 내부 dispatch는 `analysis_dispatch_service.py`로 수렴 완료(Phase 4).
`POST /episodes/{id}/analyze`와 `/reanalyze-scenes` 공개 엔드포인트는 **shim 상태로 공존**하여 내부적으로 `dispatch_category_run(category="analysis")`을 호출한다. 프런트 `Episodes.tsx`가 `useAnalyzeEpisode`로 legacy 경로를 여전히 사용 중 — **W1(공개 계약 수렴)에서 `/steps/run-all` 단일화** 예정.
참조: `docs/review-codex-1/11-fix-plan.md` §Wave 1 (최신 실행 계획), `docs/architecture-refactor-final/02-final-roadmap.md` (당시 로드맵 아카이브).

## 데이터 흐름 개념도

```mermaid
flowchart LR
    PDF[시나리오 PDF] --> |Gemini Lite| CleanText[정리된 텍스트]
    CleanText --> |Gemini Flash regex| Segments[씬 세그먼트]
    Segments --> |Gemini Pro| Beats[Beat 목록]
    Beats --> |Gemini Pro| Shots[Shot 목록]
    Segments --> |GPT / Gemini Pro| Entities[엔티티 목록]

    Shots --> |GPT Mini| SelectedShots[선택된 Shot]
    Entities --> |GPT Mini| T2I[엔티티 T2I]

    SelectedShots --> |Gemini Pro| Flow[scene_camera_flow]
    Flow --> |GPT| Staging[shot_staging]
    Staging --> |Gemini Pro| Consistency[scene_consistency]

    SelectedShots --> |Gemini Pro| Direction[scene_director]
    T2I --> Direction
    Consistency --> |GPT| SceneDetail[scene_detail: T2I 프롬프트]
    Staging --> SceneDetail
    Direction --> SceneDetail

    SceneDetail --> |Gemini Image| Images[씬 이미지]
```

## 핵심 원칙

- **LLM 데이터 무삭제**: 시나리오 텍스트는 청킹/잘라내기 없이 전문 전달
- **Short ID 체계**: `C##`(인물), `O##`(아웃룩), `L##`(배경), `P##`(소품)
- **beat→shot 계층**: 씬 → beat(상태변화) → shot(스틸컷) → selected shots
- **한 샷 = 한 찰나** (shot-more 핵심): 카메라 셔터가 한 번 눌린 1/1000초만 담는다. 시간 연결어 금지, 연속 동작 분해(before/during/after) 강제.
- **단일 시점 원칙**: 한 t2i_prompt = 하나의 카메라 위치. 3인칭 전신과 손 클로즈업 혼합 금지.
- **체크포인트 기반**: 각 단계 결과를 JSON manifest.json으로 저장, 다음 단계에서 참조
- **visible_entities 코드 구축**: LLM 의존 없이 scene_director / shot_director 확정 데이터에서 자동 생성
- **T2I 단일 스틸컷 원칙**: 한 t2i_prompt = 한 순간, 한 시공간만
- **C## 사용 규칙** (v0.5.1): 얼굴이 보이면 C## (참조 이미지 자동 연결), 뒷모습/실루엣/클로즈업이면 보통명사

## LLM 모델 배정

| 모델 | 용도 | 사용 단계 |
|------|------|----------|
| **Gemini Pro** (`gemini-3.1-pro-preview`) | 씬 감독, beat/shot, 아웃룩, 카메라 플로우, 일관성, 인물 리스팅 | scene_director, beat_extract, shot_extract, outlook_phase1/2/3, scene_camera_flow, scene_consistency, entity_character_list, entity_extract_location/prop |
| **GPT-5.5** | 텍스트 분석 주력 | visual_world_rules, entity_extract_character, entity_merge, entity_relation, entity_detail, scene_detail, shot_director, shot_staging, shot_dependency |
| **GPT-5.5 Mini** | 보조 작업 | episode_summary, scene_summary, entity_t2i, entity_filter, shot_selection, shot_dependency_t2i |
| **Gemini Flash** | 세그먼테이션, T2I 검수 | scene_segmentation, t2i_review |
| **Gemini Flash Lite** | 텍스트 정리 | text_cleanup, planning_doc_analysis |
| **Gemini Image** (`gemini-3.1-flash-image-preview`) | 이미지 생성 | ref_image_gen, composite_image_gen, character_state_variant, scene_image_pipeline |
| **GPT Vision (LVM)** | 이미지 검증/선택 | scene_t2i_validation, angle_recommend, final_select |
| **fal.ai** | 앵글 적용 | fal_angle_apply (FAL_AI_ENABLED=true시) |

## 문서 구조

| 파일 | 내용 |
|------|------|
| [`01-text-preprocessing.md`](01-text-preprocessing.md) | Phase 1: 텍스트 전처리 (8단계) |
| [`02-entity-extraction.md`](02-entity-extraction.md) | Phase 2: 엔티티 추출 (11단계) |
| [`03-shot-analysis.md`](03-shot-analysis.md) | Phase 3: 샷/비트 분석 (4단계 — shot_validator 포함) |
| [`04-scene-direction.md`](04-scene-direction.md) | Phase 4: 씬 연출 (12단계) — scene_camera_flow / scene_consistency 포함 |
| [`05-image-generation.md`](05-image-generation.md) | Phase 5: 이미지 생성 (5단계) — v0.5.1~v0.5.14 변경 반영 |
| [`06-data-contracts.md`](06-data-contracts.md) | 데이터 계약: Short ID, 체크포인트, DB 스키마 |
| [`07-prompt-versioning-policy.md`](07-prompt-versioning-policy.md) | 프롬프트 버전 관리 정책 (`_base` 활성 3개 + `_archive`) |

## 참고: 레거시 / Dead code

아래 step들은 `step_manifest.py`에 정의되어 있으나 **Active 경로에서 호출되지 않는다**.

| Step | 상태 | 대체 |
|------|------|------|
| `scene_split` | `on_demand` | beat/shot 계층으로 대체 |
| `shot_cinematography` | `disabled` | `shot_staging`이 대체 |
| `scene_dependency` | `disabled` | `shot_dependency`가 대체 |
| `scene_verify` | `disabled` | STEP_CLASSES 등록됐지만 applicability=disabled로 run-all 경로 제외 |
| `scene_cinematography` | `on_demand` | `shot_staging`이 대체 |
| `outlook_extraction` | `on_demand` | `outlook_phase1/2/3` 래퍼 |
| `outlook_dedup` | `on_demand` | (사용 안 함) |
| `project_summary` | `disabled` (lifecycle=removed) | ProjectSummaryStep 클래스 부재, 호출 시 404 |

파일 전체 dead code:

- `backend/app/core/steps/analysis_steps_legacy.py` — v3 잔재, STEP_CLASSES 미등록.
