---
description: 웹소설 챕터를 씬/라인 데이터로 변환하여 D1 시드 SQL 생성
---

## User Input

```text
$ARGUMENTS
```

User input **must** be considered (if not empty).

## Overview

마크다운 원고를 인터랙티브 씬/라인 데이터로 변환하여 D1 시드 SQL을 생성합니다.

**실행 방법:**
- `/rovel.seed content/rovel/협회 소속 양호선생님/chapters/001.md` (단일 파일)
- `/rovel.seed 협회 소속 양호선생님 1화` (작품명 + 화수)
- `/rovel.seed 협회 소속 양호선생님 1-8화` (범위)
- `/rovel.seed 협회 소속 양호선생님 전체` (모든 챕터)

**워크플로우:**
```
┌─────────────────────────────────────────────────────────┐
│  Phase 1: 입력 파싱                                      │
│  - 파일 경로 또는 작품명+화수 파싱                        │
│  - 작품 폴더 및 캐릭터 ID 매핑 로드                       │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  Phase 2: 마크다운 파싱                                  │
│  - 씬 구분 (*** 기준)                                    │
│  - 라인 타입 감지 (대화/나레이션/효과음 등)               │
│  - 시스템 카드 파싱                                      │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  Phase 3: 메타데이터 추출                                │
│  - 화자 추론 (컨텍스트 + 말투 분석)                      │
│  - 씬 정보 추출 (시간/장소/분위기)                       │
│  - is_playable 판정                                     │
└─────────────────────────────────────────────────────────┘
                          ↓
┌─────────────────────────────────────────────────────────┐
│  Phase 4: SQL 생성                                       │
│  - INSERT 문 생성                                        │
│  - 파일 저장 및 안내                                     │
└─────────────────────────────────────────────────────────┘
```

---

## Phase 1: 입력 파싱

### 입력 유형 분석

```yaml
Case A - 절대/상대 경로:
  입력: content/rovel/협회 소속 양호선생님/chapters/001.md
  해석: 해당 파일 직접 처리

Case B - 작품명 + 화수:
  입력: 협회 소속 양호선생님 3화
  해석: content/rovel/협회 소속 양호선생님/chapters/003.md

Case C - 작품명 + 범위:
  입력: 협회 소속 양호선생님 1-8화
  해석: 001.md ~ 008.md 순차 처리

Case D - 작품명 + 전체:
  입력: 협회 소속 양호선생님 전체
  해석: chapters/ 폴더의 모든 .md 파일
```

### 캐릭터 ID 매핑 로드

작품 폴더의 `인물목록.md`를 읽어 캐릭터 이름 → ID 매핑 생성:

```yaml
매핑 생성 규칙:
  - 주인공 (한시우): char-{영문이름}-001
  - 히로인/주요 인물: char-{영문이름}-001
  - 조연: char-{영문이름}-001

예시 (협회 소속 양호선생님):
  한시우: char-hansiuw-001 (주인공)
  자화연: char-jahwayeon-001
  박준혁: char-parkjunhyuk-001
  김 과장: char-kimgwajang-001
  루나: char-luna-001
```

### ID 체계

```yaml
작품 ID: work-{작품영문코드}-001
  예: work-yanghosam-001

챕터 ID: chapter-{3자리화수}
  예: chapter-001, chapter-008

씬 ID: scene-{3자리화수}-{2자리순서}
  예: scene-001-01, scene-008-03

라인 ID: line-{3자리화수}-{2자리씬순서}-{3자리라인순서}
  예: line-001-01-001, line-008-03-015

시스템 카드 ID: syscard-{3자리화수}-{2자리씬순서}-{2자리순서}
  예: syscard-001-02-01
```

---

## Phase 2: 마크다운 파싱

### 라인 타입 감지 규칙

```typescript
// 우선순위 순서로 적용
1. 빈 줄만 있음 → skip
2. `***` → divider (씬 구분)
3. `[제목]` 로 시작 (단, [다음 제외) → system (시스템 카드 시작)
4. `- ` 로 시작 → sfx (효과음)
5. `"` 로 시작하고 `"` 로 끝남 → dialogue (대화)
6. `'` 로 시작하고 `'` 로 끝남 → thought (속마음)
7. 그 외 → narration (나레이션)
```

### 시스템 카드 파싱

```markdown
입력:
[진맥 판독]
[대상: 박준혁, 28세, B급 헌터]
[외상: 좌측 어깨 베임 (깊이 1.2cm)]
[내상: 마력 과다 사용으로 인한 피로 누적]

출력:
{
  type: "diagnosis",
  title: "진맥 판독",
  content: [
    { label: "대상", value: "박준혁, 28세, B급 헌터" },
    { label: "외상", value: "좌측 어깨 베임 (깊이 1.2cm)" },
    { label: "내상", value: "마력 과다 사용으로 인한 피로 누적" }
  ],
  summary: "대상: 박준혁",
  isPlayable: true
}
```

### 시스템 카드 타입 매핑

| 제목 키워드 | 타입 | isPlayable |
|------------|------|------------|
| 진맥 판독, 분석, 스캔 | diagnosis | true |
| 잠재력 분석 | potential | true |
| 환자 심리 분석, 환자 상태 | psychology | true |
| 은밀 치유 | skill_active | true |
| 신규 기능 감지, 잠재 해방 | skill_unlock | false |
| 경고, 숨겨진 | warning | false |
| 일일 진료 현황, 권장 행동 | info_update | false |
| 그 외 | info_update | false |

---

## Phase 3: 메타데이터 추출

### 화자 추론 규칙

```yaml
1. 이전 3줄 컨텍스트 분석:
   "자화연이 고개를 들었다."
   "......" → speaker: char-jahwayeon-001

2. 대사 내 특징적 표현:
   "본좌" → 자화연
   "선생님" → 박준혁 (주인공에게 말할 때)

3. 주인공 여부:
   - 내면 독백 ('생각') → isProtagonist: true
   - "나는", "내가" 주어 → isProtagonist: true
```

### 씬 메타데이터 추출

```yaml
시간 감지:
  - "밤 11시", "새벽 2시", "오후 5시" 등
  - 첫 번째 매칭 사용

장소 감지:
  - "의무실", "협회", "던전" 등 키워드
  - 씬 첫 부분에서 추출

분위기 감지:
  - "살기", "긴장", "평온", "따뜻" 등
  - 시스템 카드나 나레이션에서 추출
```

### is_playable 판정

```yaml
씬이 플레이 가능한 경우:
  1. isPlayable: true인 시스템 카드가 1개 이상
  2. 주요 캐릭터와의 대화 장면
  3. 선택지가 제시될 수 있는 상황

is_playable: true 조건:
  - diagnosis, potential, psychology, skill_active 타입 카드 존재
  - 주요 히로인과 첫 대면 장면
```

---

## Phase 4: SQL 생성

### 출력 파일

```yaml
단일 파일:
  입력: 001.md
  출력: 001-seed.sql

범위/전체:
  입력: 1-8화
  출력: chapters-seed.sql (병합된 파일)
```

### SQL 템플릿

```sql
-- Chapter chapter-{NNN} scenes and lines
-- Auto-generated from markdown

-- Delete existing data for this chapter
DELETE FROM system_cards WHERE line_id IN (SELECT id FROM lines WHERE scene_id IN (SELECT id FROM scenes WHERE chapter_id = 'chapter-{NNN}'));
DELETE FROM lines WHERE scene_id IN (SELECT id FROM scenes WHERE chapter_id = 'chapter-{NNN}');
DELETE FROM scenes WHERE chapter_id = 'chapter-{NNN}';

-- 챕터가 없으면 생성
INSERT OR IGNORE INTO chapters (id, work_id, number, title, is_free, price, status, view_count, created_at, updated_at)
VALUES (
  'chapter-{NNN}',
  '{work_id}',
  {number},
  '{title}',
  {is_free},
  {price},
  'published',
  0,
  {timestamp},
  {timestamp}
);

-- Scene 1: {title}
INSERT INTO scenes (id, chapter_id, "order", title, location, time, mood, is_playable, play_description, character_ids, created_at) VALUES (
  'scene-{NNN}-{NN}',
  'chapter-{NNN}',
  {order},
  '{title}',
  '{location}',
  '{time}',
  '{mood}',
  {is_playable},
  '{play_description}',
  '{character_ids_json}',
  {timestamp}
);

-- Lines for scene {N}
INSERT INTO lines (id, scene_id, "order", type, content, speaker_id, is_protagonist, created_at) VALUES
  ('line-{NNN}-{NN}-{NNN}', 'scene-{NNN}-{NN}', {order}, '{type}', '{content}', {speaker_id}, {is_protagonist}, {timestamp}),
  ...;

-- System cards for scene {N}
INSERT INTO system_cards (id, line_id, type, title, content, summary, is_playable, choice_label, created_at) VALUES
  ('syscard-{NNN}-{NN}-{NN}', 'line-{NNN}-{NN}-{NNN}', '{type}', '{title}', '{content_json}', '{summary}', {is_playable}, '{choice_label}', {timestamp});
```

### SQL 이스케이프 규칙

```yaml
작은따옴표: ' → ''
줄바꿈: \n → 그대로 (TEXT 필드)
JSON: 쌍따옴표 사용, 이스케이프
NULL: speaker_id 없으면 NULL (문자열 'NULL' 아님)
```

---

## 실행 예시

### 예시 1: 단일 파일

```
/rovel.seed content/rovel/협회 소속 양호선생님/chapters/008.md
```

**출력:**
```
## 씬 변환 완료

**파일**: `content/rovel/협회 소속 양호선생님/chapters/008.md`
**챕터 ID**: chapter-008

### 생성된 데이터

| 항목 | 개수 |
|------|------|
| 씬 | 12개 |
| 라인 | 156개 |
| 시스템 카드 | 3개 |
| 플레이 가능 씬 | 2개 |

### 등장 캐릭터

| 캐릭터 | ID | 대사 수 |
|--------|-----|---------|
| 루나 | char-luna-001 | 24 |
| 한시우 | (주인공) | 18 |

### 생성된 SQL

**파일**: `content/rovel/협회 소속 양호선생님/chapters/008-seed.sql`

### 다음 단계

1. SQL 확인:
   cat content/rovel/협회 소속 양호선생님/chapters/008-seed.sql

2. 로컬 D1 적용:
   npx wrangler d1 execute rovel-db --local --file=content/rovel/협회 소속 양호선생님/chapters/008-seed.sql

3. 원격 D1 적용:
   npx wrangler d1 execute rovel-db --remote --file=content/rovel/협회 소속 양호선생님/chapters/008-seed.sql
```

### 예시 2: 범위 변환

```
/rovel.seed 협회 소속 양호선생님 1-8화
```

**출력:**
```
## 씬 변환 완료 (8개 챕터)

### 변환 결과

| 화수 | 씬 | 라인 | 시스템 카드 | 플레이 가능 |
|------|-----|------|-------------|-------------|
| 1화 | 12 | 89 | 2 | 1 |
| 2화 | 10 | 102 | 3 | 2 |
| ... | | | | |
| 8화 | 14 | 156 | 3 | 2 |
| **합계** | **92** | **1,024** | **18** | **12** |

### 생성된 SQL

**파일**: `content/rovel/협회 소속 양호선생님/chapters-seed.sql`

### 다음 단계

로컬 D1 적용:
npx wrangler d1 execute rovel-db --local --file=content/rovel/협회 소속 양호선생님/chapters-seed.sql

원격 D1 적용:
npx wrangler d1 execute rovel-db --remote --file=content/rovel/협회 소속 양호선생님/chapters-seed.sql
```

---

## 캐릭터 ID 매핑 (협회 소속 양호선생님)

```yaml
주인공:
  한시우: char-hansiuw-001

히로인:
  자화연: char-jahwayeon-001
  루나: char-luna-001

조연:
  박준혁: char-parkjunhyuk-001
  김 과장: char-kimgwajang-001
  김수진: char-kimsujin-001
```

### 새 캐릭터 등장 시

인물목록.md에 없는 새 캐릭터가 등장하면:
1. 경고 메시지 출력
2. 임시 ID 생성 (`char-{이름영문}-temp`)
3. 인물목록.md 업데이트 권장

---

## Reference Files

| 유형 | 경로 | 용도 |
|------|------|------|
| 변환 가이드 | `rules/chapter-to-scene.md` | 마크다운 문법 참조 |
| 인물목록 | `content/rovel/{작품명}/인물목록.md` | 캐릭터 ID 매핑 |
| 기존 시드 | `scripts/seed-d1.sql` | SQL 형식 참조 |
| DB 스키마 | `src/server/db/schema.ts` | 테이블 구조 참조 |

---

## Important Notes

### 변환 시 주의사항

```yaml
1. 캐릭터 ID 매핑:
   - 인물목록.md 먼저 확인
   - 없는 캐릭터는 경고 후 임시 ID

2. 시스템 카드:
   - [제목] 다음 줄들이 필드
   - 빈 줄이나 다른 타입 만나면 종료
   - JSON 형식으로 content 저장

3. 화자 추론:
   - 이전 컨텍스트 우선
   - 말투 패턴으로 보조
   - 불확실하면 NULL

4. SQL 이스케이프:
   - 작은따옴표는 ''로
   - NULL은 문자열 아닌 키워드
```

### 스키마 호환성

```yaml
현재 스키마:
  - scenes.is_playable: 플레이 가능 여부
  - scenes.character_ids: JSON 배열
  - system_cards: lines.id로 연결

체크 필요:
  - works 테이블에 작품 존재 여부
  - characters 테이블에 캐릭터 존재 여부
```

### 작품별 설정

새 작품 추가 시:
1. 작품 ID 결정 (`work-{코드}-001`)
2. 캐릭터 ID 매핑 정의
3. 인물목록.md에 캐릭터 정보 확인
