Skip to content

feat: 화상 면접 재시도 기능 구현 (#83)#85

Merged
Boyeon-Shin merged 1 commit into
mainfrom
feat/session-query-retry
Jun 1, 2026
Merged

feat: 화상 면접 재시도 기능 구현 (#83)#85
Boyeon-Shin merged 1 commit into
mainfrom
feat/session-query-retry

Conversation

@Boyeon-Shin
Copy link
Copy Markdown
Collaborator

📌 관련 이슈 (Related Issue)

📝 작업 내용 (Description)

화상 면접 재시도 기능 구현

🔄 변경 유형 (Type of Change)

  • ✨ 새로운 기능 (feat)
  • 🐛 버그 수정 (fix)
  • 📝 문서 수정 (docs)
  • 💄 스타일 (style)
  • ♻️ 리팩토링 (refactor)
  • ✅ 테스트 (test)
  • 🔧 기타 (chore)

✅ 체크리스트 (Checklist)

  • 코드가 정상적으로 동작하는지 확인했습니다
  • 기존 테스트가 통과합니다
  • 필요한 경우 새로운 테스트를 추가했습니다

@Boyeon-Shin Boyeon-Shin self-assigned this Jun 1, 2026
@Boyeon-Shin Boyeon-Shin merged commit 751ee8f into main Jun 1, 2026
3 checks passed
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces endpoints and service logic to create new interview sessions by cloning existing sessions or specific questions. Key feedback highlights the potential risk of creating empty sessions when no questions exist, performance concerns regarding database saves inside stream operations (suggesting the use of saveAll instead), and recommendations for more RESTful API path designs for the new endpoints.

Comment on lines +107 to +108
List<InterviewQuestion> oldQuestions = questionRepository.findByInterviewSessionIdOrderByCreatedAtAsc(oldSessionId);
InterviewSession newSession = sessionRepository.save(new InterviewSession(memberId, oldQuestions.size()));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

이전 세션(oldSessionId)에 등록된 질문이 없는 경우(oldQuestions.isEmpty()), 질문이 0개인 빈 세션이 생성될 수 있습니다. 면접 세션은 최소 한 개 이상의 질문을 가져야 하므로, 질문 목록이 비어있는지 검증하는 로직을 추가하는 것이 안전합니다.

        List<InterviewQuestion> oldQuestions = questionRepository.findByInterviewSessionIdOrderByCreatedAtAsc(oldSessionId);
        if (oldQuestions.isEmpty()) {
            throw new BusinessException(ErrorCode.QUESTION_NOT_FOUND);
        }
        InterviewSession newSession = sessionRepository.save(new InterviewSession(memberId, oldQuestions.size()));

Comment on lines +110 to +112
List<UUID> newQuestionIds = oldQuestions.stream()
.map(q -> cloneQuestion(q, newSession).getId())
.toList();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

스트림(stream()) 내부에서 데이터베이스에 변경을 주는 cloneQuestion (내부적으로 save 호출)을 호출하는 것은 부작용(Side-effect)을 유발하므로 지양해야 합니다. 또한, 여러 개의 질문을 개별적으로 save하는 대신 saveAll을 사용하여 일괄 저장(Batch Insert)하는 것이 성능과 가독성 측면에서 더 좋습니다.

다음과 같이 saveAll을 사용하도록 리팩토링하는 것을 제안합니다.

        List<InterviewQuestion> newQuestions = oldQuestions.stream()
                .map(q -> new InterviewQuestion(
                        q.getMemberId(),
                        q.getQuestion(),
                        q.getQuestionType(),
                        q.getQuestionTag(),
                        q.getJobPosting(),
                        newSession
                ))
                .toList();

        List<UUID> newQuestionIds = questionRepository.saveAll(newQuestions).stream()
                .map(InterviewQuestion::getId)
                .toList();

Comment on lines +45 to +64
@PostMapping("/{sessionId}")
@ResponseStatus(HttpStatus.CREATED)
public ApiResponse<CreateSessionResponse> createSession(
@PathVariable UUID sessionId,
@RequestHeader("X-User-Id") UUID memberId
) {
CreateSessionResponse data = sessionService.createSession(sessionId, memberId);
return ApiResponse.created(data, "세션이 생성되었습니다.");
}

@PostMapping("/{sessionId}/questions/{questionId}")
@ResponseStatus(HttpStatus.CREATED)
public ApiResponse<CreateSessionResponse> createQuestion(
@PathVariable UUID sessionId,
@PathVariable UUID questionId,
@RequestHeader("X-User-Id") UUID memberId
) {
CreateSessionResponse data = sessionService.createQuestion(sessionId, questionId, memberId);
return ApiResponse.created(data, "세션이 생성되었습니다.");
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

현재 API 경로 설계에서 POST /api/interviews/sessions/{sessionId}POST /api/interviews/sessions/{sessionId}/questions/{questionId}는 기존 세션의 정보를 바탕으로 새로운 세션을 생성하고 있습니다.

하지만 이 경로는 기존 세션 리소스를 수정하거나 기존 세션 하위에 질문을 생성하는 것처럼 오해를 불러일으킬 수 있어 RESTful한 설계 관점에서 아쉬움이 있습니다.

다음과 같은 대안을 고려해 보시는 것을 추천합니다:

  1. 재시도(Retry) 명시: POST /api/interviews/sessions/{sessionId}/retryPOST /api/interviews/sessions/{sessionId}/questions/{questionId}/retry와 같이 행위(retry)를 경로에 명시합니다.
  2. 세션 생성 API 통합: POST /api/interviews/sessions 엔드포인트에 요청 바디(DTO)로 parentSessionId와 선택적으로 questionId를 전달하여 새로운 세션을 생성하도록 단일화합니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 화상 면접 결과 조회 및 재시도 기능

1 participant