From d508594d7c90d7bfff06084867a9993e960ea712 Mon Sep 17 00:00:00 2001 From: kimwuju Date: Thu, 15 Oct 2026 10:46:09 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EA=B8=B0=EC=88=A0=20=EB=A9=B4=EC=A0=91?= =?UTF-8?q?=EA=B4=80=20=EC=A0=84=EA=B3=B5=EA=B3=BC=20=EC=A7=88=EB=AC=B8=20?= =?UTF-8?q?=EC=9E=AC=EC=9E=91=EC=84=B1=20=EC=A7=81=EB=AC=B4=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=A7=81=EB=AC=B4=EB=A1=9C=20?= =?UTF-8?q?=EA=B3=A0=EC=A0=95=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SOLO 면접관 2·3의 전공이 FRONTEND로 고정돼, 백엔드 사용자가 이 면접관을 고르면 테일러가 면접관 전공을 먼저 보고 프론트엔드 기준으로 질문을 다시 썼다. - 페르소나 저장: TECH 전공을 로그인 사용자 직무로 채운다. 요청의 major는 읽지 않는다(구버전 Web 호환) - 전공 누락 422("기술 면접관에게는 전공(major)이 필요합니다.")를 없앤다 - 테일러 jobRole: 면접관 전공 대신 정규화한 사용자 직무 원문만 보낸다(WEB_PUBLISHER 등) - UserJobMajors: MAJOR_ 접두사·공백·대소문자 정규화, WEB_PUBLISHER→FRONTEND, 그 밖·없음→BACKEND API를 Web보다 먼저 배포해야 한다. 신버전 Web이 major 없이 저장하면 구버전 API는 422로 막는다. Co-Authored-By: Claude Opus 5.5 --- .../persona/controller/PersonaController.java | 5 +- .../persona/dto/request/PersonaRequest.java | 2 +- .../persona/service/PersonaService.java | 12 ++-- .../persona/support/UserJobMajors.java | 57 +++++++++++++++++ .../service/QuestionTailorService.java | 30 +++------ .../service/PersonaServiceCreateTest.java | 62 ++++++++++++++----- .../persona/support/UserJobMajorsTest.java | 35 +++++++++++ .../QuestionTailorServiceRequestTest.java | 26 +++++--- 8 files changed, 175 insertions(+), 54 deletions(-) create mode 100644 src/main/java/repit/repit_api_server/domain/userdata/persona/support/UserJobMajors.java create mode 100644 src/test/java/repit/repit_api_server/domain/userdata/persona/support/UserJobMajorsTest.java diff --git a/src/main/java/repit/repit_api_server/domain/userdata/persona/controller/PersonaController.java b/src/main/java/repit/repit_api_server/domain/userdata/persona/controller/PersonaController.java index e87e0535..be8cf455 100644 --- a/src/main/java/repit/repit_api_server/domain/userdata/persona/controller/PersonaController.java +++ b/src/main/java/repit/repit_api_server/domain/userdata/persona/controller/PersonaController.java @@ -2,7 +2,9 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; +import repit.repit_api_server.global.auth.AuthUser; import repit.repit_api_server.global.common.ApiResponse; import repit.repit_api_server.domain.userdata.persona.dto.request.PersonaRequest; import repit.repit_api_server.domain.userdata.persona.dto.response.PersonaResponse; @@ -20,8 +22,9 @@ public class PersonaController { @PostMapping("/save") @ResponseStatus(HttpStatus.CREATED) public ApiResponse savePersona( + @AuthenticationPrincipal AuthUser authUser, @RequestBody PersonaRequest request) { - return ApiResponse.created(personaService.createPersona(request)); + return ApiResponse.created(personaService.createPersona(request, authUser.user().getMajor())); } @GetMapping("/getById") diff --git a/src/main/java/repit/repit_api_server/domain/userdata/persona/dto/request/PersonaRequest.java b/src/main/java/repit/repit_api_server/domain/userdata/persona/dto/request/PersonaRequest.java index 2395f8fa..8f9b4d08 100644 --- a/src/main/java/repit/repit_api_server/domain/userdata/persona/dto/request/PersonaRequest.java +++ b/src/main/java/repit/repit_api_server/domain/userdata/persona/dto/request/PersonaRequest.java @@ -22,7 +22,7 @@ public class PersonaRequest { // 필수. TECH / HR / CEO. private Role role; - // 기술 면접관에게만 필요하다. 인사팀·CEO는 비워 보낸다. + // 읽지 않는다. 기술 면접관 전공은 로그인 사용자의 직무로 정한다(구버전 Web 호환용으로만 남김). private Major major; private Type type; diff --git a/src/main/java/repit/repit_api_server/domain/userdata/persona/service/PersonaService.java b/src/main/java/repit/repit_api_server/domain/userdata/persona/service/PersonaService.java index 7826ca65..0552fd27 100644 --- a/src/main/java/repit/repit_api_server/domain/userdata/persona/service/PersonaService.java +++ b/src/main/java/repit/repit_api_server/domain/userdata/persona/service/PersonaService.java @@ -7,6 +7,7 @@ import repit.repit_api_server.domain.userdata.persona.entity.PersonaEntity; import repit.repit_api_server.domain.userdata.persona.entity.enums.Role; import repit.repit_api_server.domain.userdata.persona.repository.PersonaRepository; +import repit.repit_api_server.domain.userdata.persona.support.UserJobMajors; import repit.repit_api_server.global.exception.BusinessException; import java.util.List; @@ -17,7 +18,10 @@ public class PersonaService { private final PersonaRepository personaRepository; - public PersonaResponse createPersona(PersonaRequest request) { + /** + * @param userMajor 로그인 사용자의 직무. 기술 면접관 전공은 요청값이 아니라 이 값으로 정한다. + */ + public PersonaResponse createPersona(PersonaRequest request, String userMajor) { // 직책과 난이도에는 기본값을 두지 않는다. 조용히 채워 넣으면 인사·CEO 면접관이 // 기술 면접관으로 저장되고, 저장된 뒤에는 무엇이 요청값이고 무엇이 기본값인지 구분할 방법이 없다. if (request.getRole() == null) { @@ -31,10 +35,6 @@ public PersonaResponse createPersona(PersonaRequest request) { throw BusinessException.unprocessable("면접관 어조(tone)를 지정해주세요."); } Role role = request.getRole(); - // 전공은 기술 면접관에게만 있는 값이다. DB CHECK와 같은 규칙을 여기서 먼저 걸러 메시지를 남긴다. - if (role == Role.TECH && request.getMajor() == null) { - throw BusinessException.unprocessable("기술 면접관에게는 전공(major)이 필요합니다."); - } // DB CHECK와 같은 범위. 번호와 성별의 관계는 Web과 채팅 서버의 카탈로그가 맞추므로 보지 않는다. Integer voiceIndex = request.getVoiceIndex(); if (voiceIndex != null && (voiceIndex < 1 || voiceIndex > 5)) { @@ -47,7 +47,7 @@ public PersonaResponse createPersona(PersonaRequest request) { .type(request.getType()) .tone(request.getTone()) .level(request.getLevel()) - .major(role == Role.TECH ? request.getMajor() : null) + .major(role == Role.TECH ? UserJobMajors.toPersonaMajor(userMajor) : null) .career(request.getCareer()) .gender(request.getGender()) .imageUrl(blankToNull(request.getImageUrl())) diff --git a/src/main/java/repit/repit_api_server/domain/userdata/persona/support/UserJobMajors.java b/src/main/java/repit/repit_api_server/domain/userdata/persona/support/UserJobMajors.java new file mode 100644 index 00000000..1782745e --- /dev/null +++ b/src/main/java/repit/repit_api_server/domain/userdata/persona/support/UserJobMajors.java @@ -0,0 +1,57 @@ +package repit.repit_api_server.domain.userdata.persona.support; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import repit.repit_api_server.domain.userdata.persona.entity.enums.Major; + +import java.util.Locale; + +/** + * 인증 서버의 사용자 직무 값을 다룬다. + * + *

기술 면접관의 전공은 사용자가 고르지 않고 사용자 직무를 따른다. 면접관 전공은 + * BACKEND / FRONTEND 두 가지뿐이라, 그 밖의 직무는 가까운 값이나 대체값으로 맞춘다. + */ +public final class UserJobMajors { + + private static final Logger log = LoggerFactory.getLogger(UserJobMajors.class); + + // 인증 서버의 직무 값 앞에 붙는 접두사(MAJOR_BACKEND). + private static final String AUTH_MAJOR_PREFIX = "MAJOR_"; + + private UserJobMajors() {} + + /** MAJOR_ 접두사를 떼고 앞뒤 공백을 지운 뒤 대문자로 맞춘다. 비어 있으면 null. */ + public static String normalize(String userMajor) { + if (userMajor == null) { + return null; + } + String value = userMajor.strip().toUpperCase(Locale.ROOT); + if (value.startsWith(AUTH_MAJOR_PREFIX)) { + value = value.substring(AUTH_MAJOR_PREFIX.length()); + } + return value.isEmpty() ? null : value; + } + + /** + * 기술 면접관 전공. null을 돌려주지 않는다. + * + *

WEB_PUBLISHER는 화면 개발 직무라 FRONTEND로 맞춘다. 직무가 없거나 옮길 수 없는 값은 + * BACKEND로 둔다. 마이페이지 직무 저장이 아직 없어 직무 없는 사용자가 정상 경로에 있으므로 막지 않는다. + */ + public static Major toPersonaMajor(String userMajor) { + String job = normalize(userMajor); + if (job == null) { + log.info("사용자 직무가 없어 기술 면접관 전공을 BACKEND로 둡니다."); + return Major.BACKEND; + } + return switch (job) { + case "BACKEND" -> Major.BACKEND; + case "FRONTEND", "WEB_PUBLISHER" -> Major.FRONTEND; + default -> { + log.info("면접관 전공으로 옮길 수 없는 직무라 BACKEND로 둡니다. userMajor={}", userMajor); + yield Major.BACKEND; + } + }; + } +} diff --git a/src/main/java/repit/repit_api_server/domain/userdata/question/service/QuestionTailorService.java b/src/main/java/repit/repit_api_server/domain/userdata/question/service/QuestionTailorService.java index f7d9580d..acae6e2b 100644 --- a/src/main/java/repit/repit_api_server/domain/userdata/question/service/QuestionTailorService.java +++ b/src/main/java/repit/repit_api_server/domain/userdata/question/service/QuestionTailorService.java @@ -20,6 +20,7 @@ import repit.repit_api_server.domain.userdata.persona.entity.PersonaEntity; import repit.repit_api_server.domain.userdata.persona.entity.enums.Role; import repit.repit_api_server.domain.userdata.persona.repository.PersonaRepository; +import repit.repit_api_server.domain.userdata.persona.support.UserJobMajors; import repit.repit_api_server.domain.userdata.question.dto.request.QuestionCycleCallbackRequest; import repit.repit_api_server.domain.userdata.question.dto.request.QuestionTailorCallbackRequest; import repit.repit_api_server.domain.userdata.question.dto.request.QuestionTailorMultiCallbackRequest; @@ -67,8 +68,6 @@ public class QuestionTailorService { private static final String CALLBACK_PATH = "/api/questions/tailor/callback"; private static final String MULTI_CALLBACK_PATH = "/api/questions/tailor/multi/callback"; private static final String STATUS_SUCCEEDED = "succeeded"; - // 인증 서버의 전공 값 앞에 붙는 접두사. 떼면 면접관 전공(Major)과 같은 형식이 된다. - private static final String AUTH_MAJOR_PREFIX = "MAJOR_"; // 기술 외 면접관 한 명이 맡을 문항 수. 분석 서버 기본값과 같다. 면접관이 늘면 이만큼씩 늘어난다. private static final int OTHER_QUESTION_COUNT = 2; @@ -245,7 +244,7 @@ private QuestionTailorAcceptedResponse requestMultiTailor(InterviewEntity interv return aiServerClient.tailorQuestionsMulti(QuestionTailorMultiRequest.builder() .interviewId(String.valueOf(interview.getInterviewId())) .userId(String.valueOf(interview.getUserId())) - .jobRole(resolveJobRole(major, tech)) + .jobRole(resolveJobRole(major)) // persona.career는 면접관 설정이지 지원자 경력이 아니다. 지원자 경력은 아직 수집하지 않는다. .experienceLevel(null) .techPersona(toRequestPersona(tech, techQuestions.size())) @@ -403,25 +402,14 @@ private QuestionTailorMultiRequest.ProjectSummary toRequestProjectSummary(Questi } /** - * 재작성 개인화 축. 면접 설정에서 고른 면접관의 전공이 먼저고, 없으면 사용자 전공을 쓴다. + * 재작성 개인화 축. 사용자 직무만 본다. * - *

사용자 전공은 회원가입 때 고정값으로 들어간 것이라 사용자가 고른 적이 없다. 이것을 먼저 - * 보면 면접 설정에서 프론트엔드를 골라도 질문은 백엔드 기준으로 다시 쓰인다. + *

면접관 전공은 사용자 직무에서 나온 값이라 따로 볼 이유가 없다. 예전에는 면접관 전공을 + * 먼저 봐서, 면접 설정에서 고른 면접관에 따라 질문이 다른 직무 기준으로 다시 쓰였다. + * 면접관 전공으로 좁히지 않고 직무 원문을 보낸다(WEB_PUBLISHER 등). */ - private String resolveJobRole(String userMajor, PersonaEntity persona) { - if (persona != null && persona.getMajor() != null) { - return persona.getMajor().name(); - } - return normalizeMajor(userMajor); - } - - /** 인증 서버는 MAJOR_BACKEND 형식으로 내려준다. 면접관 전공과 같은 BACKEND 형식으로 맞춘다. */ - private String normalizeMajor(String major) { - String value = blankToNull(major); - if (value == null) { - return null; - } - return value.startsWith(AUTH_MAJOR_PREFIX) ? value.substring(AUTH_MAJOR_PREFIX.length()) : value; + private String resolveJobRole(String userMajor) { + return UserJobMajors.normalize(userMajor); } private QuestionTailorRequest.Question toRequestQuestion(TailoredQuestionResponse question) { @@ -442,7 +430,7 @@ private QuestionTailorRequest.Question toRequestQuestion(TailoredQuestionRespons private QuestionTailorRequest.Profile resolveProfile(String userMajor, Long personaId) { PersonaEntity persona = personaRepository.findById(personaId).orElse(null); - String jobRole = resolveJobRole(userMajor, persona); + String jobRole = resolveJobRole(userMajor); String personaType = persona == null ? null : enumName(persona.getType()); String personaTone = persona == null ? null : enumName(persona.getTone()); diff --git a/src/test/java/repit/repit_api_server/domain/userdata/persona/service/PersonaServiceCreateTest.java b/src/test/java/repit/repit_api_server/domain/userdata/persona/service/PersonaServiceCreateTest.java index a0faf21b..00869f20 100644 --- a/src/test/java/repit/repit_api_server/domain/userdata/persona/service/PersonaServiceCreateTest.java +++ b/src/test/java/repit/repit_api_server/domain/userdata/persona/service/PersonaServiceCreateTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.ArgumentCaptor; import org.mockito.Captor; @@ -65,7 +66,7 @@ private PersonaRequest request(Role role, Major major) { @Test void 요청한_직책이_그대로_저장된다() { - service.createPersona(request(Role.HR, null)); + service.createPersona(request(Role.HR, null), "MAJOR_BACKEND"); verify(personaRepository).save(saved.capture()); assertThat(saved.getValue().getRole()).isEqualTo(Role.HR); @@ -75,7 +76,7 @@ private PersonaRequest request(Role role, Major major) { @Test void 직책을_안_보내면_422다() { - assertThatThrownBy(() -> service.createPersona(request(null, Major.BACKEND))) + assertThatThrownBy(() -> service.createPersona(request(null, Major.BACKEND), "MAJOR_BACKEND")) .isInstanceOf(BusinessException.class) .extracting(e -> ((BusinessException) e).getStatus()) .isEqualTo(HttpStatus.UNPROCESSABLE_CONTENT); @@ -84,26 +85,53 @@ private PersonaRequest request(Role role, Major major) { verify(personaRepository, never()).save(any()); } + /** Web이 보낸 전공이 사용자 직무를 덮어쓰면 엉뚱한 직무 기준으로 면접이 진행된다. */ @Test - void 기술_면접관은_전공이_없으면_422다() { - assertThatThrownBy(() -> service.createPersona(request(Role.TECH, null))) - .isInstanceOf(BusinessException.class) - .extracting(e -> ((BusinessException) e).getStatus()) - .isEqualTo(HttpStatus.UNPROCESSABLE_CONTENT); + void 기술_면접관_전공은_요청값이_아니라_사용자_직무다() { + service.createPersona(request(Role.TECH, Major.BACKEND), "MAJOR_FRONTEND"); + + verify(personaRepository).save(saved.capture()); + assertThat(saved.getValue().getRole()).isEqualTo(Role.TECH); + assertThat(saved.getValue().getMajor()).isEqualTo(Major.FRONTEND); } @Test - void 기술_면접관은_전공을_유지한다() { - service.createPersona(request(Role.TECH, Major.BACKEND)); + void 기술_면접관은_전공을_안_보내도_저장된다() { + service.createPersona(request(Role.TECH, null), "MAJOR_BACKEND"); + + verify(personaRepository).save(saved.capture()); + assertThat(saved.getValue().getMajor()).isEqualTo(Major.BACKEND); + } + + @Test + void 웹퍼블리셔_사용자의_기술_면접관은_프론트엔드다() { + service.createPersona(request(Role.TECH, null), "WEB_PUBLISHER"); + + verify(personaRepository).save(saved.capture()); + assertThat(saved.getValue().getMajor()).isEqualTo(Major.FRONTEND); + } + + @ParameterizedTest + @NullSource + @ValueSource(strings = "DATA_ANALYST") + void 직무가_없거나_옮길_수_없으면_백엔드다(String userMajor) { + service.createPersona(request(Role.TECH, null), userMajor); verify(personaRepository).save(saved.capture()); - assertThat(saved.getValue().getRole()).isEqualTo(Role.TECH); assertThat(saved.getValue().getMajor()).isEqualTo(Major.BACKEND); } + @Test + void 비기술_면접관은_사용자_직무와_관계없이_전공이_없다() { + service.createPersona(request(Role.HR, null), "MAJOR_FRONTEND"); + + verify(personaRepository).save(saved.capture()); + assertThat(saved.getValue().getMajor()).isNull(); + } + @Test void 요청한_난이도가_그대로_저장된다() { - service.createPersona(request(Role.CEO, null)); + service.createPersona(request(Role.CEO, null), "MAJOR_BACKEND"); verify(personaRepository).save(saved.capture()); assertThat(saved.getValue().getLevel()).isEqualTo(Level.HARD); @@ -111,7 +139,7 @@ private PersonaRequest request(Role role, Major major) { @Test void 요청한_어조가_그대로_저장된다() { - service.createPersona(request(Role.CEO, null)); + service.createPersona(request(Role.CEO, null), "MAJOR_BACKEND"); verify(personaRepository).save(saved.capture()); // 성향이 FRIENDLY라고 어조까지 부드럽게 채워지면 안 된다. 두 축은 독립이다. @@ -123,7 +151,7 @@ private PersonaRequest request(Role role, Major major) { PersonaRequest request = request(Role.CEO, null); request.setTone(null); - assertThatThrownBy(() -> service.createPersona(request)) + assertThatThrownBy(() -> service.createPersona(request, "MAJOR_BACKEND")) .isInstanceOf(BusinessException.class) .extracting(e -> ((BusinessException) e).getStatus()) .isEqualTo(HttpStatus.UNPROCESSABLE_CONTENT); @@ -137,7 +165,7 @@ private PersonaRequest request(Role role, Major major) { PersonaRequest request = request(Role.HR, null); request.setVoiceIndex(voiceIndex); - assertThat(service.createPersona(request).getVoiceIndex()).isEqualTo(voiceIndex); + assertThat(service.createPersona(request, "MAJOR_BACKEND").getVoiceIndex()).isEqualTo(voiceIndex); verify(personaRepository).save(saved.capture()); assertThat(saved.getValue().getVoiceIndex()).isEqualTo(voiceIndex); } @@ -145,7 +173,7 @@ private PersonaRequest request(Role role, Major major) { /** 음성 번호는 선택이다. 비우면 채팅 서버가 기본 음성을 쓴다. */ @Test void 음성_번호_없이도_저장된다() { - service.createPersona(request(Role.HR, null)); + service.createPersona(request(Role.HR, null), "MAJOR_BACKEND"); verify(personaRepository).save(saved.capture()); assertThat(saved.getValue().getVoiceIndex()).isNull(); @@ -157,7 +185,7 @@ private PersonaRequest request(Role role, Major major) { PersonaRequest request = request(Role.HR, null); request.setVoiceIndex(voiceIndex); - assertThatThrownBy(() -> service.createPersona(request)) + assertThatThrownBy(() -> service.createPersona(request, "MAJOR_BACKEND")) .isInstanceOf(BusinessException.class) .extracting(e -> ((BusinessException) e).getStatus()) .isEqualTo(HttpStatus.UNPROCESSABLE_CONTENT); @@ -170,7 +198,7 @@ private PersonaRequest request(Role role, Major major) { PersonaRequest request = request(Role.CEO, null); request.setLevel(null); - assertThatThrownBy(() -> service.createPersona(request)) + assertThatThrownBy(() -> service.createPersona(request, "MAJOR_BACKEND")) .isInstanceOf(BusinessException.class) .extracting(e -> ((BusinessException) e).getStatus()) .isEqualTo(HttpStatus.UNPROCESSABLE_CONTENT); diff --git a/src/test/java/repit/repit_api_server/domain/userdata/persona/support/UserJobMajorsTest.java b/src/test/java/repit/repit_api_server/domain/userdata/persona/support/UserJobMajorsTest.java new file mode 100644 index 00000000..618131e7 --- /dev/null +++ b/src/test/java/repit/repit_api_server/domain/userdata/persona/support/UserJobMajorsTest.java @@ -0,0 +1,35 @@ +package repit.repit_api_server.domain.userdata.persona.support; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; +import repit.repit_api_server.domain.userdata.persona.entity.enums.Major; + +import static org.assertj.core.api.Assertions.assertThat; + +class UserJobMajorsTest { + + @ParameterizedTest + @CsvSource({ + "MAJOR_BACKEND, BACKEND, BACKEND", + "MAJOR_FRONTEND, FRONTEND, FRONTEND", + "FRONTEND, FRONTEND, FRONTEND", + "' major_frontend ', FRONTEND, FRONTEND", + "WEB_PUBLISHER, WEB_PUBLISHER, FRONTEND", + "DATA_ANALYST, DATA_ANALYST, BACKEND", + }) + void 직무를_정규화하고_면접관_전공으로_옮긴다(String userMajor, String normalized, Major major) { + assertThat(UserJobMajors.normalize(userMajor)).isEqualTo(normalized); + assertThat(UserJobMajors.toPersonaMajor(userMajor)).isEqualTo(major); + } + + /** 직무가 없는 사용자도 면접을 시작할 수 있어야 한다. 예외 대신 BACKEND로 둔다. */ + @ParameterizedTest + @NullSource + @ValueSource(strings = {"", " "}) + void 직무가_없으면_정규화는_null이고_전공은_백엔드다(String userMajor) { + assertThat(UserJobMajors.normalize(userMajor)).isNull(); + assertThat(UserJobMajors.toPersonaMajor(userMajor)).isEqualTo(Major.BACKEND); + } +} diff --git a/src/test/java/repit/repit_api_server/domain/userdata/question/service/QuestionTailorServiceRequestTest.java b/src/test/java/repit/repit_api_server/domain/userdata/question/service/QuestionTailorServiceRequestTest.java index 7fa03fdc..25df88b4 100644 --- a/src/test/java/repit/repit_api_server/domain/userdata/question/service/QuestionTailorServiceRequestTest.java +++ b/src/test/java/repit/repit_api_server/domain/userdata/question/service/QuestionTailorServiceRequestTest.java @@ -222,12 +222,9 @@ private void givenMembers(Long... personaIds) { assertThat(sent.getValue().getProfile().getPersonaTone()).isEqualTo("PRESSURING"); } - /** - * 사용자 전공은 회원가입 때 고정값으로 들어간 것이라 사용자가 고른 적이 없다. - * 이것이 먼저면 면접 설정에서 프론트엔드를 골라도 질문은 백엔드 기준으로 다시 쓰인다. - */ + /** 면접관 전공이 먼저면 고른 면접관에 따라 질문이 다른 직무 기준으로 다시 쓰인다. */ @Test - void 일대일은_면접관_전공이_사용자_전공보다_먼저다() { + void 일대일은_면접관_전공과_관계없이_사용자_직무를_쓴다() { when(user.getMajor()).thenReturn("MAJOR_BACKEND"); when(personaRepository.findById(11L)).thenReturn(Optional.of(persona(11L, Role.TECH, Major.FRONTEND))); @@ -235,7 +232,20 @@ private void givenMembers(Long... personaIds) { ArgumentCaptor sent = ArgumentCaptor.forClass(QuestionTailorRequest.class); verify(aiServerClient).tailorQuestions(sent.capture()); - assertThat(sent.getValue().getProfile().getJobRole()).isEqualTo("FRONTEND"); + assertThat(sent.getValue().getProfile().getJobRole()).isEqualTo("BACKEND"); + } + + /** 면접관 전공(BACKEND/FRONTEND)으로 좁히지 않는다. 분석 서버 job_role은 자유 문자열이다. */ + @Test + void 사용자_직무가_웹퍼블리셔면_원문_그대로_보낸다() { + when(user.getMajor()).thenReturn("WEB_PUBLISHER"); + when(personaRepository.findById(11L)).thenReturn(Optional.of(persona(11L, Role.TECH, Major.FRONTEND))); + + service.requestTailor(interview(InterviewMode.SOLO), user); + + ArgumentCaptor sent = ArgumentCaptor.forClass(QuestionTailorRequest.class); + verify(aiServerClient).tailorQuestions(sent.capture()); + assertThat(sent.getValue().getProfile().getJobRole()).isEqualTo("WEB_PUBLISHER"); } /** 인증 서버는 MAJOR_ 접두사를 붙여 내려준다. 떼지 않으면 분석 서버가 모르는 직군이 넘어간다. */ @@ -266,7 +276,7 @@ private void givenMembers(Long... personaIds) { } @Test - void N대1은_기술_면접관_전공이_사용자_전공보다_먼저다() { + void N대1은_기술_면접관_전공과_관계없이_사용자_직무를_쓴다() { when(user.getMajor()).thenReturn("MAJOR_BACKEND"); givenMembers(11L, 12L); when(personaRepository.findAllById(List.of(11L, 12L))) @@ -277,7 +287,7 @@ private void givenMembers(Long... personaIds) { ArgumentCaptor sent = ArgumentCaptor.forClass(QuestionTailorMultiRequest.class); verify(aiServerClient).tailorQuestionsMulti(sent.capture()); - assertThat(sent.getValue().getJobRole()).isEqualTo("FRONTEND"); + assertThat(sent.getValue().getJobRole()).isEqualTo("BACKEND"); } @Test