-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor/#55 지원서 조회 시 선택항목의 id, title 모두 반환되도록 수정 및 추가 수정 #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Walkthrough지원서 응답 DTO에 선택지 ID와 제목을 함께 포함하도록 응답 구조를 변경하고, 지원자 조회 흐름을 Council 기반에서 Recruitment 기반으로 리팩토링했습니다. SelectItem 옵션 ID→제목 맵을 생성해 관련 팩토리 메서드로 전달합니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Controller as CouncilController
participant Usecase as CouncilManageUsecase
participant RecruitService as RecruitmentGetService
participant AppGetService as ApplicationGetService
participant AppRepository as ApplicationRepository
participant ResponseBuilder as GetApplicationAdminResponse
Client->>Controller: GET /recruitments/{recruitmentId}/applicants
Controller->>Usecase: getDocumentScreeningApplicants(memberId, recruitmentId)
Usecase->>RecruitService: getRecruitmentById(recruitmentId)
RecruitService-->>Usecase: Recruitment
Usecase->>AppGetService: getDocumentScreeningApplicantsForRecruitment(Recruitment, status)
AppGetService->>AppRepository: findDocumentList*(recruitment)
AppRepository-->>AppGetService: List<CouncilApplicantQueryRow>
AppGetService-->>Usecase: List<CouncilApplicantQueryRow>
Usecase-->>Controller: List<Application>
Controller->>ResponseBuilder: GetApplicationAdminResponse.from(Application)
rect rgb(230, 245, 255)
Note over ResponseBuilder: buildSelectOptionTitleMap(Recruitment) 실행
ResponseBuilder->>ResponseBuilder: SelectItemOption ID → title Map 생성
ResponseBuilder->>ResponseBuilder: ApplicationAnswerResponse.from(item, selectOptionTitleById) 호출
ResponseBuilder->>ResponseBuilder: SelectAnswerResponse.from(selectItem, selectOptionTitleById) 호출
ResponseBuilder->>ResponseBuilder: SelectOptionAnswerResponse 리스트(ID+title) 생성
end
ResponseBuilder-->>Controller: 응답 (선택지 제목 포함)
Controller-->>Client: JSON 응답
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–25 minutes 주의 필요 영역:
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/GetApplicationResponse.java (1)
55-64: 코드 중복을 고려해보세요.이 메서드는
GetApplicationAdminResponse의 동일한 메서드와 중복됩니다. 공통 유틸리티 클래스로 추출하면 유지보수성이 향상됩니다.예시: 공통 헬퍼 클래스 생성
public final class SelectOptionTitleMapBuilder { private SelectOptionTitleMapBuilder() {} public static Map<Long, String> build(Recruitment recruitment) { return recruitment.getItems().stream() .filter(item -> item instanceof SelectItem) .map(item -> (SelectItem)item) .flatMap(selectItem -> selectItem.getSelectItemOptions().stream()) .collect(Collectors.toMap( SelectItemOption::getId, SelectItemOption::getTitle )); } }src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/SelectAnswerResponse.java (1)
31-46: Null 안전성과 변수명 개선이 필요합니다.로직은 올바르지만 다음 개선 사항을 고려하세요:
Null 안전성: 35번 라인의
selectOptionTitleById.get(optionId)는 맵에 해당 키가 없을 경우 null을 반환할 수 있습니다. 데이터 불일치 상황(예: 저장된 답변의 옵션 ID가 현재 모집 항목에 존재하지 않는 경우)에서 문제가 발생할 수 있습니다.변수명 개선: 34번 라인의
selectOptionTitles는 실제로SelectOptionAnswerResponse객체 리스트이므로 오해의 소지가 있습니다.다음 diff를 적용하여 개선하세요:
public static SelectAnswerResponse from(SelectItem selectItem, Map<Long, String> selectOptionTitleById) { List<Long> selectOptionIds = selectItem.getAnswer() == null ? List.of() : selectItem.getAnswer().answer(); - List<SelectOptionAnswerResponse> selectOptionTitles = selectOptionIds.stream() - .map(optionId -> new SelectOptionAnswerResponse(optionId, selectOptionTitleById.get(optionId))) + List<SelectOptionAnswerResponse> selectOptions = selectOptionIds.stream() + .map(optionId -> new SelectOptionAnswerResponse( + optionId, + selectOptionTitleById.getOrDefault(optionId, "Unknown Option") + )) .toList(); return new SelectAnswerResponse( ItemType.SELECT, selectItem.getTitle(), selectItem.getOrder(), selectItem.getDescription(), selectItem.isMultiple(), - selectOptionTitles + selectOptions ); }참고: 학습된 컨텍스트에 따르면 지원서 제출 후 모집 항목 필드가 불변으로 유지된다고 하므로, 데이터 불일치가 발생할 가능성은 낮지만 방어적 코딩을 위해 null 처리를 추가하는 것이 좋습니다.
Based on learnings
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/ApplicationAnswerResponse.java(2 hunks)src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/GetApplicationAdminResponse.java(3 hunks)src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/GetApplicationResponse.java(3 hunks)src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/SelectAnswerResponse.java(2 hunks)src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/SelectOptionAnswerResponse.java(1 hunks)src/main/java/com/unionmate/backend/domain/applicant/domain/repository/ApplicationRepository.java(2 hunks)src/main/java/com/unionmate/backend/domain/applicant/domain/service/ApplicationGetService.java(1 hunks)src/main/java/com/unionmate/backend/domain/council/application/usecase/CouncilManageUsecase.java(4 hunks)src/main/java/com/unionmate/backend/domain/council/presentation/CouncilController.java(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-26T13:02:17.892Z
Learnt from: 1winhyun
Repo: UnionMate/UnionMate-BE PR: 24
File: src/main/java/com/unionmate/backend/domain/applicant/application/usecase/ApplicationUseCase.java:288-293
Timestamp: 2025-10-26T13:02:17.892Z
Learning: In the UnionMate-BE application system, recruitment item fields (title and order) will be made immutable after applications are submitted. This design constraint ensures that the ExistingAnswers matching logic in ApplicationUseCase (which matches by itemType, title, and order) remains valid and prevents inconsistencies between submitted applications and recruitment templates.
Applied to files:
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/GetApplicationResponse.javasrc/main/java/com/unionmate/backend/domain/applicant/application/dto/response/SelectAnswerResponse.java
🧬 Code graph analysis (4)
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/ApplicationAnswerResponse.java (3)
src/main/java/com/unionmate/backend/domain/recruitment/domain/entity/item/SelectItem.java (1)
Entity(27-91)src/main/java/com/unionmate/backend/domain/recruitment/application/dto/response/SelectOptionResponse.java (2)
from(17-23)SelectOptionResponse(7-24)src/main/java/com/unionmate/backend/domain/applicant/application/dto/request/SelectAnswerRequest.java (1)
SelectAnswerRequest(8-17)
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/SelectOptionAnswerResponse.java (3)
src/main/java/com/unionmate/backend/domain/recruitment/application/dto/response/SelectOptionResponse.java (2)
SelectOptionResponse(7-24)from(17-23)src/main/java/com/unionmate/backend/domain/applicant/application/dto/request/SelectAnswerRequest.java (1)
SelectAnswerRequest(8-17)src/main/java/com/unionmate/backend/domain/recruitment/application/dto/response/SelectResponse.java (1)
SelectResponse(10-53)
src/main/java/com/unionmate/backend/domain/council/presentation/CouncilController.java (1)
src/main/java/com/unionmate/backend/domain/recruitment/presentation/RecruitmentController.java (2)
PatchMapping(47-56)RestController(31-133)
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/GetApplicationResponse.java (2)
src/main/java/com/unionmate/backend/domain/recruitment/domain/entity/item/SelectItem.java (1)
Entity(27-91)src/main/java/com/unionmate/backend/domain/recruitment/domain/entity/item/SelectItemOption.java (1)
Entity(20-58)
🔇 Additional comments (13)
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/GetApplicationResponse.java (1)
55-64: 선택 항목 제목 맵 구축 로직이 정확합니다.SelectItem의 모든 SelectItemOption을 순회하여 ID를 키로, 제목을 값으로 하는 맵을 올바르게 생성하고 있습니다.
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/SelectOptionAnswerResponse.java (1)
1-12: 새로운 DTO 구조가 깔끔합니다.선택 항목의 ID와 제목을 함께 반환하는 목적에 적합한 간결한 레코드 구조입니다. Swagger 문서화도 적절합니다.
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/ApplicationAnswerResponse.java (1)
22-29: 제목 맵 전파 로직이 올바릅니다.SelectItem에만 selectOptionTitleById 맵을 전달하고, 다른 항목 타입에는 영향을 주지 않도록 적절히 구현되었습니다.
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/GetApplicationAdminResponse.java (1)
44-50: 제목 맵 구축 및 전달 로직이 정확합니다.관리자용 응답에서도 선택 항목 제목을 올바르게 매핑하여 답변 변환에 사용하고 있습니다.
src/main/java/com/unionmate/backend/domain/council/presentation/CouncilController.java (2)
143-153: 면접 리스트 API 엔드포인트 변경도 일관성 있게 적용되었습니다.서류 심사와 동일한 패턴으로
recruitmentId기반으로 변경되어 일관성이 유지됩니다.
122-132: 백엔드 엔드포인트 변경 사항은 정상 적용되었으나 프론트엔드 업데이트 확인 불가검증 결과 백엔드 코드에서는 경로 변수가
councilId에서recruitmentId로 정상 변경되었습니다. 기존 엔드포인트 패턴에 대한 참조가 현재 저장소에 남아있지 않으며, CouncilController.java의 해당 엔드포인트들(lines 122, 143)이 올바르게 업데이트되었음을 확인했습니다.그러나 이 저장소는 Java 백엔드 코드만 포함하고 있어, 프론트엔드 및 외부 API 소비자의 업데이트 여부는 이 저장소 내에서 검증할 수 없습니다. 프론트엔드 코드가 별도 저장소에 있다면 그곳에서 새로운 엔드포인트 경로(
/{recruitmentId}/applications/document-screening,/{recruitmentId}/applications/interview)로의 업데이트를 확인하세요.src/main/java/com/unionmate/backend/domain/council/application/usecase/CouncilManageUsecase.java (2)
118-135: Recruitment 기반 조회 로직이 올바르게 구현되었습니다.recruitmentId로 Recruitment를 조회한 후 Council을 파생하는 흐름이 정확합니다. 기존의 권한 검증 로직도 유지되어 안전합니다.
137-154: 면접 지원자 조회 로직도 일관되게 리팩토링되었습니다.서류 심사 메서드와 동일한 패턴으로 Recruitment 기반 조회를 구현하여 일관성이 유지됩니다.
src/main/java/com/unionmate/backend/domain/applicant/domain/service/ApplicationGetService.java (2)
54-67: 서비스 메서드 리네이밍 및 파라미터 변경이 정확합니다.
getDocumentScreeningApplicantsForCouncil에서getDocumentScreeningApplicantsForRecruitment로의 변경이 명확하며, 모든 레포지토리 호출이 Recruitment 파라미터를 일관되게 사용합니다.
69-82: 면접 지원자 조회 메서드도 일관되게 리팩토링되었습니다.서류 심사 메서드와 동일한 패턴으로 Recruitment 기반으로 변경되어 전체 리팩토링의 일관성이 유지됩니다.
src/main/java/com/unionmate/backend/domain/applicant/domain/repository/ApplicationRepository.java (1)
26-135: Recruitment 기반 쿼리로의 변환이 모든 계층에서 올바르게 구현되었습니다.전체 호출 체인을 검증했으며, 모든 단계에서 일관되게 Recruitment 파라미터를 사용합니다:
- ApplicationRepository의 모든 쿼리 메서드 (8개)가 Recruitment 파라미터 사용 ✓
- ApplicationGetService의 두 메서드가 Recruitment을 수신하고 전달 ✓
- CouncilManageUsecase가 recruitmentId에서 Recruitment를 올바르게 조회하고 전달 ✓
- 레거시 Council 기반 메서드 호출 없음 ✓
모든 호출자가 정상적으로 업데이트되었습니다.
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/SelectAnswerResponse.java (2)
4-4: LGTM!새로운 팩토리 메서드 시그니처에 필요한 import 추가입니다.
27-28: API 응답 구조 변경이 정상 적용되었으나, 클라이언트 호환성 검증이 필요합니다.변경 사항 검증 결과:
SelectAnswerResponse의selectOptions필드가List<Long>에서List<SelectOptionAnswerResponse>로 변경됨 (각 선택지의 ID와 제목 포함)- 영향 범위:
GetApplicationResponse(사용자 API)와GetApplicationAdminResponse(관리자 API) 두 엔드포인트 모두에 적용됨- 구현은 올바르고 일관성 있게 적용됨
다만 이는 API 응답 구조의 breaking change이므로, 외부 클라이언트와 연동 시스템이 새로운 응답 형식(
{optionId, title})을 처리할 수 있도록 준비되었는지 확인 필요합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/SelectAnswerResponse.java (1)
31-36: 존재하지 않는 옵션 ID에 대한 방어 로직 필요Line 35에서
selectOptionTitleById.get(optionId)가 null을 반환할 수 있습니다. 옵션이 삭제되었거나 데이터 불일치가 있는 경우SelectOptionAnswerResponse가 null 제목을 가지게 됩니다.학습된 내용에 따르면 지원서 제출 후 모집 항목 필드가 불변이지만, 과거 데이터나 예외 상황을 고려한 방어 코드가 권장됩니다.
다음과 같이 누락된 키에 대한 처리를 추가하세요:
List<SelectOptionAnswerResponse> selectOptions = selectOptionIds.stream() - .map(optionId -> new SelectOptionAnswerResponse(optionId, selectOptionTitleById.get(optionId))) + .map(optionId -> { + String title = selectOptionTitleById.getOrDefault(optionId, "삭제된 옵션"); + return new SelectOptionAnswerResponse(optionId, title); + }) .toList();또는 더 엄격한 검증이 필요한 경우:
List<SelectOptionAnswerResponse> selectOptions = selectOptionIds.stream() - .map(optionId -> new SelectOptionAnswerResponse(optionId, selectOptionTitleById.get(optionId))) + .map(optionId -> { + String title = selectOptionTitleById.get(optionId); + if (title == null) { + throw new IllegalStateException("SelectOption not found for ID: " + optionId); + } + return new SelectOptionAnswerResponse(optionId, title); + }) .toList();Based on learnings
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/GetApplicationAdminResponse.java(3 hunks)src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/GetApplicationResponse.java(3 hunks)src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/SelectAnswerResponse.java(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/GetApplicationResponse.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-26T13:02:17.892Z
Learnt from: 1winhyun
Repo: UnionMate/UnionMate-BE PR: 24
File: src/main/java/com/unionmate/backend/domain/applicant/application/usecase/ApplicationUseCase.java:288-293
Timestamp: 2025-10-26T13:02:17.892Z
Learning: In the UnionMate-BE application system, recruitment item fields (title and order) will be made immutable after applications are submitted. This design constraint ensures that the ExistingAnswers matching logic in ApplicationUseCase (which matches by itemType, title, and order) remains valid and prevents inconsistencies between submitted applications and recruitment templates.
Applied to files:
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/SelectAnswerResponse.java
🔇 Additional comments (3)
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/GetApplicationAdminResponse.java (2)
45-49: Map 생성 및 사용 로직 확인 완료
buildSelectOptionMap을 통해 선택지 옵션 ID→제목 매핑을 생성하고, 각 답변 항목에 전달하는 로직이 올바르게 구현되었습니다.
129-138: 리뷰 코멘트가 정확하지 않습니다.검증 결과,
SelectItemOption은BaseEntity를 상속하며, ID는@GeneratedValue(strategy = GenerationType.IDENTITY)로 정의되어 있습니다. 이는 데이터베이스 시퀀스에서 각 레코드에 전역적으로 고유한 ID를 자동 생성한다는 의미입니다.따라서:
- 서로 다른
SelectItem에 속한SelectItemOption들이 중복된 ID를 가질 수 없습니다.Collectors.toMap에서 중복 키가 발생하여IllegalStateException이 던져질 가능성은 없습니다.- 현재 코드는 안전합니다.
Likely an incorrect or invalid review comment.
src/main/java/com/unionmate/backend/domain/applicant/application/dto/response/SelectAnswerResponse.java (1)
27-28: API 응답 구조 변경 확인선택지 필드가
List<Long> selectedOptionIds에서List<SelectOptionAnswerResponse> selectOptions로 변경되어 ID와 제목을 함께 반환하도록 개선되었습니다. PR 목표와 일치합니다.
rootTiket
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨습니다 👍
Related issue 🛠
작업 내용 💻
스크린샷 📷
같이 얘기해보고 싶은 내용이 있다면 작성 📢
Summary by CodeRabbit
릴리스 노트
새 기능
개선 사항