diff --git a/src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/response/AnalysisResponse.java b/src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/response/AnalysisResponse.java index 077fcdb..9d841fb 100644 --- a/src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/response/AnalysisResponse.java +++ b/src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/response/AnalysisResponse.java @@ -9,6 +9,7 @@ public record AnalysisResponse( Long mockApplyId, Long analysisId, MockApplyStatus status, + int sequence, int score, int jobFit, int impact, @@ -19,12 +20,14 @@ public record AnalysisResponse( public static AnalysisResponse of( Analysis analysis, MockApplyStatus status, + int sequence, List questions ) { return new AnalysisResponse( analysis.getMockApply().getId(), analysis.getId(), status, + sequence, analysis.getScore(), analysis.getJobFit(), analysis.getImpact(), diff --git a/src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/response/QuestionAnswerResponse.java b/src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/response/QuestionAnswerResponse.java index abf0ecf..111fef9 100644 --- a/src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/response/QuestionAnswerResponse.java +++ b/src/main/java/com/jobdri/jobdri_api/domain/analysis/dto/response/QuestionAnswerResponse.java @@ -7,6 +7,7 @@ public record QuestionAnswerResponse( Long mockApplyId, MockApplyStatus status, + int sequence, List questions ) { } diff --git a/src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisService.java b/src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisService.java index 4b91102..8d66f33 100644 --- a/src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisService.java +++ b/src/main/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisService.java @@ -179,7 +179,12 @@ private AnalysisResponse toResponse( )) .toList(); - return AnalysisResponse.of(analysis, mockApply.getStatus(), questionResponses); + return AnalysisResponse.of( + analysis, + mockApply.getStatus(), + mockApplyRepository.calculateSequence(mockApply), + questionResponses + ); } private MockApply getOwnedMockApply(User user, Long mockApplyId) { diff --git a/src/main/java/com/jobdri/jobdri_api/domain/analysis/service/QuestionService.java b/src/main/java/com/jobdri/jobdri_api/domain/analysis/service/QuestionService.java index 1acaad1..0bf0cb2 100644 --- a/src/main/java/com/jobdri/jobdri_api/domain/analysis/service/QuestionService.java +++ b/src/main/java/com/jobdri/jobdri_api/domain/analysis/service/QuestionService.java @@ -199,6 +199,7 @@ public QuestionAnswerResponse saveAnswers( return new QuestionAnswerResponse( mockApply.getId(), mockApply.getStatus(), + mockApplyRepository.calculateSequence(mockApply), questions.stream().map(QuestionResponse::from).toList() ); } diff --git a/src/main/java/com/jobdri/jobdri_api/domain/mockapply/repository/MockApplyRepository.java b/src/main/java/com/jobdri/jobdri_api/domain/mockapply/repository/MockApplyRepository.java index 1a273a0..f1bd89c 100644 --- a/src/main/java/com/jobdri/jobdri_api/domain/mockapply/repository/MockApplyRepository.java +++ b/src/main/java/com/jobdri/jobdri_api/domain/mockapply/repository/MockApplyRepository.java @@ -12,6 +12,14 @@ public interface MockApplyRepository extends JpaRepository { List findAllByJobPostingId(Long jobPostingId); long countByUserIdAndJobPostingId(Long userId, Long jobPostingId); + default int calculateSequence(MockApply mockApply) { + return Math.toIntExact(countSequenceByUserIdAndJobPostingId( + mockApply.getUser().getId(), + mockApply.getJobPosting().getId(), + mockApply.getId() + )); + } + @Query(""" select ma from MockApply ma @@ -29,15 +37,11 @@ select count(ma) from MockApply ma where ma.user.id = :userId and ma.jobPosting.id = :jobPostingId - and ( - ma.createdAt < :createdAt - or (ma.createdAt = :createdAt and ma.id <= :mockApplyId) - ) + and ma.id <= :mockApplyId """) long countSequenceByUserIdAndJobPostingId( @Param("userId") Long userId, @Param("jobPostingId") Long jobPostingId, - @Param("createdAt") java.time.LocalDateTime createdAt, @Param("mockApplyId") Long mockApplyId ); } diff --git a/src/main/java/com/jobdri/jobdri_api/domain/mockapply/service/MockApplyService.java b/src/main/java/com/jobdri/jobdri_api/domain/mockapply/service/MockApplyService.java index ef58858..23c1206 100644 --- a/src/main/java/com/jobdri/jobdri_api/domain/mockapply/service/MockApplyService.java +++ b/src/main/java/com/jobdri/jobdri_api/domain/mockapply/service/MockApplyService.java @@ -108,14 +108,7 @@ public MockApplySequenceResponse getMockApplySequence(User user, Long mockApplyI int totalCount = Math.toIntExact( mockApplyRepository.countByUserIdAndJobPostingId(validatedUser.getId(), jobPostingId) ); - int sequence = Math.toIntExact( - mockApplyRepository.countSequenceByUserIdAndJobPostingId( - validatedUser.getId(), - jobPostingId, - mockApply.getCreatedAt(), - mockApply.getId() - ) - ); + int sequence = mockApplyRepository.calculateSequence(mockApply); if (sequence < 1 || sequence > totalCount) { throw new GeneralException( diff --git a/src/test/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisServiceTest.java b/src/test/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisServiceTest.java index e89137b..58c88be 100644 --- a/src/test/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisServiceTest.java +++ b/src/test/java/com/jobdri/jobdri_api/domain/analysis/service/AnalysisServiceTest.java @@ -111,6 +111,7 @@ void analyzeSavesAnalysis() { AnalysisResponse response = analysisService.analyze(user, mockApply.getId()); assertThat(response.status()).isEqualTo(MockApplyStatus.COMPLETED); + assertThat(response.sequence()).isEqualTo(1); assertThat(response.score()).isEqualTo(100); assertThat(response.jobFit()).isEqualTo(82); assertThat(response.impact()).isEqualTo(71); @@ -131,6 +132,35 @@ void analyzeSavesAnalysis() { )).hasSize(1); } + @Test + @DisplayName("분석 응답은 같은 공고 기준 현재 지원 순번을 반환한다") + void analyzeReturnsSequence() { + User user = saveUser("analysis-sequence@example.com"); + JobPosting jobPosting = saveJobPosting(user); + mockApplyRepository.save(MockApply.create(user, jobPosting, ApplyType.ACTUAL)); + MockApply secondMockApply = mockApplyRepository.save(MockApply.create(user, jobPosting, ApplyType.ACTUAL)); + Question question = saveQuestion(secondMockApply, "재지원 분석 문항입니다.", "Spring Boot API를 개발했습니다."); + when(analysisAiClient.analyze(any(), any())).thenReturn(new AnalysisLlmResponse( + 80, + 81, + 82, + 83, + "재지원 분석입니다.", + List.of(new AnalysisLlmResponse.QuestionAnalysisItem( + question.getId(), + "Spring Boot API를 개발했습니다.", + "mentioned", + "성과 지표가 부족합니다.", + "Spring Boot API를 개발해 응답 시간을 개선했습니다." + )) + )); + + AnalysisResponse response = analysisService.analyze(user, secondMockApply.getId()); + + assertThat(response.mockApplyId()).isEqualTo(secondMockApply.getId()); + assertThat(response.sequence()).isEqualTo(2); + } + @Test @DisplayName("LLM 분석 실패 시 크레딧 차감과 분석 저장을 롤백한다") void analyzeRollsBackCreditWhenLlmFails() { diff --git a/src/test/java/com/jobdri/jobdri_api/domain/analysis/service/QuestionServiceTest.java b/src/test/java/com/jobdri/jobdri_api/domain/analysis/service/QuestionServiceTest.java index 16967dc..96ce1a3 100644 --- a/src/test/java/com/jobdri/jobdri_api/domain/analysis/service/QuestionServiceTest.java +++ b/src/test/java/com/jobdri/jobdri_api/domain/analysis/service/QuestionServiceTest.java @@ -299,12 +299,33 @@ void saveAnswers() { ))); assertThat(response.questions()).hasSize(1); + assertThat(response.sequence()).isEqualTo(1); assertThat(response.questions().get(0).content()).isEqualTo("지원 동기를 작성해주세요."); assertThat(response.questions().get(0).answer()).isEqualTo("저는 백엔드 개발 경험을 바탕으로 지원했습니다."); assertThat(questionRepository.findById(questionId).orElseThrow().getAnswer()) .isEqualTo("저는 백엔드 개발 경험을 바탕으로 지원했습니다."); } + @Test + @DisplayName("답변 저장 응답은 같은 공고 기준 현재 지원 순번을 반환한다") + void saveAnswersReturnsSequence() { + User user = saveUser("answer-sequence@example.com"); + JobPosting jobPosting = saveJobPosting(); + mockApplyRepository.save(MockApply.create(user, jobPosting, ApplyType.ACTUAL)); + MockApply secondMockApply = mockApplyRepository.save(MockApply.create(user, jobPosting, ApplyType.ACTUAL)); + QuestionSelectionResponse selected = questionService.saveSelectedQuestions(user, secondMockApply.getId(), new QuestionSelectionSaveRequest(List.of( + new QuestionSelectionSaveRequest.QuestionItem("재지원 답변 문항입니다.", 700, false) + ))); + Long questionId = selected.questions().get(0).questionId(); + + QuestionAnswerResponse response = questionService.saveAnswers(user, secondMockApply.getId(), new QuestionAnswerSaveRequest(List.of( + new QuestionAnswerSaveRequest.AnswerItem(questionId, "두 번째 지원 답변입니다.") + ))); + + assertThat(response.mockApplyId()).isEqualTo(secondMockApply.getId()); + assertThat(response.sequence()).isEqualTo(2); + } + @Test @DisplayName("해당 지원서에 속하지 않은 문항은 답변 저장에 사용할 수 없다") void saveAnswersThrowsWhenQuestionDoesNotBelongToMockApply() {