Script Revisions and AI Proposals
1. 목적
사용자가 편집 중인 시나리오와 AI가 실제 분석한 시나리오를 구분한다. AI 분석 결과는 비동기로 생성될 수 있으므로 결과가 어느 원문을 기준으로 만들어졌는지 추적할 수 있어야 하며, 재분석이 사용자의 기존 구조를 덮어쓰면 안 된다.
사용자는 Sequence와 Scene을 한 단계씩 검토하거나 Scene까지 분석으로 이어진 실행을 시작할 수 있다. 통합 분석은 Sequence Proposal 검토에서 멈춘 뒤 사용자가 승인한 Sequence만 Scene 분석으로 넘긴다. 두 모드는 같은 Proposal schema, validator, source range와 정식 Sequence·Scene을 사용한다.
통합 분석은 Sequence를 생략하지 않는다. Sequence는 후속 Scene이 참조하는 서사 목적, 감정 흐름, 촬영·음악 기본값과 연출 메모를 소유한다.
2. 엔티티 책임
| 엔티티 | 책임 | 변경 가능성 |
|---|---|---|
ScriptRevision | 사용자가 저장한 시나리오 버전의 전체 원문과 해시 | 생성 후 불변 |
ProposalSet | 하나의 분석 실행에서 생성된 Proposal 묶음과 Character·Beat·Shot 발행 시각 | 검토 중 Proposal 편집, 발행 후 읽기 전용 |
CharacterProposal | 특정 ScriptRevision에서 추출한 등장인물 후보와 원문 근거 | 발행 전 편집·채택·제외 가능 |
CinemaCharacter | Revision을 넘어 유지되는 Project 공용 등장인물 정체성 | 사용자가 명시적으로 편집 |
SequenceProposal | Sequence 후보의 제목, 목적, 원문 범위, 순서 | 검토 중 편집 가능 |
SceneProposal | 특정 Sequence 내부의 Scene 후보 | 검토 중 편집 가능 |
BeatProposal | 특정 Scene 내부의 행동·의도·감정 변화 후보 | 발행 전 편집 가능 |
ShotProposal | 활성 Beat를 카메라 커버리지로 표현하는 Shot 후보와 제안 Mapping | 발행 전 편집 가능 |
Sequence, Scene, Beat, Shot | 사용자가 승인하거나 발행한 정식 영화 구조 | 사용자가 명시적으로 편집 |
ScriptRevision은 키 입력마다 생성하는 자동 저장 이력이나 Undo 스택이 아니다. 사용자가 변경 후 저장을 누르고 새 버전 생성 안내를 확인한 시점에만 만들어지는 사용자 가시적 시나리오 버전이다. 편집 중 본문은 브라우저 로컬 상태이며 별도 ScriptDraft 테이블은 두지 않는다. Sequence 분석은 최신 ScriptRevision을 참조하며 분석 자체가 새 버전을 만들지는 않는다.
3. 권장 최소 스키마
ScriptRevision
├── id
├── projectId
├── version
├── contentSnapshot
├── contentHash
├── characterCount
├── createdAt
└── createdBy
ProposalSet
├── id
├── projectId
├── type: CHARACTER_EXTRACTION | SEQUENCE_DECOMPOSITION | SCENE_DECOMPOSITION | BEAT_DECOMPOSITION | SHOT_DECOMPOSITION
├── scriptRevisionId
├── sourceSequenceId?
├── sourceSceneId?
├── status
├── sourceHash
├── modelMetadata
├── createdAt
├── completedAt
└── publishedAt?
Sequence 분석은 scriptRevisionId를 필수로 참조한다. Scene 분석은 승인된 sequenceId, 해당 Sequence의 원문 기준 scriptRevisionId, 분석 시점의 Sequence 내용 해시를 함께 보존하는 방향이 적절하다.
4. 생성 흐름
- 사용자가 현재 저장 버전을 기준으로 시나리오를 편집한다.
- 편집 내용은 브라우저 로컬 상태에만 있으며 자동 저장하지 않는다.
- 사용자가 저장을 누르면 시스템이 다음 버전 번호와 기존 버전 보존 안내를 표시한다.
- 사용자가 확인하면 마지막으로 본 Revision ID를 충돌 기준으로 새 ScriptRevision을 하나의 트랜잭션에서 생성한다.
- 사용자가
등장인물 분석을 실행하면 최신 저장 버전의 원문 근거를 가진 Character ProposalSet을 만든다. - 사용자가 제안을 편집·채택·제외한 뒤 발행하면 Revision과 독립적인 Project Character Registry를 생성하거나 갱신한다.
- 사용자가
Sequence 분석을 실행하면 최신 저장 버전을 참조하는 새 ProposalSet을 만든다. - AI 결과를 SequenceProposal로 저장한다.
- 사용자는 Proposal을 승인, 수정 승인, 거절, 분할, 병합, 재정렬한다.
- 승인 또는 수정 승인된 결과로 Sequence를 생성한다.
- 이후 새 시나리오 버전을 저장해도 승인된 Character·Sequence와 과거 Proposal은 자동 삭제하지 않는다.
같은 시나리오 버전을 재분석하면 ScriptRevision은 재사용하고 별도 ProposalSet만 만든다. 시나리오를 수정하고 저장한 경우에만 새 ScriptRevision을 생성한다.
5. 상태 모델
ProposalSet과 개별 Proposal의 상태는 분리한다.
| 대상 | 권장 상태 | 의미 |
|---|---|---|
| ProposalSet | PROCESSING | AI 분석 진행 중 |
| ProposalSet | READY | 결과 검토 가능 |
| ProposalSet | STALE | 최신 Revision, Project 문맥 또는 Sequence가 분석 기준과 달라짐 |
| ProposalSet | FAILED | 분석 실패 |
| ProposalSet | ARCHIVED | 이전 분석본으로 보관 |
| Proposal | PENDING | 승인 또는 제외를 기다리는 후보 |
| Proposal | ACCEPTED | 정식 엔티티 생성 완료 |
| Proposal | REJECTED | 사용하지 않음 |
검토 상태와 생성·편집 이력은 별도 필드다. origin은 AI | MANUAL | SPLIT | MERGED, hasUserChanges는 사용자 편집 여부를 나타낸다. 따라서 사용자가 수정한 Proposal을 승인해도 상태는 ACCEPTED이고 수정 사실은 hasUserChanges = true로 유지된다. originalSnapshot은 AI 원본에만 저장한다.
STALE은 결과가 잘못됐다는 뜻이 아니라 ProposalSet이 실제로 소비한 입력 fingerprint가 현재값과 달라졌다는 경고다. 단순히 상위 엔티티의 updatedAt이 바뀌었다는 이유만으로 설정하지 않는다. 과거 Revision의 Proposal과 정식 제작 데이터는 읽기 전용으로 보존한다.
Sequence와 Scene은 Proposal별 승인을 사용한다. Beat는 제안 사이의 연속 범위와 전체 Scene 커버리지가 하나의 계약이므로 ProposalSet 전체 발행을 사용한다. Shot도 순서와 M:N Mapping이 하나의 카메라 계획을 이루므로 ProposalSet 전체 발행을 사용한다.
Character 추출 결과는 ScriptRevision별 ProposalSet으로 검토하지만, 발행 결과는 Project 공용 CinemaCharacter다. 새 Revision 분석은 기존 Character를 안정적인 key로 전달해 동일 인물을 갱신할 수 있으며, 새 원문에서 발견되지 않은 기존 Character를 자동 삭제하거나 보관하지 않는다. 원문 근거는 중복 본문이 아니라 sourceStart, sourceEnd 범위 배열로 저장한다.
Sequence 승인 취소는 원본 Proposal이나 정식 Sequence를 삭제하지 않고 정식 Sequence를 ARCHIVED로 전환한다. 보관 상태에서는 제목, 요약, 서사 목적을 원본 Proposal과 별도로 편집할 수 있고, 원문 범위와 기존 순서는 승인 이력의 기준이므로 변경하지 않는다. 다시 승인하면 새 행을 만들지 않고 같은 Sequence ID를 ACTIVE로 복원하며 기존 하위 Scene과 제작 데이터도 유지한다. Sequence 문맥이 실제로 바뀌면 변경된 dependency group을 소비한 미발행 ProposalSet만 STALE로 표시하고, 승인된 하위 제작 데이터는 자동 보관하지 않은 채 RECOMPILE_NEEDED, REVIEW_NEEDED, REANALYSIS_NEEDED 중 해당 상태와 이유를 계산한다.
보관 상태에서 분할하거나 제외하는 것은 복원 편집과 다른 구조 변경이다. 이 경우 기존 보관 Sequence의 sourceProposalId를 해제해 하위 제작 데이터와 함께 복원 불가 과거 이력으로 보존하고, 원본 Proposal을 다시 PENDING으로 전환한 뒤 분할하거나 REJECTED로 제외한다. 분할로 생성된 Proposal은 각각 새 정식 Sequence로 승인해야 하며 기존 하위 제작 데이터는 자동 이전하지 않는다. 과거 ScriptRevision의 Sequence는 모든 경로에서 읽기 전용이다.
Scene도 같은 두 경로를 사용한다. 복원 편집에서는 정식 Scene의 제목, 행동, 서사 기능, 장소, 시간대, 내외부, 날씨, 등장인물을 수정하고 같은 Scene ID로 다시 승인한다. 원문 범위와 기존 Beat·Shot은 유지한다. 실제 문맥이 바뀌면 관련 미발행 ProposalSet의 consumed fingerprint를 비교하고, 승인된 Beat·Shot·Frame·Motion에는 영향 상태만 기록한다. 분할·제외 시에는 기존 Scene의 sourceProposalId를 해제해 Beat·Shot과 함께 복원 불가 이력으로 보존하고 Scene Proposal을 새 검토 흐름으로 돌린다. 기존 Beat·Shot은 분할된 새 Scene에 자동 이전하지 않는다.
Beat의 전체 발행과 발행 후 복원은 다른 동작이다. 사용자가 정식 Beat 하나를 직접 보관하면 archiveReason = MANUAL로 남기고 동일 Beat ID를 다시 활성화할 수 있다. 복원 전에는 원본 Proposal을 수정하지 않고 보관된 정식 Beat의 제목, 행동, 서사 기능, 감정 전환, 퍼포먼스를 편집한다. 원문 범위와 순서는 발행 이력의 기준이므로 이 단계에서 바꾸지 않는다. 새 ProposalSet 전체 발행으로 대체된 과거 Beat는 SUPERSEDED이며 현재 Beat 계획에 개별로 섞어 복원하지 않는다. Beat를 보관하거나 복원해 활성 집합이 바뀌어도 기존 정식 Shot을 자동 보관하지 않는다. 대신 Beat-Shot Mapping의 커버리지 유효성을 다시 계산하고, 관련 Shot ProposalSet과 Shot Specification에 STALE 또는 영향 상태를 표시한다.
Shot 발행 트랜잭션은 모든 비제외 Shot이 하나 이상의 활성 Beat를 참조하고 모든 활성 Beat가 하나 이상의 Shot에서 다뤄지는지 확인한다. 기존 활성 Shot을 ARCHIVED로 바꾼 뒤 Shot과 CinemaBeatShotMapping을 함께 생성하고 Proposal을 ACCEPTED로 전환한다. STALE 세트는 발행할 수 없고, 이미 발행된 세트는 읽기 전용이며 반복 발행 요청은 기존 결과를 반환한다.
6. 데이터 불변 조건
- ScriptRevision의
contentSnapshot은 생성 후 수정하지 않는다. - ProposalSet은 정확히 하나의 분석 기준 Revision을 가진다.
- AI 결과는 정식 Sequence나 Scene을 자동 생성하지 않는다.
- 승인된 Sequence와 Scene은 재분석으로 자동 수정하거나 삭제하지 않는다.
- 정식 엔티티는 생성 원본의
proposalId,scriptRevisionId,sourceStart,sourceEnd를 추적할 수 있어야 한다. - 분석 완료 시 ProposalSet이 실제로 소비한 Revision segment 또는 dependency fingerprint가 달라지면 결과를
STALE로 표시한다. - Beat ProposalSet은 발행 후 수정할 수 없으며 한 번의 발행은 활성 Beat 묶음을 원자적으로 교체한다.
- Shot ProposalSet은 발행 후 수정할 수 없으며 Shot과 Mapping을 원자적으로 교체한다.
- Shot 분석 기준은 활성 Beat의 ID·순서·내용·연출 메모 중 실제 소비한 그룹을 기록하며, 해당 fingerprint가 바뀐 미발행 결과만
STALE이다. - 직접 보관한 최신 발행 묶음의 Beat만 개별 복원할 수 있으며, 새 묶음으로 대체된 Beat는 과거 이력으로만 조회한다.
- 보관된 Sequence의 복원 전 편집은 정식 Sequence의 표시 문맥만 변경하며 원본 Proposal, 원문 범위, ID와 하위 제작 데이터는 유지한다.
- 보관된 Sequence의 Proposal을 분할·제외하면 기존 Sequence는 Proposal 연결을 해제한 복원 불가 이력으로 보존하고 새 Proposal 검토 흐름으로 돌아간다.
- 보관된 Scene도 복원 편집에서는 ID·원문 범위·Beat·Shot을 유지하고, 분할·제외에서는 기존 Scene과 하위 데이터를 복원 불가 이력으로 분리한다.
- Character Proposal은 ScriptRevision에 귀속되지만 발행된 Character는 Project에 귀속되며 Revision 교체로 자동 삭제하지 않는다.
- Shot 분석 모델은 승인된 Character의 서버 발급 key만 반환하고 Asset ID를 선택하지 않는다. 서버가 key를 Character ID로 변환한다.
- Character Registry의 서사적 내용 변경은 이를 소비한 미발행 Shot 계획을
STALE로 만들 수 있지만, Character-Persona 연결 변경은 Shot 서사 설계를 무효화하지 않고 Reference 재컴파일만 요구한다.
7. MVP UI
사용자에게 Git과 같은 복잡한 버전 UI를 노출하지 않는다.
Sequence 분석버튼과 진행 상태시나리오 v3,v3 기반 편집본과 같은 현재 버전 표시- 저장 시 생성될 다음 버전 번호와 기존 버전 보존 확인
- 분석 기준 버전과 현재 저장 버전이 다르면
현재 시나리오와 다름표시 - Proposal 추가·삭제·분할·병합·정렬·수정
- 승인, 수정 승인, 거절
- 이전 시나리오 버전 열람과 ProposalSet 재분석
- 시나리오 버전별 등장인물 분석 이력, 제안 편집·채택·제외·전체 발행
- Project Character별 Persona 캐릭터 시트 연결 상태 표시
8. 현재 API
Project, ScriptRevision과 Sequence Proposal 검토·승인 계약을 다음 API로 제공한다.
| Method | Path | 책임 |
|---|---|---|
GET | /v1/cinema/projects | 내 Project 목록과 최신 Revision 문자 수, Revision 수 조회 |
POST | /v1/cinema/projects | 빈 Project 생성 |
GET | /v1/cinema/projects/:projectId | Project와 최신 Revision 원문 조회 |
PATCH | /v1/cinema/projects/:projectId | 제목, 로그라인, 장르 수정 |
DELETE | /v1/cinema/projects/:projectId | 소유 Project와 하위 Revision 삭제 |
GET | /v1/cinema/projects/:projectId/script-revisions | Revision 메타데이터 목록 조회 |
POST | /v1/cinema/projects/:projectId/script-revisions | 제출 본문으로 다음 Revision 생성. expectedRevisionId 충돌 검사, 동일 hash 멱등 처리 |
GET | /v1/cinema/projects/:projectId/script-revisions/:revisionId | Revision 원문 스냅샷 조회 |
POST | /v1/cinema/projects/:projectId/script-revisions/:revisionId/character-analyses | 최신 Revision 기반 Character 추출 시작 |
GET | /v1/cinema/projects/:projectId/character-proposal-sets?scriptRevisionId=... | Revision별 Character 분석 이력 조회 |
GET | /v1/cinema/projects/:projectId/character-proposal-sets/:proposalSetId | Character 제안과 발행 결과 조회 |
PATCH/POST | /v1/cinema/projects/:projectId/character-proposal-sets/:proposalSetId/... | 제안 편집·채택·채택 취소·제외·전체 채택 |
POST | /v1/cinema/projects/:projectId/character-proposal-sets/:proposalSetId/publish | 채택한 제안을 Project Character Registry로 발행 |
GET | /v1/cinema/projects/:projectId/characters | Project Character 목록 조회 |
PATCH | /v1/cinema/projects/:projectId/characters/:characterId | Project Character 개별 정보 편집 |
POST/DELETE | /v1/cinema/projects/:projectId/characters/:characterId/asset-mapping | Character와 Persona ProjectAssetBinding 연결·해제 |
POST | /v1/cinema/projects/:projectId/sequence-analyses | 최신 저장 Revision을 참조하는 PROCESSING ProposalSet 생성 후 분석 시작 |
POST | /v1/cinema/projects/:projectId/structure-analyses | 표준 Sequence 분석을 시작하고 재개 가능한 통합 실행을 생성 |
GET | /v1/cinema/projects/:projectId/structure-analysis-runs | ScriptRevision별 통합 실행과 Sequence·Scene 진행 상태 조회 |
POST | /v1/cinema/projects/:projectId/structure-analysis-runs/:runId/continue | 승인된 Sequence 중 Scene 분석이 없거나 실패한 항목만 실행 |
POST | /v1/cinema/projects/:projectId/structure-analysis-runs/:runId/complete | 모든 Scene Proposal 검토가 끝난 통합 실행을 완료 |
GET | /v1/cinema/projects/:projectId/sequence-proposal-sets | Sequence 분석 실행 이력 조회 |
GET | /v1/cinema/projects/:projectId/sequence-proposal-sets/:proposalSetId | ProposalSet, 제안, 승인 결과 조회 |
POST | /v1/cinema/projects/:projectId/sequence-proposal-sets/:proposalSetId/proposals | 수동 Sequence Proposal 추가 |
PATCH | /v1/cinema/projects/:projectId/sequence-proposal-sets/:proposalSetId/proposals/:proposalId | Proposal 제목, 요약, 목적 수정 |
PUT | /v1/cinema/projects/:projectId/sequence-proposal-sets/:proposalSetId/reorder | 제외되지 않은 Proposal 전체 순서 변경 |
POST | /v1/cinema/projects/:projectId/sequence-proposal-sets/:proposalSetId/proposals/:proposalId/split | 하나의 Proposal을 둘 이상으로 분할 |
POST | /v1/cinema/projects/:projectId/sequence-proposal-sets/:proposalSetId/merge | 연속한 Proposal 병합 |
POST | /v1/cinema/projects/:projectId/sequence-proposal-sets/:proposalSetId/proposals/:proposalId/reject | Proposal 제외 |
POST | /v1/cinema/projects/:projectId/sequence-proposal-sets/:proposalSetId/proposals/:proposalId/accept | 정식 Sequence 생성 |
GET | /v1/cinema/projects/:projectId/sequences | 승인된 정식 Sequence 조회 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/archive | 정식 Sequence의 승인을 취소하고 보관. 하위 제작 데이터는 유지 |
PATCH | /v1/cinema/projects/:projectId/sequences/:sequenceId/restoration-draft | 보관된 정식 Sequence의 제목, 요약, 서사 목적을 복원 전에 편집 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/restore | 보관된 Sequence를 동일 ID로 다시 승인 |
GET | /v1/cinema/projects/:projectId/sequences/:sequenceId | 승인된 Sequence 상세와 원문 범위 조회 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scene-analyses | Sequence를 참조하는 PROCESSING Scene ProposalSet 생성 후 분석 시작 |
GET | /v1/cinema/projects/:projectId/sequences/:sequenceId/scene-proposal-sets | Sequence의 Scene 분석 실행 이력 조회 |
GET | /v1/cinema/projects/:projectId/sequences/:sequenceId/scene-proposal-sets/:proposalSetId | Scene ProposalSet, 제안, 승인 결과 조회 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scene-proposal-sets/:proposalSetId/proposals | 수동 Scene Proposal 추가 |
PATCH | /v1/cinema/projects/:projectId/sequences/:sequenceId/scene-proposal-sets/:proposalSetId/proposals/:proposalId | Scene 기본 정보 수정 |
PUT | /v1/cinema/projects/:projectId/sequences/:sequenceId/scene-proposal-sets/:proposalSetId/reorder | 제외되지 않은 Scene Proposal 전체 순서 변경 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scene-proposal-sets/:proposalSetId/proposals/:proposalId/split | 하나의 Scene Proposal을 둘 이상으로 분할 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scene-proposal-sets/:proposalSetId/merge | 연속한 Scene Proposal 병합 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scene-proposal-sets/:proposalSetId/proposals/:proposalId/reject | Scene Proposal 제외 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scene-proposal-sets/:proposalSetId/proposals/:proposalId/accept | 정식 Scene 생성 |
GET | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes | Sequence에 승인된 정식 Scene 조회 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/archive | 정식 Scene의 승인을 취소하고 보관. Beat·Shot은 유지 |
PATCH | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/restoration-draft | 보관된 정식 Scene의 서사·환경·등장인물 정보를 복원 전에 편집 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/restore | 보관된 Scene을 동일 ID로 다시 승인 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/beat-analyses | Scene 기반 Beat 분석 시작 |
GET | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/beat-proposal-sets | Beat 분석 이력 조회 |
GET | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/beat-proposal-sets/:proposalSetId | Beat 제안과 발행 결과 조회 |
POST/PATCH | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/beat-proposal-sets/:proposalSetId/... | Beat 추가·수정·분할·병합·정렬·제외 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/beat-proposal-sets/:proposalSetId/publish | 검토한 제안 전체를 정식 Beat로 원자적 발행 |
GET | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/beats | 활성 또는 보관 포함 정식 Beat 조회 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/beats/:beatId/archive | 정식 Beat를 MANUAL 사유로 보관하고 현재 Shot 계획 무효화 |
PATCH | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/beats/:beatId/restoration-draft | 직접 보관한 정식 Beat의 복원 전 내용 편집. 원본 Proposal·원문 범위·순서는 유지 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/beats/:beatId/restore | 직접 보관한 Beat를 동일 ID로 복원하고 현재 Shot 계획 무효화 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/shot-analyses | 활성 Beat 기반 Shot 설계 시작 |
GET | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/shot-proposal-sets | Shot 설계 이력 조회 |
POST/PATCH | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/shot-proposal-sets/:proposalSetId/... | Shot과 제안 Beat Mapping 추가·수정·정렬·제외 |
POST | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/shot-proposal-sets/:proposalSetId/publish | Shot과 정식 Beat-Shot Mapping 원자적 발행 |
GET | /v1/cinema/projects/:projectId/sequences/:sequenceId/scenes/:sceneId/shots | 활성 또는 보관 포함 정식 Shot과 Mapping 조회 |
Revision 저장 요청은 공백이 아닌 시나리오 원문을 요구한다. 마지막으로 조회한 최신 Revision ID를 expectedRevisionId로 전달하며, 서버의 최신 ID와 다르면 409 Conflict를 반환해 다른 탭이나 요청의 수정을 자동으로 덮어쓰지 않는다. Revision이 없는 최초 저장은 ID를 생략한다.
Revision 수정·삭제 API는 제공하지 않는다. 같은 내용을 다시 저장하는 멱등 요청은 새 version을 만들지 않으며, 같은 버전을 재분석하면 별도 ProposalSet만 만든다. 분석 요청은 한 프로젝트에 하나의 PROCESSING 실행만 허용하며, 결과가 준비되기 전에는 Proposal 편집 API를 허용하지 않는다.
9. 현재 구현의 경계 검증과 개편 목표
모델은 문자 offset을 직접 결정하지 않고 각 Sequence 또는 Scene 시작점의 짧은 원문 문자열인 startMarker를 반환한다. 서버가 분석 대상 원문에서 marker를 순서대로 찾은 뒤 처음부터 끝까지 겹치거나 비는 범위가 없도록 sourceStart, sourceEnd를 계산한다. Scene offset은 Sequence 상대값이 아니라 ScriptRevision의 절대 문자 위치로 저장한다. sourceExcerpt는 DB 컬럼이 아니라 Revision 원문과 범위로 API 응답 시 복원한다. marker를 찾을 수 없거나 순서가 맞지 않으면 Proposal을 일부 저장하지 않고 ProposalSet 전체를 FAILED로 처리한다.
Scene 분석의 sourceHash는 승인된 Sequence의 제목, 요약, 서사 목적, 원문 발췌와 저장된 범위를 함께 해시한다. 분석 완료 시 현재 Sequence의 hash가 달라졌으면 Scene ProposalSet을 STALE로 표시한다. 한 Sequence에는 동시에 하나의 PROCESSING Scene 분석만 허용한다.
Beat 분석의 sourceHash는 Project 문맥, Sequence 제목·요약·목적·연출 메모, Scene 메타데이터·연출 메모·원문 범위를 포함한다. Scene 연출 메모가 변경되면 발행되지 않은 READY Beat ProposalSet을 즉시 STALE로 전환하며, 한 Scene에는 동시에 하나의 Beat 분석만 실행한다.
Shot 분석의 sourceHash는 위 Project·Sequence·Scene 문맥과 활성 Beat의 ID, 순서, 원문 범위, 사건, 감정, 퍼포먼스, 연출 메모를 포함한다. 별도 공간·블로킹 설계 값은 Shot 분석 유효성에 포함하지 않는다. 모델은 UUID 대신 화면 순서 기준 beatNumber를 반환하고 서버가 현재 활성 Beat ID로 해석한다. 외부 Beat, 중복 Mapping, Shot 길이를 벗어난 coverage, 미커버 Beat가 있으면 결과 전체를 저장 또는 발행하지 않는다. 한 Scene에는 Beat 분석과 별도로 Shot 분석 하나만 PROCESSING일 수 있다.
AI 출력 원본은 AI 생성 Proposal의 originalSnapshot에만 보존한다. 수동 추가·분할·병합 Proposal은 현재 값 자체가 원본이므로 snapshot을 중복 저장하지 않는다. 승인 API는 트랜잭션 안에서 sourceProposalId의 고유성을 보장하며 반복 요청에는 기존 Sequence 또는 Scene을 반환한다.
위 startMarker + 전체 sourceHash 방식은 현재 구현 호환을 위한 계약이다. 새 통합 분석 pipeline에서는 다음 순서로 교체한다.
- 작품 정보와 실제 시나리오 본문을 먼저 분리한다.
- 문단 또는 source segment에 안정적인 ID를 부여하고 offset과 함께 저장한다.
- marker 하나를 찾지 못해 전체 ProposalSet을 실패시키지 않고 실패 구간만 다시 분석한다.
- 구조 Proposal의 분석 기준과 Shot 이후 파생 Artifact의 최신성을 구분한다.
- Shot 이후에는 단일 source hash 대신 dependency group별 fingerprint를 사용한다.
- 상위 변경 시 하위 정식 엔티티를 자동 보관·삭제하지 않고
RECOMPILE_NEEDED,REVIEW_NEEDED,REANALYSIS_NEEDED로 영향 범위를 표시한다.
세부 전환 기준은 Structure Analysis, Shot Specification, and Dependency DAG를 따른다.