# 인터뷰 시나리오

## 개요

인터뷰 시나리오는 영업 상담 시 사용할 질문 템플릿을 관리하고,
인터뷰 세션을 진행/기록하는 기능입니다.
카테고리별 질문 구조, 체크리스트/텍스트 답변, MD 일괄 가져오기를 지원합니다.

- **라우트**: `GET /sales/interviews`
- **미들웨어**: `auth`, `hq.member`
- **UI 기술**: Blade + React/JavaScript (API 기반, 1,076줄)

## 파일 구조

```
mng/
├── app/Http/Controllers/Sales/
│   └── InterviewScenarioController.php   # 메인 컨트롤러 (16개 메서드)
├── app/Services/Sales/
│   └── InterviewScenarioService.php      # 비즈니스 로직 서비스
├── app/Models/Interview/
│   ├── InterviewCategory.php             # 카테고리
│   ├── InterviewTemplate.php             # 템플릿 (항목)
│   ├── InterviewQuestion.php             # 질문
│   ├── InterviewSession.php              # 인터뷰 세션
│   └── InterviewAnswer.php              # 답변
└── resources/views/sales/interviews/
    └── index.blade.php                   # 메인 페이지 (1,076줄)

api/
└── database/migrations/
    ├── 2026_02_06_100000_create_interview_categories_table.php
    ├── 2026_02_06_100001_create_interview_templates_table.php
    ├── 2026_02_06_100002_create_interview_questions_table.php
    ├── 2026_02_06_100003_create_interview_sessions_table.php
    └── 2026_02_06_100004_create_interview_answers_table.php
```

## 라우트

```php
// routes/web.php (sales/interviews prefix 그룹 내)

// 페이지
GET  /interviews                            → index()           메인 페이지

// 카테고리 API
GET  /interviews/api/categories             → categories()       카테고리 목록
POST /interviews/api/categories             → storeCategory()    카테고리 생성
PUT  /interviews/api/categories/{id}        → updateCategory()   카테고리 수정
DELETE /interviews/api/categories/{id}      → destroyCategory()  카테고리 삭제

// 트리 API
GET  /interviews/api/tree                   → tree()             전체 계층 구조

// 템플릿(항목) API
POST /interviews/api/templates              → storeTemplate()    템플릿 생성
PUT  /interviews/api/templates/{id}         → updateTemplate()   템플릿 수정
DELETE /interviews/api/templates/{id}       → destroyTemplate()  템플릿 삭제

// 질문 API
POST /interviews/api/questions              → storeQuestion()    질문 생성
PUT  /interviews/api/questions/{id}         → updateQuestion()   질문 수정
DELETE /interviews/api/questions/{id}       → destroyQuestion()  질문 삭제

// 일괄 가져오기
POST /interviews/api/bulk-import            → bulkImport()       MD 파일에서 가져오기

// 세션(인터뷰) API
GET  /interviews/api/sessions               → sessions()         세션 목록 (필터)
POST /interviews/api/sessions               → storeSession()     인터뷰 시작
GET  /interviews/api/sessions/{id}          → showSession()      세션 상세
POST /interviews/api/sessions/toggle-answer → toggleAnswer()     답변 토글
POST /interviews/api/sessions/{id}/complete → completeSession()  인터뷰 완료
```

## 컨트롤러

### InterviewScenarioController

| 메서드 | HTTP | 설명 |
|--------|------|------|
| `index()` | GET | 메인 페이지 |
| `categories()` | GET | 카테고리 목록 |
| `storeCategory()` | POST | 카테고리 생성 |
| `updateCategory()` | PUT | 카테고리 수정 |
| `destroyCategory()` | DELETE | 카테고리 삭제 |
| `tree()` | GET | 전체 계층 구조 (카테고리→템플릿→질문) |
| `storeTemplate()` | POST | 템플릿 생성 |
| `updateTemplate()` | PUT | 템플릿 수정 |
| `destroyTemplate()` | DELETE | 템플릿 삭제 |
| `storeQuestion()` | POST | 질문 생성 |
| `updateQuestion()` | PUT | 질문 수정 |
| `destroyQuestion()` | DELETE | 질문 삭제 |
| `bulkImport()` | POST | MD 파일에서 일괄 가져오기 |
| `sessions()` | GET | 인터뷰 세션 목록 |
| `storeSession()` | POST | 인터뷰 시작 |
| `showSession()` | GET | 세션 상세 |
| `toggleAnswer()` | POST | 답변 토글/기록 |
| `completeSession()` | POST | 인터뷰 완료 |

### InterviewScenarioService

| 메서드 | 설명 |
|--------|------|
| `getCategories()` | 카테고리 목록 |
| `createCategory()` | 카테고리 생성 |
| `updateCategory()` | 카테고리 수정 |
| `deleteCategory()` | 카테고리 삭제 |
| `getTree()` | 전체 계층 구조 조회 |
| `createTemplate()` | 템플릿 생성 |
| `updateTemplate()` | 템플릿 수정 |
| `deleteTemplate()` | 템플릿 삭제 |
| `createQuestion()` | 질문 생성 |
| `updateQuestion()` | 질문 수정 |
| `deleteQuestion()` | 질문 삭제 |
| `bulkImport()` | MD에서 일괄 가져오기 |
| `getSessions()` | 세션 목록 (필터) |
| `startSession()` | 인터뷰 시작 |
| `getSessionDetail()` | 세션 상세 |
| `toggleAnswer()` | 답변 토글 |
| `completeSession()` | 인터뷰 완료 |

## 모델

### 데이터 계층 구조

```
InterviewCategory (카테고리)
  └── InterviewTemplate (템플릿/항목)
        └── InterviewQuestion (질문)

InterviewSession (인터뷰 세션)
  └── InterviewAnswer (답변)
```

### InterviewCategory

**테이블**: `interview_categories`

| 필드 | 타입 | 설명 |
|------|------|------|
| `tenant_id` | bigint | 테넌트 ID |
| `name` | string | 카테고리명 (예: 제조-방화셔터) |
| `description` | text | 설명 |
| `sort_order` | int | 정렬 순서 |
| `is_active` | boolean | 활성 여부 |
| `created_by` | bigint | 등록자 |

- SoftDeletes 적용
- 관계: `templates()`, `sessions()`

### InterviewTemplate

**테이블**: `interview_templates`

| 필드 | 타입 | 설명 |
|------|------|------|
| `tenant_id` | bigint | 테넌트 ID |
| `interview_category_id` | bigint (FK) | 카테고리 ID |
| `name` | string | 항목명 (예: 견적서 제작) |
| `description` | text | 설명 |
| `sort_order` | int | 정렬 순서 |
| `is_active` | boolean | 활성 여부 |

- SoftDeletes 적용
- 관계: `category()`, `questions()`

### InterviewQuestion

**테이블**: `interview_questions`

| 필드 | 타입 | 설명 |
|------|------|------|
| `tenant_id` | bigint | 테넌트 ID |
| `interview_template_id` | bigint (FK) | 템플릿 ID |
| `question_text` | string(500) | 질문 텍스트 |
| `question_type` | string | **checkbox** / **text** |
| `options` | json | 선택지 (배열) |
| `is_required` | boolean | 필수 여부 |
| `sort_order` | int | 정렬 순서 |
| `is_active` | boolean | 활성 여부 |

- SoftDeletes 적용
- 관계: `template()`

#### 질문 타입

| 타입 | 설명 | 답변 방식 |
|------|------|----------|
| `checkbox` | 체크 질문 | is_checked 토글 |
| `text` | 서술형 질문 | answer_text 입력 |

### InterviewSession

**테이블**: `interview_sessions`

| 필드 | 타입 | 설명 |
|------|------|------|
| `tenant_id` | bigint | 테넌트 ID |
| `interview_category_id` | bigint (FK) | 사용한 카테고리 ID |
| `interviewer_id` | bigint (FK) | 면담자(매니저) ID |
| `interviewee_name` | string(100) | 면담 상대 이름 |
| `interviewee_company` | string(200) | 면담 상대 회사 |
| `interview_date` | date | 면담 일자 |
| `status` | string | **in_progress** / **completed** |
| `total_questions` | int | 총 질문 수 |
| `answered_questions` | int | 답변 완료 수 |
| `memo` | text | 메모 |
| `completed_at` | timestamp | 완료 일시 |

- SoftDeletes 적용
- 관계: `category()`, `interviewer()`, `answers()`

### InterviewAnswer

**테이블**: `interview_answers`

| 필드 | 타입 | 설명 |
|------|------|------|
| `tenant_id` | bigint | 테넌트 ID |
| `interview_session_id` | bigint (FK) | 세션 ID |
| `interview_question_id` | bigint (FK) | 질문 ID |
| `interview_template_id` | bigint (FK) | 템플릿 ID |
| `is_checked` | boolean | 체크 여부 (checkbox 유형) |
| `answer_text` | text | 답변 텍스트 (text 유형) |
| `memo` | text | 메모 |

### 인터뷰 진행 흐름

```
1. 카테고리 선택 + 면담 상대 정보 입력
   → storeSession() → 세션 생성 (status: in_progress)
   → 해당 카테고리의 모든 질문에 대해 빈 Answer 생성

2. 질문별 답변 기록
   → toggleAnswer() → is_checked 토글 / answer_text 저장
   → answered_questions 카운트 갱신

3. 인터뷰 완료
   → completeSession() → status: completed, completed_at 기록
```

## 뷰 구성

### index.blade.php

```
┌─ 페이지 헤더 ──────────────────────
│  제목: "인터뷰 시나리오"
│  [카테고리 추가] [일괄 가져오기] 버튼
│
├─ 좌측 사이드바 ───────────────────
│  카테고리 트리
│  ├── 카테고리 A
│  │   ├── 템플릿 1 (질문 3개)
│  │   └── 템플릿 2 (질문 5개)
│  └── 카테고리 B
│      └── 템플릿 3 (질문 2개)
│
├─ 우측 메인 영역 ──────────────────
│  ├─ 템플릿 편집 모드
│  │   질문 목록 + 추가/수정/삭제
│  │   질문 타입(checkbox/text) + 옵션
│  │
│  └─ 인터뷰 세션 모드
│      면담 상대 정보 + 날짜
│      질문별 체크/답변 기록
│      진행률 표시
│      [완료] 버튼
│
└─ 세션 목록 ───────────────────────
   과거 인터뷰 기록 (필터: 카테고리, 날짜)
   면담자 | 상대방 | 회사 | 날짜 | 완료율 | 상태
```

## HTMX 호환성

- JavaScript/React 기반 페이지이므로 **HX-Redirect 필요**
- API 호출로 동적 CRUD 관리
- `@push('scripts')` 블록에 스크립트 포함
