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(); } }