Conversation
- 지원서 id와 제목, description을 list로 반환
- TODO: status가 null인 경우(마이그레이션X), default로 할 status 결정해야 함
구버전 호환용 v1 api 제공
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
Controllersbackend/src/main/java/moadong/club/controller/ClubApplyController.java, backend/src/main/java/moadong/club/controller/ClubApplyControllerV1.java |
기존 /application 엔드포인트 메타데이터 정비(설명 변경). 신규 V1 컨트롤러 추가: 활성 폼 조회, 지원 제출, 지원자 정보 조회, 지원자 대량 수정/삭제 엔드포인트 추가. |
DTOs (Active/Form Slim & Result Items)backend/src/main/java/moadong/club/payload/dto/ClubActiveFormResult.java, backend/src/main/java/moadong/club/payload/dto/ClubActiveFormSlim.java, backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormSlim.java, backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResultItem.java |
활성 폼 전용 DTO/프로젝션 추가(id/title/description). 기존 Slim/ResultItem에 status 노출(프로퍼티/컴포넌트 추가). |
Requests / Responsesbackend/src/main/java/moadong/club/payload/request/ClubApplicationFormEditRequest.java, backend/src/main/java/moadong/club/payload/response/ClubActiveFormsResponse.java |
EditRequest의 active 타입을 Boolean으로 변경하고 @NotNull 추가. 활성 폼 목록 응답 레코드(Builder 지원) 추가. |
Repositorybackend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.java, backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java |
활성 폼 조회용 쿼리 메서드(findClubActiveFormsByClubId) 및 최신 활성 폼 조회(findTopByClubIdAndStatusOrderByEditedAtDesc) 추가. 기존 폼 목록 프로젝션에 status 포함 및 커스텀 집계 파이프라인에서 status 전파. |
Servicebackend/src/main/java/moadong/club/service/ClubApplyService.java |
그룹화된 목록에 status 포함. edit 대상 조회를 findByClubIdAndId(clubId, id)로 변경. 활성 폼 목록 반환 메서드(getActiveApplicationForms) 추가(없을 시 에러 발생). |
Error Codesbackend/src/main/java/moadong/global/exception/ErrorCode.java |
ACTIVE_APPLICATION_NOT_FOUND 에러 코드 추가. |
Sequence Diagram(s)
sequenceDiagram
autonumber
actor U as 사용자
participant C as ClubApplyControllerV1
participant S as ClubApplyService
participant R as ClubApplicationFormsRepository
rect rgb(238,246,255)
note over U,C: 활성화된 지원서 목록 조회
U->>C: GET /api/club/{clubId}/application/active
C->>S: getActiveApplicationForms(clubId)
S->>R: findClubActiveFormsByClubId(clubId)
R-->>S: List<ClubActiveFormSlim>
alt 결과 있음
S-->>C: ClubActiveFormsResponse(forms)
C-->>U: 200 OK + forms
else 없음
S-->>C: throws ACTIVE_APPLICATION_NOT_FOUND
C-->>U: 404 NOT_FOUND
end
end
sequenceDiagram
autonumber
actor U as 인증된 사용자
participant C as ClubApplyControllerV1
participant S as ClubApplyService
participant R as ClubApplicationFormsRepository
rect rgb(241,255,240)
note over U,C: 활성 폼 기준 지원서 제출
U->>C: POST /api/club/{clubId}/application/apply
C->>R: findTopByClubIdAndStatusOrderByEditedAtDesc(clubId, ACTIVE)
R-->>C: Optional<ClubApplicationForm>
alt 활성 폼 존재
C->>S: apply(clubId, formId, request, user)
S-->>C: ApplicationResult
C-->>U: 200 OK
else 없음
C-->>U: 404 NOT_FOUND (APPLICATION_NOT_FOUND)
end
end
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related issues
- MOA-265: 활성화된 동아리 지원서만 보여준다 — 본 PR의 활성 폼 조회 및 status 전파가 이 요구사항과 직접적으로 일치합니다.
- [feature] MOA-265 활성화된 동아리 지원서만 보여준다 #768: 활성화된 지원서만 노출 기능 설명과 동일한 변경(활성 폼 조회 API·status 포함).
Possibly related PRs
- [feature] 해당 학기에 게시할 지원서 폼을 선택할 수 있다 #765 — 지원서 status/active 개념 도입 및 전파와 직접적으로 관련된 변경입니다.
- [feature] 동아리 지원서 폼 제작 시에 학기를 선택할 수 있고 생성된 모든 지원서 폼을 학기별로 분류하여 조회할 수 있다 #739 — 동일 도메인(컨트롤러/서비스/레포/DTO)에서 프로젝션과 목록 항목 변경을 다루는 PR로 연관성이 높습니다.
- [Release] BE v1.0.6 배포 #675 — ClubApplyController 및 서비스 레이어의 유사 변경을 포함해 관련성이 있습니다.
Suggested labels
✨ Feature, 📬 API, 💾 BE
Suggested reviewers
- lepitaaar
- Zepelown
- PororoAndFriends
- yw6938
Pre-merge checks and finishing touches
❌ Failed checks (2 warnings)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Out of Scope Changes Check | ClubApplicationFormEditRequest의 boolean→Boolean 타입 변경과 @NotNull 추가, Wildcard import 적용 등은 활성화된 지원서 필터링 요구사항과 직접 관련이 없으며 해당 이슈의 범위를 벗어나는 변경사항입니다. | 편집 요청 DTO 변경 및 스타일 관련 수정은 별도의 PR로 분리하거나 제외하여 활성화된 지원서 필터링 기능만 남기도록 조정해 주세요. | |
| Docstring Coverage | Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
✅ Passed checks (3 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title Check | ✅ Passed | 제목 “[feature] 활성화된 동아리 지원서만 보여준다”는 PR의 주요 변경사항인 활성화된 지원서 필터링 기능을 명확하고 간결하게 요약하고 있어 한눈에 이해하기 쉽습니다. |
| Linked Issues Check | ✅ Passed | PR은 레포지토리 조회 메서드에 status == ACTIVE 조건을 추가하고, 이를 반영한 서비스 메서드(getActiveApplicationForms), DTO(ClubActiveFormResult, ClubActiveFormsResponse 등) 및 예외 코드(ACTIVE_APPLICATION_NOT_FOUND) 도입을 통해 활성화된 동아리 지원서만 사용자에게 노출한다는 MOA-265의 요구사항을 충족하고 있습니다. |
✨ Finishing touches
- 📝 Generate docstrings
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
feature/#768-get-active-form-MOA-265
📜 Recent review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
backend/src/main/java/moadong/club/controller/ClubApplyController.java(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- backend/src/main/java/moadong/club/controller/ClubApplyController.java
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 @coderabbitai help to get the list of available commands and usage tips.
Test Results70 tests 67 ✅ 7s ⏱️ Results for commit 1258ecc. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
backend/src/main/java/moadong/club/controller/ClubApplyController.java (2)
64-75: 모드 기반 라우팅이 구현되었지만 파라미터 검증을 고려하세요.모드 파라미터를 통한 조건부 라우팅이 잘 구현되었습니다. 다만
mode파라미터가 임의의 문자열을 허용하므로, 향후 유지보수성을 위해 다음을 고려하세요:옵션 1: Enum 사용
public enum ApplicationListMode { AGG, SERVER } @GetMapping("/application") public ResponseEntity<?> getClubApplications( @PathVariable String clubId, @CurrentUser CustomUserDetails user, @RequestParam(defaultValue = "AGG") ApplicationListMode mode) { return mode == ApplicationListMode.SERVER ? Response.ok(clubApplyService.getGroupedClubApplicationForms(clubId, user)) : Response.ok(clubApplyService.getClubApplicationForms(clubId, user)); }옵션 2: Swagger 문서에 허용 값 명시
@Parameter( name = "mode", description = "조회 모드: agg(aggregation 사용) 또는 server(서버 그룹화)", schema = @Schema(allowableValues = {"agg", "server"}) )
93-97: 주석 처리된 활성 폼 엔드포인트 확인.PR 설명에 따르면 프론트엔드 모달 구현 대기 및 v1 API와의 중복으로 인해 주석 처리되었습니다. 이 엔드포인트가 필요할 때까지 주석으로 유지하거나, 향후 혼란을 방지하기 위해 TODO 주석을 추가하는 것을 고려하세요.
// TODO: 프론트엔드 활성 폼 모달 구현 후 활성화 예정 (v1 API와 중복 해결 필요) // @GetMapping("/apply") // @Operation(summary = "클럽의 활성화된 지원서 목록 불러오기", description = "클럽의 활성화된 모든 지원서 목록을 불러옵니다") // public ResponseEntity<?> getActiveApplicationForms(@PathVariable String clubId) { // return Response.ok(clubApplyService.getActiveApplicationForms(clubId)); // }backend/src/main/java/moadong/club/service/ClubApplyService.java (2)
23-23: 와일드카드 임포트 대신 명시적 임포트를 사용하세요.와일드카드 임포트(
import moadong.club.payload.dto.*,import moadong.club.payload.response.*)는 어떤 클래스가 실제로 사용되는지 명확하지 않으며, 패키지 간 이름 충돌 가능성을 높입니다. 명시적 임포트를 사용하면 의존성 추적이 용이하고 코드 가독성이 향상됩니다.Also applies to: 29-29
207-215: Stream API를 사용하여 코드를 간결하게 개선할 수 있습니다.수동 루프 대신 Stream API를 사용하면 코드가 더 간결하고 함수형 스타일로 작성됩니다.
다음 diff를 적용하여 리팩토링하세요:
- List<ClubActiveFormResult> results = new ArrayList<>(); - for (ClubActiveFormSlim form : forms) { - ClubActiveFormResult result = ClubActiveFormResult.builder() - .id(form.getId()) - .title(form.getTitle()) - .description(form.getDescription()) - .build(); - results.add(result); - } + List<ClubActiveFormResult> results = forms.stream() + .map(form -> ClubActiveFormResult.builder() + .id(form.getId()) + .title(form.getTitle()) + .description(form.getDescription()) + .build()) + .collect(Collectors.toList());
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (12)
backend/src/main/java/moadong/club/controller/ClubApplyController.java(3 hunks)backend/src/main/java/moadong/club/controller/ClubApplyControllerV1.java(1 hunks)backend/src/main/java/moadong/club/payload/dto/ClubActiveFormResult.java(1 hunks)backend/src/main/java/moadong/club/payload/dto/ClubActiveFormSlim.java(1 hunks)backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormSlim.java(2 hunks)backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResultItem.java(1 hunks)backend/src/main/java/moadong/club/payload/request/ClubApplicationFormEditRequest.java(1 hunks)backend/src/main/java/moadong/club/payload/response/ClubActiveFormsResponse.java(1 hunks)backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.java(2 hunks)backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java(2 hunks)backend/src/main/java/moadong/club/service/ClubApplyService.java(4 hunks)backend/src/main/java/moadong/global/exception/ErrorCode.java(1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-09-30T05:26:41.774Z
Learnt from: alsdddk
PR: Moadong/moadong#765
File: backend/src/main/java/moadong/club/service/ClubApplyService.java:431-435
Timestamp: 2025-09-30T05:26:41.774Z
Learning: In the Moadong codebase's club application feature (backend/src/main/java/moadong/club/), multiple ClubApplicationForm entities can have ACTIVE status for the same clubId, semesterYear, and semesterTerm simultaneously. There is no uniqueness constraint requiring only one ACTIVE form per semester.
Applied to files:
backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormSlim.javabackend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.javabackend/src/main/java/moadong/club/service/ClubApplyService.java
📚 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/service/ClubApplyService.javabackend/src/main/java/moadong/club/controller/ClubApplyController.java
📚 Learning: 2025-08-25T14:43:52.320Z
Learnt from: lepitaaar
PR: Moadong/moadong#703
File: backend/src/main/java/moadong/club/controller/ClubApplyController.java:84-84
Timestamp: 2025-08-25T14:43:52.320Z
Learning: In the Moadong codebase, questionId and clubId are equivalent identifiers that represent the same entity. The ClubApplicationRepository.findAllByIdInAndQuestionId method correctly uses clubId as the questionId parameter for filtering club applications.
Applied to files:
backend/src/main/java/moadong/club/service/ClubApplyService.java
📚 Learning: 2025-05-15T12:03:57.356Z
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`와 같은 별도의 클래스를 정의하고 사용해야 합니다. 이렇게 하면 요청 객체 변경이 데이터베이스 스키마나 엔티티 계층에 영향을 미치지 않습니다.
Applied to files:
backend/src/main/java/moadong/club/service/ClubApplyService.java
🧬 Code graph analysis (1)
backend/src/main/java/moadong/club/controller/ClubApplyControllerV1.java (1)
backend/src/main/java/moadong/club/controller/ClubApplyController.java (1)
RestController(33-138)
🔇 Additional comments (12)
backend/src/main/java/moadong/club/payload/request/ClubApplicationFormEditRequest.java (1)
18-19: API 계약 변경: 마이그레이션·문서화 필요
boolean→Boolean+@NotNull변경으로active필드를 누락할 경우 검증 오류 발생
다음 사항 확인 필요:
- API 문서에 breaking change 명시 여부
- 프론트엔드팀에 변경사항 전달 여부
- 클라이언트가
active필드를 명시 전송하도록 수정 여부backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java (1)
32-32: LGTM!상태 필드를 프로젝션과 그룹화 단계에 올바르게 추가했습니다. MongoDB aggregation 파이프라인을 통해 status가 일관되게 전파됩니다.
Also applies to: 46-47
backend/src/main/java/moadong/club/payload/dto/ClubActiveFormSlim.java (1)
1-7: LGTM!Spring Data 프로젝션 인터페이스가 올바르게 정의되었습니다. 활성 폼 조회를 위한 간결한 계약입니다.
backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormSlim.java (1)
3-3: LGTM!프로젝션 인터페이스에 상태 접근자를 올바르게 추가했습니다. 기존 패턴과 일관성을 유지합니다.
Also applies to: 14-14
backend/src/main/java/moadong/club/payload/dto/ClubActiveFormResult.java (1)
1-11: LGTM!활성 폼 결과를 위한 간결한 DTO 레코드입니다.
@Builder사용이 적절하며 구조가 명확합니다.backend/src/main/java/moadong/global/exception/ErrorCode.java (1)
45-45: LGTM!활성 지원서 미발견 시나리오를 위한 새로운 에러 코드가 올바르게 추가되었습니다. 기존 패턴과 일관되며 800 시리즈의 순차적 번호 체계를 따릅니다.
backend/src/main/java/moadong/club/payload/response/ClubActiveFormsResponse.java (1)
1-12: LGTM!활성 폼 목록을 위한 응답 레코드입니다. 구조가 명확하고
@Builder사용이 적절합니다.backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResultItem.java (1)
3-4: LGTM!결과 아이템 레코드에 상태 필드를 올바르게 추가했습니다. 임포트와 컴포넌트 정의가 기존 패턴과 일관됩니다.
Also applies to: 10-11
backend/src/main/java/moadong/club/service/ClubApplyService.java (4)
100-101: LGTM! 보안이 강화되었습니다.
findById에서findByClubIdAndId로 변경하여 clubId를 추가로 검증함으로써, 다른 클럽의 지원서를 수정하는 것을 방지합니다. 이는 보안 측면에서 올바른 개선입니다.
158-160: LGTM! status 필드 전파가 올바르게 구현되었습니다.
ClubApplicationFormsResultItem생성자에status파라미터를 추가하여 지원서 상태 정보를 응답에 포함시키는 것은 PR 목표(활성화된 지원서 표시)와 일치합니다.
201-221: 인증/권한 검증이 누락되었는지 확인하세요.이 메서드는
validateClubOwner를 호출하지 않으며, 누구나 clubId만으로 활성 지원서 목록을 조회할 수 있습니다. PR 설명에 따르면 이는 의도된 동작(공개 접근)일 수 있으나, 코드나 주석에 명시되지 않았습니다.활성 지원서 목록이 공개 정보가 맞는지 확인하세요. 만약 인증이 필요하다면
CustomUserDetails user파라미터를 추가하고 권한 검증을 수행해야 합니다.
223-250: 인증 제거가 의도된 것인지 확인하고 악용 방지책을 고려하세요.메서드 시그니처에서
CustomUserDetails user파라미터가 제거된 것으로 보이며, 이는 익명 지원 제출을 허용하는 것으로 추정됩니다. 이것이 의도된 동작이라면:
- 스팸/악용 방지를 위한 속도 제한(rate limiting) 구현을 고려하세요.
- CAPTCHA나 다른 봇 방지 메커니즘을 추가하는 것을 검토하세요.
- 동일한 지원서에 대한 중복 제출 방지 로직이 필요할 수 있습니다.
익명 접근이 의도되지 않았다면,
CustomUserDetails user파라미터를 복원하고 적절한 인증 검증을 추가하세요.
| .map(ClubApplicationForm::getId) | ||
| .orElseThrow(() -> new RestApiException(ErrorCode.APPLICATION_NOT_FOUND)); | ||
| } | ||
| } |
| @SecurityRequirement(name = "BearerAuth") | ||
| public ResponseEntity<?> getClubApplications(@PathVariable String clubId, | ||
| @CurrentUser CustomUserDetails user, | ||
| @RequestParam(defaultValue = "agg") String mode) { //agg면 aggregation사용, server면, 서비스에서 그룹 및 정렬 |
There was a problem hiding this comment.
네 개발서버랑 메인서버에서 성능테스트가 필요할 거 같습니다
lepitaaar
left a comment
There was a problem hiding this comment.
이전 api 지원까지 정말 잘해주셨습니다!!! 수고하셨습니다
| } | ||
|
|
||
| @DeleteMapping("/applicant/{applicationFormId}") | ||
| @DeleteMapping("/applicant/{applicationFormId}") // |
| @RestController | ||
| @RequestMapping("/api/club/{clubId}") | ||
| @AllArgsConstructor | ||
| @Tag(name = "Club_Apply_V1", | ||
| description = "클럽 지원서 수정 전 API <br>" | ||
| + "구버전 호환을 위한 임시 API입니다. <br>" | ||
| + "프론트에서 formId 기반 신규 규격으로 전환하기 전까지 clubId 기반 요청을 한시적으로 지원합니다. <br>" | ||
| + "(clubId로 활성화된 최신 지원서 양식의 formId를 가져옴)") |
#️⃣연관된 이슈
#768
📝작업 내용
status == ACTIVE 인 동아리 지원서 노출되도록 합니다.
(✅ 머지 후 디비에 status필드가 없는 도큐먼트들의 마이그레이션이 필요합니다.)
관리자 대상으로 사용될 GET /api/club/{clubId}/application에 학기별로 분류 한 후에 id와 제목, 최종수정날짜, status를 함께 반환합니다.
모두에게 사용될 GET /api/club/{clubId}/apply 는 클럽의 활성화된 모든 지원서 목록 리스트를 반환하지만, 아직 프론트에서 활성화된 지원서 목록을 표시하는 모달 구현이 되지 않았기도 하고 v1 api와 겹치기도 하여 주석처리했습니다.

v1
v2
구버전 api 지원 : 추가된 기획이 프론트에 반영되기 전까지 호환성을 위해 ClubApplyControllerV1을 추가했습니다. 이 컨트롤러에는 기존 규격의 api를 모아두었으며, 추후 삭제될 예정입니다.
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
New Features
Changes
Error Handling