Skip to content

[feature] 동아리 지원자의 목록을 확인할 수 있다#532

Merged
seongwon030 merged 11 commits intodevelop/befrom
feature/#531-club-applicants-view-MOA-69
Jul 12, 2025
Merged

[feature] 동아리 지원자의 목록을 확인할 수 있다#532
seongwon030 merged 11 commits intodevelop/befrom
feature/#531-club-applicants-view-MOA-69

Conversation

@seongwon030
Copy link
Member

@seongwon030 seongwon030 commented Jul 9, 2025

#️⃣연관된 이슈

ex) #531

📝작업 내용

동아리 지원자 현황을 보기 위한 get api를 제작했습니다.

  • ClubApplicantsResult DTO - 955b60e
  • ClubApplyInfoResponse DTO 6ad9098
  • questionId로 모든 지원서 불러오기 - d19c125
  • 지원정보조회 00f8a05

ClubAppySevice ce61013

  • null또는 DRAFT일 때 서류에 카운트되지 않습니다.
  • reviewRequired -> 제출완료+서류심사중
  • scheduledInterview -> 서류통과+면접일정확정+면접진행중
  • accepted -> 면접통과+최종합격제안+제안수락

ApplicationStatus.java

public enum ApplicationStatus {
    DRAFT,                     // 작성 중
    SUBMITTED,                 // 제출 완료
    SCREENING,                 // 서류 심사 중
    SCREENING_PASSED,          // 서류 통과
    SCREENING_FAILED,          // 서류 탈락
    INTERVIEW_SCHEDULED,       // 면접 일정 확정
    INTERVIEW_IN_PROGRESS,     // 면접 진행 중
    INTERVIEW_PASSED,          // 면접 통과
    INTERVIEW_FAILED,          // 면접 탈락
    OFFERED,                   // 최종 합격 제안
    ACCEPTED,                  // 제안 수락
    DECLINED,                  // 제안 거절
    CANCELED_BY_APPLICANT      // 지원자 자진 철회
}

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

status에 따른 카운트 방식 확인 부탁드립니다

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

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

🫡 참고사항

Summary by CodeRabbit

Summary by CodeRabbit

  • 신규 기능
    • 클럽 지원 현황을 조회할 수 있는 새로운 API 엔드포인트가 추가되었습니다. (클럽 소유자 인증 필요)
    • 지원자 수, 검토 필요 지원, 인터뷰 일정, 합격자 수 등 상세 지원 정보를 확인할 수 있습니다.
    • 각 지원자의 질문별 답변 및 상태를 확인할 수 있습니다.

- questionId, status, answers
- `/apply/info` 엔드포인트 추가
- 사용자별 클럽 지원 정보 반환 로직 구현
- 클럽 지원 정보 응답용 DTO 생성
- total, reviewRequired, scheduledInterview, accepted 필드 추가
- 지원자 목록을 포함하는 applicants 필드 추가
- 사용자별 클럽 지원 정보 반환 메서드 추가
- 제출된 상태별 지원서 통계 계산 로직 구현
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jul 9, 2025

"""

Walkthrough

동아리 지원자의 목록 및 상태별 통계 정보를 반환하는 새로운 GET API(/api/club/{clubId}/apply/info)가 추가되었습니다. 이를 위해 컨트롤러, 서비스, DTO, 레코드, 레포지토리 메서드가 새롭게 구현되어, 동아리 소유자가 지원자 목록과 상태를 확인할 수 있도록 하였습니다.

Changes

파일/경로 요약 변경 내용 요약
.../controller/ClubApplyController.java /api/club/{clubId}/apply/info GET 엔드포인트 및 handler 메서드 추가
.../service/ClubApplyService.java 지원자 목록 및 상태별 집계 반환 메서드(getClubApplyInfo) 추가
.../payload/dto/ClubApplicantsResult.java,
.../payload/response/ClubApplyInfoResponse.java
지원자 정보 및 응답용 레코드(Record) DTO 2종 추가
.../repository/ClubApplicationRepository.java findAllByQuestionId(String questionId) 메서드 선언 추가

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller as ClubApplyController
    participant Service as ClubApplyService
    participant Repository as ClubApplicationRepository

    Client->>Controller: GET /api/club/{clubId}/apply/info (Bearer Token)
    Controller->>Service: getClubApplyInfo(clubId, user)
    Service->>Repository: findAllByClubId(clubId)
    Repository-->>Service: List<ClubApplication>
    Service->>Service: 지원자 필터링/집계 및 DTO 매핑
    Service-->>Controller: ClubApplyInfoResponse
    Controller-->>Client: ResponseEntity<ClubApplyInfoResponse>
Loading

Assessment against linked issues

Objective Addressed Explanation
동아리 지원자의 목록을 확인할 수 있다 (MOA-69)

Assessment against linked issues: Out-of-scope changes

(해당 없음)

Possibly related PRs

  • Moadong/moadong#503: ClubApplyController의 초기 구현 및 지원서 작성/조회/수정/제출 엔드포인트 추가. 본 PR의 신규 지원자 목록/통계 API와 같은 맥락의 확장 PR입니다.

Suggested reviewers

  • Due-IT
  • lepitaaar
    """

📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 449d4aa and 144b341.

📒 Files selected for processing (2)
  • backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java (1 hunks)
  • backend/src/main/java/moadong/club/service/ClubApplyService.java (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • backend/src/main/java/moadong/club/service/ClubApplyService.java
  • backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
✨ Finishing Touches
  • 📝 Generate Docstrings

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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • 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

Documentation and Community

  • 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.

@seongwon030 seongwon030 added ✨ Feature 기능 개발 📬 API 서버 API 통신 작업 💾 BE Backend labels Jul 9, 2025
@seongwon030 seongwon030 linked an issue Jul 9, 2025 that may be closed by this pull request
3 tasks
@github-actions
Copy link

github-actions bot commented Jul 9, 2025

Test Results

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

Results for commit 144b341.

♻️ This comment has been updated with latest results.

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: 1

🧹 Nitpick comments (2)
backend/src/main/java/moadong/club/service/ClubApplyService.java (2)

84-91: 인증 로직 중복 제거 권장

기존 getClubQuestion 메서드와 동일한 인증 로직이 중복되어 있습니다. 공통 메서드로 추출하여 코드 중복을 제거하는 것을 권장합니다.

다음과 같이 공통 메서드를 추출할 수 있습니다:

+private void validateClubOwnership(String clubId, CustomUserDetails user) {
+    Club club = clubRepository.findById(clubId)
+            .orElseThrow(() -> new RestApiException(ErrorCode.CLUB_NOT_FOUND));
+    
+    if (!user.getId().equals(club.getUserId())) {
+        throw new RestApiException(ErrorCode.USER_UNAUTHORIZED);
+    }
+}

그리고 메서드 시작 부분을 다음과 같이 변경:

 public ClubApplyInfoResponse getClubApplyInfo(String clubId, CustomUserDetails user) {
-    Club club = clubRepository.findById(clubId)
-            .orElseThrow(() -> new RestApiException(ErrorCode.CLUB_NOT_FOUND));
-
-    if (!user.getId().equals(club.getUserId())) {
-        throw new RestApiException(ErrorCode.USER_UNAUTHORIZED);
-    }
+    validateClubOwnership(clubId, user);

106-121: 성능 최적화 및 상태 그룹핑 로직 개선

동일한 컬렉션에 대해 여러 번의 스트림 연산을 수행하고 있으며, 상태 그룹핑 로직이 하드코딩되어 있습니다. 단일 스트림으로 최적화하고 상태 그룹핑 로직을 별도 메서드로 추출하는 것을 권장합니다.

다음과 같이 개선할 수 있습니다:

+private boolean isReviewRequired(ApplicationStatus status) {
+    return status == ApplicationStatus.SUBMITTED || status == ApplicationStatus.SCREENING;
+}
+
+private boolean isScheduledInterview(ApplicationStatus status) {
+    return status == ApplicationStatus.SCREENING_PASSED ||
+           status == ApplicationStatus.INTERVIEW_SCHEDULED ||
+           status == ApplicationStatus.INTERVIEW_IN_PROGRESS;
+}
+
+private boolean isAccepted(ApplicationStatus status) {
+    return status == ApplicationStatus.INTERVIEW_PASSED ||
+           status == ApplicationStatus.OFFERED ||
+           status == ApplicationStatus.ACCEPTED;
+}

그리고 카운팅 로직을 다음과 같이 개선:

+int reviewRequired = 0;
+int scheduledInterview = 0;
+int accepted = 0;
+
+for (ClubApplication app : submittedApplications) {
+    ApplicationStatus status = app.getStatus();
+    if (isReviewRequired(status)) reviewRequired++;
+    else if (isScheduledInterview(status)) scheduledInterview++;
+    else if (isAccepted(status)) accepted++;
+}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4aadd3b and ce61013.

📒 Files selected for processing (5)
  • backend/src/main/java/moadong/club/controller/ClubApplyController.java (3 hunks)
  • backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java (1 hunks)
  • backend/src/main/java/moadong/club/payload/response/ClubApplyInfoResponse.java (1 hunks)
  • backend/src/main/java/moadong/club/repository/ClubApplicationRepository.java (1 hunks)
  • backend/src/main/java/moadong/club/service/ClubApplyService.java (2 hunks)
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
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.
Learnt from: seongwon030
PR: Moadong/moadong#195
File: frontend/src/pages/AdminPage/AdminPage.tsx:7-7
Timestamp: 2025-03-19T05:18:07.818Z
Learning: AdminPage.tsx에서 현재 하드코딩된 클럽 ID('67d2e3b9b15c136c6acbf20b')는 로그인 기능 구현 후 동적으로 가져오는 방식으로 수정될 예정입니다.
Learnt from: Zepelown
PR: Moadong/moadong#406
File: backend/src/main/java/moadong/club/entity/ClubApplicationQuestion.java:32-33
Timestamp: 2025-05-15T12:03:57.356Z
Learning: 엔티티 클래스는 요청/응답 객체(DTO)에 의존해서는 안 됩니다. 계층 간 의존성 문제를 방지하기 위해 엔티티와 DTO는 분리되어야 합니다. 예를 들어, `ClubApplicationQuestion` 엔티티가 `ClubApplicationRequest.Options`와 같은 요청 객체를 직접 참조하는 대신, 엔티티 패키지 내에 `QuestionOptions`와 같은 별도의 클래스를 정의하고 사용해야 합니다. 이렇게 하면 요청 객체 변경이 데이터베이스 스키마나 엔티티 계층에 영향을 미치지 않습니다.
backend/src/main/java/moadong/club/repository/ClubApplicationRepository.java (2)
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.
Learnt from: Zepelown
PR: Moadong/moadong#406
File: backend/src/main/java/moadong/club/entity/ClubApplicationQuestion.java:32-33
Timestamp: 2025-05-15T12:03:57.356Z
Learning: 엔티티 클래스는 요청/응답 객체(DTO)에 의존해서는 안 됩니다. 계층 간 의존성 문제를 방지하기 위해 엔티티와 DTO는 분리되어야 합니다. 예를 들어, `ClubApplicationQuestion` 엔티티가 `ClubApplicationRequest.Options`와 같은 요청 객체를 직접 참조하는 대신, 엔티티 패키지 내에 `QuestionOptions`와 같은 별도의 클래스를 정의하고 사용해야 합니다. 이렇게 하면 요청 객체 변경이 데이터베이스 스키마나 엔티티 계층에 영향을 미치지 않습니다.
backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java (2)
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.
Learnt from: Zepelown
PR: Moadong/moadong#406
File: backend/src/main/java/moadong/club/entity/ClubApplicationQuestion.java:32-33
Timestamp: 2025-05-15T12:03:57.356Z
Learning: 엔티티 클래스는 요청/응답 객체(DTO)에 의존해서는 안 됩니다. 계층 간 의존성 문제를 방지하기 위해 엔티티와 DTO는 분리되어야 합니다. 예를 들어, `ClubApplicationQuestion` 엔티티가 `ClubApplicationRequest.Options`와 같은 요청 객체를 직접 참조하는 대신, 엔티티 패키지 내에 `QuestionOptions`와 같은 별도의 클래스를 정의하고 사용해야 합니다. 이렇게 하면 요청 객체 변경이 데이터베이스 스키마나 엔티티 계층에 영향을 미치지 않습니다.
backend/src/main/java/moadong/club/payload/response/ClubApplyInfoResponse.java (1)
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.
backend/src/main/java/moadong/club/controller/ClubApplyController.java (1)
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.
backend/src/main/java/moadong/club/service/ClubApplyService.java (2)
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.
Learnt from: Zepelown
PR: Moadong/moadong#406
File: backend/src/main/java/moadong/club/entity/ClubApplicationQuestion.java:32-33
Timestamp: 2025-05-15T12:03:57.356Z
Learning: 엔티티 클래스는 요청/응답 객체(DTO)에 의존해서는 안 됩니다. 계층 간 의존성 문제를 방지하기 위해 엔티티와 DTO는 분리되어야 합니다. 예를 들어, `ClubApplicationQuestion` 엔티티가 `ClubApplicationRequest.Options`와 같은 요청 객체를 직접 참조하는 대신, 엔티티 패키지 내에 `QuestionOptions`와 같은 별도의 클래스를 정의하고 사용해야 합니다. 이렇게 하면 요청 객체 변경이 데이터베이스 스키마나 엔티티 계층에 영향을 미치지 않습니다.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test
🔇 Additional comments (3)
backend/src/main/java/moadong/club/repository/ClubApplicationRepository.java (1)

9-10: 레포지토리 메서드 추가 승인

Spring Data JPA 네이밍 규칙을 따른 명확한 메서드 구현입니다. 메서드명과 반환 타입이 적절합니다.

backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java (1)

9-15: DTO 레코드 구현 승인

불변성을 제공하는 레코드 구조와 @builder 어노테이션을 활용한 깔끔한 DTO 구현입니다. 필드 타입과 네이밍이 적절합니다.

backend/src/main/java/moadong/club/payload/response/ClubApplyInfoResponse.java (1)

8-16: 응답 레코드 구현 승인

통계 정보와 상세 지원자 정보를 포함한 명확한 응답 구조입니다. 필드명이 비즈니스 로직과 일치하며 타입 선택이 적절합니다.

Copy link
Contributor

@lepitaaar lepitaaar left a comment

Choose a reason for hiding this comment

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

처음인데도 잘해주셨습니다 !! 👍👍

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.

고생하셨습니다~

seongwon030 and others added 2 commits July 12, 2025 17:27
- stream().filter().count() 반복을 제거하고 for + switch로 상태별 카운트 수행
@seongwon030 seongwon030 merged commit dea11cf into develop/be Jul 12, 2025
3 checks passed
@seongwon030 seongwon030 deleted the feature/#531-club-applicants-view-MOA-69 branch July 12, 2025 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📬 API 서버 API 통신 작업 💾 BE Backend ✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature] MOA-69 동아리 지원자의 목록을 확인할 수 있다

3 participants