Skip to content

Comments

[hotfix] 지원자 응답 순서 보장#685

Merged
lepitaaar merged 1 commit intodevelop/befrom
fix/sort-application-answer
Aug 20, 2025
Merged

[hotfix] 지원자 응답 순서 보장#685
lepitaaar merged 1 commit intodevelop/befrom
fix/sort-application-answer

Conversation

@lepitaaar
Copy link
Contributor

@lepitaaar lepitaaar commented Aug 20, 2025

#️⃣연관된 이슈

ex) #이슈번호, #이슈번호

📝작업 내용

지원자의 응답을 지원서의 순서에 맞게 정렬하여 응답해줍니다.
이를통해 프론트에서 이름을 가져오는 부분에 문제가 생기지않도록 보장합니다

중점적으로 리뷰받고 싶은 부분(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

논의하고 싶은 부분(선택)

논의하고 싶은 부분이 있다면 작성해주세요.

🫡 참고사항

Summary by CodeRabbit

  • 신규 기능

    • 없음
  • 버그 수정

    • 동아리 지원서 답변이 질문 순서와 다르게 표시되던 문제를 수정했습니다. 이제 지원자 목록/상세에서 답변이 질문 순서대로 일관되게 정렬되어 표시됩니다.
  • 리팩터링

    • 메모와 상태 변경 로직을 분리하고 답변 목록 갱신 방식을 정리해 안정성을 향상했습니다. 사용자 기능 변화는 없습니다.

@lepitaaar lepitaaar self-assigned this Aug 20, 2025
@lepitaaar lepitaaar added 🔨 Refactor 코드 리팩토링 💾 BE Backend 🛠Fix 기능이 의도한 대로 동작하지 않는 버그를 수정 labels Aug 20, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 20, 2025

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: Invalid regex pattern for base branch. Received: "**" at "reviews.auto_review.base_branches[0]"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

ClubApplication 엔티티에서 updateDetail을 제거하고 updateMemo, updateStatus, updateAnswers를 추가했다. ClubApplyService는 getClubApplyInfo에서 ClubQuestion을 조회하고 답변 정렬 로직을 추가했으며, editApplicantDetail에서 분리된 mutator들을 호출하도록 변경했다. 공개 API 시그니처 변화는 없다.

Changes

Cohort / File(s) Summary
Entity mutator 리팩터링
backend/src/main/java/moadong/club/entity/ClubApplication.java
updateDetail(memo, status) 제거. updateMemo(String), updateStatus(ApplicationStatus), updateAnswers(List) 추가. updateAnswers는 기존 답변을 대체(클리어 후 추가). 기타 필드/생성 로직 변경 없음.
Service 로직 정렬/호출 변경
backend/src/main/java/moadong/club/service/ClubApplyService.java
getClubApplyInfo에서 clubId로 ClubQuestion 조회, 미존재 시 APPLICATION_NOT_FOUND 예외. sortApplicationAnswers(ClubQuestion, ClubApplication) 추가하여 질문 순서대로 답변 재정렬 후 매핑. editApplicantDetail에서 updateMemo 및 updateStatus 각각 호출. 외부 API 시그니처 변경 없음.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Client
  participant ClubApplyService as Service
  participant ClubQuestionRepo as ClubQuestionRepo
  participant ClubApplication as Application

  Client->>Service: getClubApplyInfo(clubId)
  Service->>ClubQuestionRepo: findByClubId(clubId)
  alt ClubQuestion 없음
    Service-->>Client: throw APPLICATION_NOT_FOUND
  else ClubQuestion 있음
    loop 각 지원서
      Service->>Application: sortApplicationAnswers(question, app)
      note right of Service: 답변을 질문 순서대로 재배치 후<br/>app.updateAnswers(sorted)
      Service->>Application: updateAnswers(sortedAnswers)
    end
    Service-->>Client: ClubApplicantsResult 목록
  end
Loading
sequenceDiagram
  autonumber
  participant Client
  participant ClubApplyService as Service
  participant ClubApplication as Application

  Client->>Service: editApplicantDetail(appId, memo, status)
  Service->>Application: updateMemo(memo)
  Service->>Application: updateStatus(status)
  Service-->>Client: OK
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Zepelown
  • seongwon030
  • oesnuj

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/sort-application-answer

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@vercel
Copy link

vercel bot commented Aug 20, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
moadong Ready Ready Preview Comment Aug 20, 2025 2:04am

@github-actions
Copy link

Test Results

75 tests   75 ✅  2s ⏱️
12 suites   0 💤
12 files     0 ❌

Results for commit 77ad972.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 (5)
backend/src/main/java/moadong/club/service/ClubApplyService.java (3)

102-104: 변수명 혼동: ClubQuestion을 clubApplication 변수명으로 사용

가독성/유지보수 측면에서 혼동을 유발합니다. 동일 메서드 내에서 ClubApplication도 함께 다루고 있어 변수명 충돌 위험이 큽니다. 아래처럼 clubQuestion으로 명확히 변경하는 것을 제안합니다.

-        ClubQuestion clubApplication = clubQuestionRepository.findByClubId(clubId)
+        ClubQuestion clubQuestion = clubQuestionRepository.findByClubId(clubId)
                 .orElseThrow(() -> new RestApiException(ErrorCode.APPLICATION_NOT_FOUND));
-            ClubApplication sortedApp = sortApplicationAnswers(clubApplication, app);
+            ClubApplication sortedApp = sortApplicationAnswers(clubQuestion, app);
             applications.add(ClubApplicantsResult.of(sortedApp, cipher));

Also applies to: 112-114


112-114: 정렬 결과를 응답에만 반영하는 접근은 OK

DB 저장 없이 응답 직전에만 정렬해 FE 요구사항(질문 순서 보장)을 만족시키는 선택은 합리적입니다. 루프 내부에서 status 참조는 정렬과 무관하므로 기능적으로 문제 없습니다. 다만 일관성을 위해 switch도 sortedApp을 사용하면 읽기 쉬워집니다.


131-143: 정렬 유틸의 NPE/중복 키 방어 및 폴백 처리 보강 제안

현재 구현은 app.getAnswers()가 null이면 NPE, 중복 answer id가 존재하면 IllegalStateException이 발생할 수 있습니다. 또한 폼 수정 등으로 질문 목록에 없는 기존 답변은 모두 drop됩니다. 아래처럼 방어 로직과 “질문 외 답변은 꼬리에 보존” 폴백을 제안합니다.

-    private ClubApplication sortApplicationAnswers(ClubQuestion application, ClubApplication app) {
-        Map<Long, ClubQuestionAnswer> answerMap = app.getAnswers().stream()
-                .collect(Collectors.toMap(ClubQuestionAnswer::getId, answer -> answer));
-
-        List<ClubQuestionAnswer> sortedAnswers = application.getQuestions().stream()
-                .map(question -> answerMap.get(question.getId()))
-                .filter(Objects::nonNull)
-                .collect(Collectors.toList());
-
-        app.updateAnswers(sortedAnswers);
-        return app;
-    }
+    private ClubApplication sortApplicationAnswers(ClubQuestion application, ClubApplication app) {
+        List<ClubQuestionAnswer> safeAnswers =
+                Optional.ofNullable(app.getAnswers()).orElseGet(Collections::emptyList);
+
+        Map<Long, ClubQuestionAnswer> answerMap = safeAnswers.stream()
+                .collect(Collectors.toMap(ClubQuestionAnswer::getId, Function.identity(), (a, b) -> a));
+
+        Set<Long> orderedIds = application.getQuestions().stream()
+                .map(ClubApplicationQuestion::getId)
+                .collect(Collectors.toCollection(LinkedHashSet::new));
+
+        List<ClubQuestionAnswer> sortedAnswers = orderedIds.stream()
+                .map(answerMap::get)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+
+        // 폼 변경으로 질문에 매칭되지 않는 기존 답변은 꼬리에 보존
+        if (sortedAnswers.size() != safeAnswers.size()) {
+            for (ClubQuestionAnswer ans : safeAnswers) {
+                if (!orderedIds.contains(ans.getId())) {
+                    sortedAnswers.add(ans);
+                }
+            }
+        }
+
+        app.updateAnswers(sortedAnswers);
+        return app;
+    }
backend/src/main/java/moadong/club/entity/ClubApplication.java (2)

46-49: status null 방어 추가 제안

도메인적으로 status가 null이면 일관성 문제가 생깁니다. 간단한 선검증 추가를 권장합니다.

-    public void updateStatus(ApplicationStatus status) {
-        this.status = status;
-    }
+    public void updateStatus(ApplicationStatus status) {
+        if (status == null) {
+            throw new IllegalArgumentException("status must not be null");
+        }
+        this.status = status;
+    }

50-53: updateAnswers의 null 안전성 보강 제안

현재 인자 answers가 null이면 NPE가 발생합니다. 아래처럼 null을 허용하고 빈 리스트로 취급하면 호출부가 단순해집니다. 기존 리스트를 유지하면서 clear/addAll로 갱신하는 방식은 변경 추적(특히 JPA 케이스)과도 잘 맞습니다.

-    public void updateAnswers(List<ClubQuestionAnswer> answers) {
-        this.answers.clear();
-        this.answers.addAll(answers);
-    }
+    public void updateAnswers(List<ClubQuestionAnswer> answers) {
+        this.answers.clear();
+        if (answers != null) {
+            this.answers.addAll(answers);
+        }
+    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ff4c17c and 77ad972.

📒 Files selected for processing (2)
  • backend/src/main/java/moadong/club/entity/ClubApplication.java (1 hunks)
  • backend/src/main/java/moadong/club/service/ClubApplyService.java (5 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-05-19T05:45:52.957Z
Learnt from: lepitaaar
PR: Moadong/moadong#406
File: backend/src/main/java/moadong/club/service/ClubApplyService.java:34-38
Timestamp: 2025-05-19T05:45:52.957Z
Learning: The code duplication between createClubApplication and editClubApplication methods in ClubApplyService.java is acknowledged but will be addressed in a future refactoring, as per the developer's plan.

Applied to files:

  • backend/src/main/java/moadong/club/entity/ClubApplication.java
  • backend/src/main/java/moadong/club/service/ClubApplyService.java
🔇 Additional comments (3)
backend/src/main/java/moadong/club/service/ClubApplyService.java (2)

307-307: 변경 없음

파일 말미 포맷팅 변경으로 보이며 기능 영향 없습니다.


156-158: 레거시 updateDetail 호출 없음 확인

전체 코드베이스에서 updateDetail( 호출을 검색한 결과가 없으므로, updateMemo/updateStatus 분리 적용이 안전하며 의도한 대로 동작할 것으로 보입니다. 리뷰 승인합니다.

backend/src/main/java/moadong/club/entity/ClubApplication.java (1)

42-45: 메모 업데이트 분리: 단일 책임에 부합, 문제 없음

단순 세터형 변경으로 사이드이펙트 없고 의도가 명확합니다.

Copy link
Member

@Zepelown Zepelown left a comment

Choose a reason for hiding this comment

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

고생하셨습니다

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

Labels

💾 BE Backend 🛠Fix 기능이 의도한 대로 동작하지 않는 버그를 수정 🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants