diff --git a/app/Http/Controllers/Sales/InterviewScenarioController.php b/app/Http/Controllers/Sales/InterviewScenarioController.php
new file mode 100644
index 00000000..d169ff55
--- /dev/null
+++ b/app/Http/Controllers/Sales/InterviewScenarioController.php
@@ -0,0 +1,227 @@
+header('HX-Request')) {
+ return response('', 200)->header('HX-Redirect', route('sales.interviews.index'));
+ }
+
+ return view('sales.interviews.index');
+ }
+
+ // ============================================================
+ // 카테고리 API
+ // ============================================================
+
+ public function categories(): JsonResponse
+ {
+ return response()->json($this->service->getCategories());
+ }
+
+ public function storeCategory(Request $request): JsonResponse
+ {
+ $validated = $request->validate([
+ 'name' => 'required|string|max:100',
+ 'description' => 'nullable|string',
+ ]);
+
+ $category = $this->service->createCategory($validated);
+
+ return response()->json($category, 201);
+ }
+
+ public function updateCategory(Request $request, int $id): JsonResponse
+ {
+ $validated = $request->validate([
+ 'name' => 'required|string|max:100',
+ 'description' => 'nullable|string',
+ ]);
+
+ $category = $this->service->updateCategory($id, $validated);
+
+ return response()->json($category);
+ }
+
+ public function destroyCategory(int $id): JsonResponse
+ {
+ $this->service->deleteCategory($id);
+
+ return response()->json(['message' => '삭제되었습니다.']);
+ }
+
+ // ============================================================
+ // 트리 API
+ // ============================================================
+
+ public function tree(): JsonResponse
+ {
+ return response()->json($this->service->getTree());
+ }
+
+ // ============================================================
+ // 템플릿(항목) API
+ // ============================================================
+
+ public function storeTemplate(Request $request): JsonResponse
+ {
+ $validated = $request->validate([
+ 'interview_category_id' => 'required|integer|exists:interview_categories,id',
+ 'name' => 'required|string|max:200',
+ 'description' => 'nullable|string',
+ ]);
+
+ $template = $this->service->createTemplate($validated);
+
+ return response()->json($template, 201);
+ }
+
+ public function updateTemplate(Request $request, int $id): JsonResponse
+ {
+ $validated = $request->validate([
+ 'name' => 'required|string|max:200',
+ 'description' => 'nullable|string',
+ ]);
+
+ $template = $this->service->updateTemplate($id, $validated);
+
+ return response()->json($template);
+ }
+
+ public function destroyTemplate(int $id): JsonResponse
+ {
+ $this->service->deleteTemplate($id);
+
+ return response()->json(['message' => '삭제되었습니다.']);
+ }
+
+ // ============================================================
+ // 질문 API
+ // ============================================================
+
+ public function storeQuestion(Request $request): JsonResponse
+ {
+ $validated = $request->validate([
+ 'interview_template_id' => 'required|integer|exists:interview_templates,id',
+ 'question_text' => 'required|string|max:500',
+ 'question_type' => 'nullable|string|in:checkbox,text',
+ 'is_required' => 'nullable|boolean',
+ ]);
+
+ $question = $this->service->createQuestion($validated);
+
+ return response()->json($question, 201);
+ }
+
+ public function updateQuestion(Request $request, int $id): JsonResponse
+ {
+ $validated = $request->validate([
+ 'question_text' => 'required|string|max:500',
+ 'question_type' => 'nullable|string|in:checkbox,text',
+ 'is_required' => 'nullable|boolean',
+ ]);
+
+ $question = $this->service->updateQuestion($id, $validated);
+
+ return response()->json($question);
+ }
+
+ public function destroyQuestion(int $id): JsonResponse
+ {
+ $this->service->deleteQuestion($id);
+
+ return response()->json(['message' => '삭제되었습니다.']);
+ }
+
+ // ============================================================
+ // MD 파일 일괄 가져오기
+ // ============================================================
+
+ public function bulkImport(Request $request): JsonResponse
+ {
+ $validated = $request->validate([
+ 'category_id' => 'required|integer|exists:interview_categories,id',
+ 'templates' => 'required|array|min:1',
+ 'templates.*.name' => 'required|string|max:200',
+ 'templates.*.questions' => 'required|array|min:1',
+ 'templates.*.questions.*' => 'required|string|max:500',
+ ]);
+
+ $result = $this->service->bulkImport($validated['category_id'], $validated['templates']);
+
+ return response()->json($result, 201);
+ }
+
+ // ============================================================
+ // 세션 API
+ // ============================================================
+
+ public function sessions(Request $request): JsonResponse
+ {
+ $filters = $request->only(['status', 'category_id']);
+ $sessions = $this->service->getSessions($filters);
+
+ return response()->json($sessions);
+ }
+
+ public function storeSession(Request $request): JsonResponse
+ {
+ $validated = $request->validate([
+ 'interview_category_id' => 'required|integer|exists:interview_categories,id',
+ 'interviewee_name' => 'nullable|string|max:100',
+ 'interviewee_company' => 'nullable|string|max:200',
+ 'interview_date' => 'nullable|date',
+ 'memo' => 'nullable|string',
+ ]);
+
+ $session = $this->service->startSession($validated);
+
+ return response()->json($session, 201);
+ }
+
+ public function showSession(int $id): JsonResponse
+ {
+ $session = $this->service->getSessionDetail($id);
+
+ return response()->json($session);
+ }
+
+ public function toggleAnswer(Request $request): JsonResponse
+ {
+ $validated = $request->validate([
+ 'session_id' => 'required|integer',
+ 'question_id' => 'required|integer',
+ 'answer_text' => 'nullable|string',
+ 'memo' => 'nullable|string',
+ ]);
+
+ $answer = $this->service->toggleAnswer($validated);
+
+ return response()->json($answer);
+ }
+
+ public function completeSession(int $id): JsonResponse
+ {
+ $session = $this->service->completeSession($id);
+
+ return response()->json($session);
+ }
+}
diff --git a/app/Models/Interview/InterviewAnswer.php b/app/Models/Interview/InterviewAnswer.php
new file mode 100644
index 00000000..cd484388
--- /dev/null
+++ b/app/Models/Interview/InterviewAnswer.php
@@ -0,0 +1,40 @@
+ 'boolean',
+ ];
+
+ public function session()
+ {
+ return $this->belongsTo(InterviewSession::class, 'interview_session_id');
+ }
+
+ public function question()
+ {
+ return $this->belongsTo(InterviewQuestion::class, 'interview_question_id');
+ }
+
+ public function template()
+ {
+ return $this->belongsTo(InterviewTemplate::class, 'interview_template_id');
+ }
+}
diff --git a/app/Models/Interview/InterviewCategory.php b/app/Models/Interview/InterviewCategory.php
new file mode 100644
index 00000000..dac8c0af
--- /dev/null
+++ b/app/Models/Interview/InterviewCategory.php
@@ -0,0 +1,39 @@
+ 'boolean',
+ 'sort_order' => 'integer',
+ ];
+
+ public function templates()
+ {
+ return $this->hasMany(InterviewTemplate::class, 'interview_category_id');
+ }
+
+ public function sessions()
+ {
+ return $this->hasMany(InterviewSession::class, 'interview_category_id');
+ }
+}
diff --git a/app/Models/Interview/InterviewQuestion.php b/app/Models/Interview/InterviewQuestion.php
new file mode 100644
index 00000000..896f6c56
--- /dev/null
+++ b/app/Models/Interview/InterviewQuestion.php
@@ -0,0 +1,39 @@
+ 'array',
+ 'is_required' => 'boolean',
+ 'is_active' => 'boolean',
+ 'sort_order' => 'integer',
+ ];
+
+ public function template()
+ {
+ return $this->belongsTo(InterviewTemplate::class, 'interview_template_id');
+ }
+}
diff --git a/app/Models/Interview/InterviewSession.php b/app/Models/Interview/InterviewSession.php
new file mode 100644
index 00000000..c0733bff
--- /dev/null
+++ b/app/Models/Interview/InterviewSession.php
@@ -0,0 +1,52 @@
+ 'date',
+ 'completed_at' => 'datetime',
+ 'total_questions' => 'integer',
+ 'answered_questions' => 'integer',
+ ];
+
+ public function category()
+ {
+ return $this->belongsTo(InterviewCategory::class, 'interview_category_id');
+ }
+
+ public function interviewer()
+ {
+ return $this->belongsTo(\App\Models\User::class, 'interviewer_id');
+ }
+
+ public function answers()
+ {
+ return $this->hasMany(InterviewAnswer::class, 'interview_session_id');
+ }
+}
diff --git a/app/Models/Interview/InterviewTemplate.php b/app/Models/Interview/InterviewTemplate.php
new file mode 100644
index 00000000..3b851806
--- /dev/null
+++ b/app/Models/Interview/InterviewTemplate.php
@@ -0,0 +1,40 @@
+ 'boolean',
+ 'sort_order' => 'integer',
+ ];
+
+ public function category()
+ {
+ return $this->belongsTo(InterviewCategory::class, 'interview_category_id');
+ }
+
+ public function questions()
+ {
+ return $this->hasMany(InterviewQuestion::class, 'interview_template_id');
+ }
+}
diff --git a/app/Services/Sales/InterviewScenarioService.php b/app/Services/Sales/InterviewScenarioService.php
new file mode 100644
index 00000000..6a35afb2
--- /dev/null
+++ b/app/Services/Sales/InterviewScenarioService.php
@@ -0,0 +1,340 @@
+orderBy('id')
+ ->get();
+ }
+
+ public function createCategory(array $data): InterviewCategory
+ {
+ $tenantId = session('selected_tenant_id', 1);
+ $maxSort = InterviewCategory::max('sort_order') ?? 0;
+
+ return InterviewCategory::create([
+ 'tenant_id' => $tenantId,
+ 'name' => $data['name'],
+ 'description' => $data['description'] ?? null,
+ 'sort_order' => $maxSort + 1,
+ 'is_active' => true,
+ 'created_by' => auth()->id(),
+ 'updated_by' => auth()->id(),
+ ]);
+ }
+
+ public function updateCategory(int $id, array $data): InterviewCategory
+ {
+ $category = InterviewCategory::findOrFail($id);
+ $category->update([
+ 'name' => $data['name'],
+ 'description' => $data['description'] ?? null,
+ 'updated_by' => auth()->id(),
+ ]);
+
+ return $category->fresh();
+ }
+
+ public function deleteCategory(int $id): void
+ {
+ $category = InterviewCategory::findOrFail($id);
+ $category->update(['deleted_by' => auth()->id()]);
+ $category->delete();
+ }
+
+ // ============================================================
+ // 템플릿(항목) CRUD
+ // ============================================================
+
+ public function createTemplate(array $data): InterviewTemplate
+ {
+ $tenantId = session('selected_tenant_id', 1);
+ $maxSort = InterviewTemplate::where('interview_category_id', $data['interview_category_id'])
+ ->max('sort_order') ?? 0;
+
+ return InterviewTemplate::create([
+ 'tenant_id' => $tenantId,
+ 'interview_category_id' => $data['interview_category_id'],
+ 'name' => $data['name'],
+ 'description' => $data['description'] ?? null,
+ 'sort_order' => $maxSort + 1,
+ 'is_active' => true,
+ 'created_by' => auth()->id(),
+ 'updated_by' => auth()->id(),
+ ]);
+ }
+
+ public function updateTemplate(int $id, array $data): InterviewTemplate
+ {
+ $template = InterviewTemplate::findOrFail($id);
+ $template->update([
+ 'name' => $data['name'],
+ 'description' => $data['description'] ?? null,
+ 'updated_by' => auth()->id(),
+ ]);
+
+ return $template->fresh();
+ }
+
+ public function deleteTemplate(int $id): void
+ {
+ $template = InterviewTemplate::findOrFail($id);
+ $template->update(['deleted_by' => auth()->id()]);
+ $template->delete();
+ }
+
+ // ============================================================
+ // 질문 CRUD
+ // ============================================================
+
+ public function createQuestion(array $data): InterviewQuestion
+ {
+ $tenantId = session('selected_tenant_id', 1);
+ $maxSort = InterviewQuestion::where('interview_template_id', $data['interview_template_id'])
+ ->max('sort_order') ?? 0;
+
+ return InterviewQuestion::create([
+ 'tenant_id' => $tenantId,
+ 'interview_template_id' => $data['interview_template_id'],
+ 'question_text' => $data['question_text'],
+ 'question_type' => $data['question_type'] ?? 'checkbox',
+ 'is_required' => $data['is_required'] ?? false,
+ 'sort_order' => $maxSort + 1,
+ 'is_active' => true,
+ 'created_by' => auth()->id(),
+ 'updated_by' => auth()->id(),
+ ]);
+ }
+
+ public function updateQuestion(int $id, array $data): InterviewQuestion
+ {
+ $question = InterviewQuestion::findOrFail($id);
+ $question->update([
+ 'question_text' => $data['question_text'],
+ 'question_type' => $data['question_type'] ?? $question->question_type,
+ 'is_required' => $data['is_required'] ?? $question->is_required,
+ 'updated_by' => auth()->id(),
+ ]);
+
+ return $question->fresh();
+ }
+
+ public function deleteQuestion(int $id): void
+ {
+ $question = InterviewQuestion::findOrFail($id);
+ $question->update(['deleted_by' => auth()->id()]);
+ $question->delete();
+ }
+
+ // ============================================================
+ // MD 파일 일괄 가져오기
+ // ============================================================
+
+ public function bulkImport(int $categoryId, array $templates): array
+ {
+ return DB::transaction(function () use ($categoryId, $templates) {
+ $tenantId = session('selected_tenant_id', 1);
+ $userId = auth()->id();
+ $maxTemplateSort = InterviewTemplate::where('interview_category_id', $categoryId)
+ ->max('sort_order') ?? 0;
+
+ $createdTemplates = 0;
+ $createdQuestions = 0;
+
+ foreach ($templates as $tpl) {
+ $maxTemplateSort++;
+ $template = InterviewTemplate::create([
+ 'tenant_id' => $tenantId,
+ 'interview_category_id' => $categoryId,
+ 'name' => $tpl['name'],
+ 'sort_order' => $maxTemplateSort,
+ 'is_active' => true,
+ 'created_by' => $userId,
+ 'updated_by' => $userId,
+ ]);
+ $createdTemplates++;
+
+ $questionSort = 0;
+ foreach ($tpl['questions'] as $questionText) {
+ $questionSort++;
+ InterviewQuestion::create([
+ 'tenant_id' => $tenantId,
+ 'interview_template_id' => $template->id,
+ 'question_text' => $questionText,
+ 'question_type' => 'checkbox',
+ 'is_required' => false,
+ 'sort_order' => $questionSort,
+ 'is_active' => true,
+ 'created_by' => $userId,
+ 'updated_by' => $userId,
+ ]);
+ $createdQuestions++;
+ }
+ }
+
+ return [
+ 'templates_created' => $createdTemplates,
+ 'questions_created' => $createdQuestions,
+ ];
+ });
+ }
+
+ // ============================================================
+ // 전체 트리 조회
+ // ============================================================
+
+ public function getTree()
+ {
+ return InterviewCategory::with([
+ 'templates' => function ($q) {
+ $q->orderBy('sort_order')->orderBy('id');
+ $q->with(['questions' => function ($q2) {
+ $q2->orderBy('sort_order')->orderBy('id');
+ }]);
+ },
+ ])
+ ->orderBy('sort_order')
+ ->orderBy('id')
+ ->get();
+ }
+
+ // ============================================================
+ // 세션 관리
+ // ============================================================
+
+ public function getSessions(array $filters = [])
+ {
+ $query = InterviewSession::with(['category', 'interviewer'])
+ ->orderByDesc('interview_date')
+ ->orderByDesc('id');
+
+ if (!empty($filters['status'])) {
+ $query->where('status', $filters['status']);
+ }
+
+ if (!empty($filters['category_id'])) {
+ $query->where('interview_category_id', $filters['category_id']);
+ }
+
+ return $query->paginate(20);
+ }
+
+ public function startSession(array $data): InterviewSession
+ {
+ return DB::transaction(function () use ($data) {
+ $tenantId = session('selected_tenant_id', 1);
+ $categoryId = $data['interview_category_id'];
+
+ // 카테고리의 모든 활성 템플릿과 질문 가져오기
+ $templates = InterviewTemplate::where('interview_category_id', $categoryId)
+ ->where('is_active', true)
+ ->with(['questions' => function ($q) {
+ $q->where('is_active', true)->orderBy('sort_order');
+ }])
+ ->orderBy('sort_order')
+ ->get();
+
+ $totalQuestions = $templates->sum(fn($t) => $t->questions->count());
+
+ // 세션 생성
+ $session = InterviewSession::create([
+ 'tenant_id' => $tenantId,
+ 'interview_category_id' => $categoryId,
+ 'interviewer_id' => auth()->id(),
+ 'interviewee_name' => $data['interviewee_name'] ?? null,
+ 'interviewee_company' => $data['interviewee_company'] ?? null,
+ 'interview_date' => $data['interview_date'] ?? now()->toDateString(),
+ 'status' => 'in_progress',
+ 'total_questions' => $totalQuestions,
+ 'answered_questions' => 0,
+ 'memo' => $data['memo'] ?? null,
+ 'created_by' => auth()->id(),
+ 'updated_by' => auth()->id(),
+ ]);
+
+ // 모든 질문에 대해 빈 답변 레코드 생성
+ foreach ($templates as $template) {
+ foreach ($template->questions as $question) {
+ InterviewAnswer::create([
+ 'tenant_id' => $tenantId,
+ 'interview_session_id' => $session->id,
+ 'interview_question_id' => $question->id,
+ 'interview_template_id' => $template->id,
+ 'is_checked' => false,
+ ]);
+ }
+ }
+
+ return $session;
+ });
+ }
+
+ public function getSessionDetail(int $id)
+ {
+ return InterviewSession::with([
+ 'category',
+ 'interviewer',
+ 'answers' => function ($q) {
+ $q->with(['question', 'template']);
+ },
+ ])->findOrFail($id);
+ }
+
+ public function toggleAnswer(array $data): InterviewAnswer
+ {
+ $answer = InterviewAnswer::where('interview_session_id', $data['session_id'])
+ ->where('interview_question_id', $data['question_id'])
+ ->firstOrFail();
+
+ $answer->update([
+ 'is_checked' => !$answer->is_checked,
+ 'answer_text' => $data['answer_text'] ?? $answer->answer_text,
+ 'memo' => $data['memo'] ?? $answer->memo,
+ ]);
+
+ // answered_questions 갱신
+ $session = InterviewSession::findOrFail($data['session_id']);
+ $answeredCount = InterviewAnswer::where('interview_session_id', $session->id)
+ ->where('is_checked', true)
+ ->count();
+ $session->update([
+ 'answered_questions' => $answeredCount,
+ 'updated_by' => auth()->id(),
+ ]);
+
+ return $answer->fresh();
+ }
+
+ public function completeSession(int $id): InterviewSession
+ {
+ $session = InterviewSession::findOrFail($id);
+
+ $answeredCount = InterviewAnswer::where('interview_session_id', $session->id)
+ ->where('is_checked', true)
+ ->count();
+
+ $session->update([
+ 'status' => 'completed',
+ 'answered_questions' => $answeredCount,
+ 'completed_at' => now(),
+ 'updated_by' => auth()->id(),
+ ]);
+
+ return $session->fresh();
+ }
+}
diff --git a/database/seeders/InterviewMenuSeeder.php b/database/seeders/InterviewMenuSeeder.php
new file mode 100644
index 00000000..c468144e
--- /dev/null
+++ b/database/seeders/InterviewMenuSeeder.php
@@ -0,0 +1,59 @@
+where('name', '영업관리')
+ ->whereNull('parent_id')
+ ->whereNull('deleted_at')
+ ->get();
+
+ if ($salesMenus->isEmpty()) {
+ $this->command->error('영업관리 메뉴를 찾을 수 없습니다.');
+ return;
+ }
+
+ foreach ($salesMenus as $salesMenu) {
+ $tenantId = $salesMenu->tenant_id;
+ $label = $tenantId ? "tenant_id={$tenantId}" : 'global(tenant_id=null)';
+
+ // 이미 존재하는지 확인
+ $exists = Menu::withoutGlobalScopes()
+ ->where('parent_id', $salesMenu->id)
+ ->where('name', '인터뷰 시나리오')
+ ->whereNull('deleted_at')
+ ->exists();
+
+ if ($exists) {
+ $this->command->info("[{$label}] 인터뷰 시나리오 메뉴가 이미 존재합니다.");
+ continue;
+ }
+
+ // 마지막 sort_order 확인
+ $maxSort = Menu::withoutGlobalScopes()
+ ->where('parent_id', $salesMenu->id)
+ ->whereNull('deleted_at')
+ ->max('sort_order') ?? 0;
+
+ Menu::withoutGlobalScopes()->create([
+ 'tenant_id' => $tenantId,
+ 'parent_id' => $salesMenu->id,
+ 'name' => '인터뷰 시나리오',
+ 'url' => '/sales/interviews',
+ 'icon' => 'clipboard-check',
+ 'sort_order' => $maxSort + 1,
+ 'is_active' => true,
+ ]);
+
+ $this->command->info("[{$label}] 인터뷰 시나리오 메뉴 생성 완료.");
+ }
+ }
+}
diff --git a/docs/samples/방화셔터_견적구조_인터뷰.md b/docs/samples/방화셔터_견적구조_인터뷰.md
new file mode 100644
index 00000000..45a6f9f7
--- /dev/null
+++ b/docs/samples/방화셔터_견적구조_인터뷰.md
@@ -0,0 +1,87 @@
+# 견적 산출 엑셀 구조 검토
+- 견적 산출 엑셀 파일을 분석했는가?
+- 엑셀 구조를 자세히 검토했는가?
+- 이미 완성된 엑셀을 그대로 활용할 수 있는가?
+- 견적 구조를 문서화하여 설명할 수 있는가?
+
+# 셔터 카테고리 및 제품 분류
+- 통합 견적(견적 산출 + 발주서 작성) 범위를 확인했는가?
+- 스크린 셔터와 철제 셔터의 분류 기준을 확인했는가?
+- 스크린 본체/철제 슬랫 본체에 따른 제품 구분을 이해했는가?
+- 산업용 등 카테고리별 구분 체계를 확인했는가?
+
+# 셔터 제품명 및 구분 구조
+- KSS01, KSS02 등 제품명 체계를 파악했는가?
+- KWW WS 등 대형 제품 포함 여부를 확인했는가?
+- KQTS, KT201 등 전체 제품 목록을 확보했는가?
+- 벽면형, 측면형, 혼합형 등 설치 유형별 분류를 확인했는가?
+
+# 셔터 본체 구성
+- 본체가 스크린 또는 철제 슬랫으로 구성됨을 확인했는가?
+- 본체와 모터가 공통 구성 요소임을 확인했는가?
+- 스크린 본체의 원단 종류(실리카, 와이어, 하이바)를 확인했는가?
+- 스크린의 절단, 미싱, 포장 공정을 파악했는가?
+- 환봉이 부자재 창고에서 별도 관리됨을 확인했는가?
+
+# 전동 개폐기(모터) 구성
+- 전동 개폐기(모터)의 품질심사 용어와 현장 용어 차이를 인지했는가?
+- 모터 내부 구성품(절연 거품, 부자재)을 확인했는가?
+- 모터 용량 범위(150kg~1,500kg)를 파악했는가?
+- 인증 제품의 경우 모터 구성이 고정됨을 확인했는가?
+- 모터를 별도 구매하여 부품으로만 관리하는 현재 방식을 확인했는가?
+
+# 인정제품 vs 비인정제품 구분
+- 인정제품은 모든 구성 요소가 고정된 완전 세트임을 확인했는가?
+- 비인정제품은 본체만/모터만/부자재만 개별 주문 가능함을 확인했는가?
+- 인증 제품의 고정 구성 목록을 확보했는가?
+
+# 연동 제어기 및 부자재
+- 연동 제어기의 노출형/매립형 구분을 확인했는가?
+- 매립형 연동 제어기에 뒷박스 부자재가 추가됨을 확인했는가?
+- 공임과 부자재가 견적의 핵심 항목임을 인지했는가?
+
+# 가이드레일 및 케이스 구성
+- 가이드레일이 제품마다 모양과 치수가 다름을 확인했는가?
+- 가이드레일 표준 길이(2,438mm, 3,305mm, 4,430mm) 조합을 파악했는가?
+- 케이스 크기별(1500×380, 500×380) 부속품 차이를 확인했는가?
+- 가이드레일은 항상 2개씩 필요함을 확인했는가?
+- 판재 절곡 방식에 따른 모양 차이를 이해했는가?
+
+# 오픈 사이즈와 제작 사이즈
+- 오픈 사이즈 입력에 따른 제작 사이즈 산출 방식을 확인했는가?
+- 케이스/가이드레일 길이가 오픈 사이즈 확정 후 산출됨을 이해했는가?
+- 현장 조합 및 용접 방식을 파악했는가?
+- 표준 길이 판재의 현장 절단 방식을 확인했는가?
+
+# BOM 구조 현황 및 문제점
+- 현재 상향식(최하위 부품→상위 조립품) BOM 구조를 파악했는가?
+- 제품별 부품 매칭 정보가 미구현 상태임을 확인했는가?
+- KSS02 선택 시 부품 목록 자동 나열이 안 되는 문제를 인지했는가?
+- 오픈 사이즈 기반 동적 부품 계산이 미구현임을 확인했는가?
+- 케이스 내 부속품 연결이 표시되지 않는 문제를 확인했는가?
+
+# BOM 구조 개선 방안
+- 하향식 BOM 구조(상위 제품→하위 구성품) 도입을 검토했는가?
+- KSS02 등록 시 하위 항목 자동 등록 플로우를 설계했는가?
+- 카테고리별 품목 분류(본체, 절곡품, 부자재) 체계를 수립했는가?
+- 제품-부품 매핑 테이블(기본 구성품/옵션 구성품)을 정의했는가?
+- 오픈 사이즈 입력 시 동적 계산 부품 구분을 설계했는가?
+
+# 품목 등록 시스템 개선
+- 품목 등록 시 상위 품목 선택 기능을 구현할 수 있는가?
+- 카테고리 선택 시 해당 목록만 표시하는 기능을 설계했는가?
+- 제품별 부품 설정 등록 기능을 기획했는가?
+- 상위 부품 선택 시 하위 부품 자동 표시를 구현할 수 있는가?
+
+# 제품 목록 및 데이터 확보
+- 5130 시스템의 제품 수(20개 미만)를 확인했는가?
+- 미등록 제품이 더 있을 가능성을 검토했는가?
+- 전체 제품(약 11개 + 스모크 관련) 목록을 확보했는가?
+- 참고 자료 기반 부품 정리가 완료되었는가?
+
+# 견적 구조 확장 계획
+- 기본 복에서 제품 단위로 견적 확장 계획을 수립했는가?
+- 제품별 원단 확정(예: KSS02→실리카) 정보를 정리했는가?
+- 케이스 부품 종류 확정 및 사이즈/길이의 동적 입력 방식을 설계했는가?
+- 공정 관리와 품목 연동 구조를 검토했는가?
+- 개발팀과의 추가 협의 일정을 확인했는가?
diff --git a/resources/views/barobill/hometax/index.blade.php b/resources/views/barobill/hometax/index.blade.php
index 098c354a..c85820f6 100644
--- a/resources/views/barobill/hometax/index.blade.php
+++ b/resources/views/barobill/hometax/index.blade.php
@@ -61,7 +61,7 @@
+
+
+
+@verbatim
+
+@endverbatim
+@endpush
diff --git a/routes/web.php b/routes/web.php
index 665ce111..d9b165cd 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -1222,4 +1222,32 @@
Route::post('/products', [\App\Http\Controllers\Sales\SalesContractController::class, 'saveProducts'])->name('products.save');
Route::get('/products/{tenant}', [\App\Http\Controllers\Sales\SalesContractController::class, 'getProducts'])->name('products.get');
});
+
+ // 인터뷰 시나리오 관리
+ Route::prefix('interviews')->name('interviews.')->group(function () {
+ Route::get('/', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'index'])->name('index');
+ // 카테고리 API
+ Route::get('/api/categories', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'categories'])->name('api.categories');
+ Route::post('/api/categories', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'storeCategory'])->name('api.categories.store');
+ Route::put('/api/categories/{id}', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'updateCategory'])->name('api.categories.update');
+ Route::delete('/api/categories/{id}', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'destroyCategory'])->name('api.categories.destroy');
+ // 트리 API
+ Route::get('/api/tree', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'tree'])->name('api.tree');
+ // 템플릿(항목) API
+ Route::post('/api/templates', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'storeTemplate'])->name('api.templates.store');
+ Route::put('/api/templates/{id}', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'updateTemplate'])->name('api.templates.update');
+ Route::delete('/api/templates/{id}', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'destroyTemplate'])->name('api.templates.destroy');
+ // 질문 API
+ Route::post('/api/questions', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'storeQuestion'])->name('api.questions.store');
+ Route::put('/api/questions/{id}', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'updateQuestion'])->name('api.questions.update');
+ Route::delete('/api/questions/{id}', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'destroyQuestion'])->name('api.questions.destroy');
+ // 일괄 가져오기 API
+ Route::post('/api/bulk-import', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'bulkImport'])->name('api.bulk-import');
+ // 세션 API
+ Route::get('/api/sessions', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'sessions'])->name('api.sessions');
+ Route::post('/api/sessions', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'storeSession'])->name('api.sessions.store');
+ Route::get('/api/sessions/{id}', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'showSession'])->name('api.sessions.show');
+ Route::post('/api/sessions/toggle-answer', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'toggleAnswer'])->name('api.sessions.toggle-answer');
+ Route::post('/api/sessions/{id}/complete', [\App\Http\Controllers\Sales\InterviewScenarioController::class, 'completeSession'])->name('api.sessions.complete');
+ });
});