[feature] 해당 학기에 게시할 지원서 폼을 선택할 수 있다#765
Conversation
…학기별로 분류하여 조회할 수 있다""
…-applicaton-semester-selection-MOA-231 Revert "Revert "[feature] 동아리 지원서 폼 제작 시에 학기를 선택할 수 있고 생성된 모든 지원서 폼을 …
active, published, unpublished
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
Controllerbackend/src/main/java/moadong/club/controller/ClubApplyController.java |
엔드포인트를 양식(application-form) 기준으로 재설계: 생성/수정/단건조회/목록조회(mode 쿼리), 지원 제출(apply), 지원 정보 조회, 지원자 일괄 수정/삭제. applicationFormId 경로변수 및 mode 쿼리파라미터 추가. |
Servicebackend/src/main/java/moadong/club/service/ClubApplyService.java |
도메인을 Question/Application → ApplicationForm/Applicant로 전환. 양식 생성·수정·조회, 학기 유효성·옵션 생성, 소유자 검증, 평면/집계 조회, 지원 제출 및 지원자 편집/삭제 로직 재구성·추가. |
Entitiesbackend/src/main/java/moadong/club/entity/ClubApplicant.java, .../ClubApplicationForm.java, .../ClubApplicationFormQuestion.java |
엔티티명·컬렉션명 변경(ClubApplication→ClubApplicant, ClubQuestion→ClubApplicationForm 등), 필드명/타입 조정(formId, questions 타입 변경), 양식에 semesterYear/semesterTerm/status 등 필드 추가·변경. |
Enumsbackend/src/main/java/moadong/club/enums/ApplicantStatus.java, .../ApplicationFormStatus.java, .../SemesterTerm.java |
ApplicationStatus → ApplicantStatus 명칭 변경. ApplicationFormStatus(UNPUBLISHED/PUBLISHED/ACTIVE) 및 SemesterTerm(FIRST/SECOND) 신규 추가. |
DTOs (payload/dto, request, response)backend/src/main/java/moadong/club/payload/dto/*, .../payload/request/*, .../payload/response/* |
여러 DTO/레코드/인터페이스 추가·변경: ClubApplicationFormSlim, ClubApplicationFormsResult(+Item), ClubApplicantsResult 타입 변경, 요청: ClubApplicationFormCreateRequest/ClubApplicationFormEditRequest, 응답: ClubApplicationFormResponse/ClubApplicationFormsResponse/SemesterOptionResponse 추가. 기존 ClubApplicationResponse 파일 제거. |
Repositoriesbackend/src/main/java/moadong/club/repository/ClubApplicantsRepository.java, .../ClubApplicationFormsRepository.java, .../ClubApplicationFormsRepositoryCustom.java(삭제) .../ClubApplicationRepository.java, .../ClubQuestionRepository.java |
신규 리포지토리(지원자/양식/집계 커스텀) 추가 및 쿼리(프로젝션·정렬·exists) 도입. 기존 Application/Question 관련 리포지토리 삭제. |
Exceptions / Handlerbackend/src/main/java/moadong/global/exception/ErrorCode.java, .../GlobalExceptionHandler.java |
APPLICATION_NOT_FOUND 메시지 문구 수정; GlobalExceptionHandler는 포맷팅(공백) 변경만. |
Tests & Fixturesbackend/src/test/.../ClubApplyServiceTest.java, .../ClubApplicationEditFixture.java, .../UserFixture.java |
테스트/픽스처를 폼 기반 타입·리포지토리로 갱신 및 일부 테스트 데이터 변경(사용자 자격증명). |
Sequence Diagram(s)
sequenceDiagram
autonumber
actor Client
participant Controller as ClubApplyController
participant Service as ClubApplyService
participant FormsRepo as ClubApplicationFormsRepository
participant FormsRepoC as ClubApplicationFormsRepositoryCustom
participant ApplicantsRepo as ClubApplicantsRepository
rect rgba(227,241,255,0.35)
note over Client,Service: 양식 생성
Client->>Controller: POST /clubs/{clubId}/application-forms
Controller->>Service: createClubApplicationForm(clubId, user, req)
Service->>FormsRepo: save(ClubApplicationForm)
FormsRepo-->>Service: saved
Service-->>Controller: 200
Controller-->>Client: 200
end
rect rgba(232,255,232,0.35)
note over Client,FormsRepoC: 양식 목록 조회 (mode=agg|plain)
Client->>Controller: GET /clubs/{clubId}/application-forms?mode=agg|plain
alt mode==agg
Controller->>Service: getGroupedClubApplicationForms(clubId, user)
Service->>FormsRepoC: aggregate by semester
FormsRepoC-->>Service: List<ClubApplicationFormsResult>
else
Controller->>Service: getClubApplicationForms(clubId, user)
Service->>FormsRepo: findClubApplicationFormsByClubId(...)
FormsRepo-->>Service: List<ClubApplicationFormSlim>
end
Service-->>Controller: ClubApplicationFormsResponse
Controller-->>Client: 200 + body
end
rect rgba(255,244,229,0.35)
note over Client,ApplicantsRepo: 양식에 지원 제출
Client->>Controller: POST /clubs/{clubId}/application-forms/{formId}/apply
Controller->>Service: applyToClub(clubId, formId, req)
Service->>FormsRepo: findById(formId)
FormsRepo-->>Service: ClubApplicationForm?
Service->>ApplicantsRepo: save(ClubApplicant with answers)
ApplicantsRepo-->>Service: saved
Service-->>Controller: 200
Controller-->>Client: 200
end
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related issues
- MOA-239: 해당 학기에 게시할 동아리 지원서를 선택할 수 있다 — ApplicationFormStatus/active 및 mode 기반 조회가 이 이슈 목표와 직접 연관됨.
- [feature] MOA-239 해당 학기에 게시할 동아리 지원서를 선택할 수 있다 #748 — 양식 활성/게시 선택 및 mode 기반 조회 요구와 직접적으로 연관됨.
Possibly related PRs
- Revert "Revert "[feature] 동아리 지원서 폼 제작 시에 학기를 선택할 수 있고 생성된 모든 지원서 폼을 … #762 — 동일한 폼 중심 리팩터링(엔티티/컨트롤러/서비스/리포지토리 변경)과 직접 연관.
- [feature] 동아리 지원서 폼 제작 시에 학기를 선택할 수 있고 생성된 모든 지원서 폼을 학기별로 분류하여 조회할 수 있다 #739 — 폼 중심 전환(학기/상태/리포지토리 교체 등)과 유사한 변경을 포함.
- [feature] 동아리 지원자의 목록을 확인할 수 있다 #532 — 지원 정보 조회 및 지원자 목록 처리(서비스/DTO/리포지토리) 관련 변경과 연관.
Suggested labels
📬 API
Suggested reviewers
- lepitaaar
- yw6938
- Zepelown
- PororoAndFriends
Pre-merge checks and finishing touches
❌ Failed checks (2 warnings)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Out of Scope Changes Check | PR 설명에는 active 상태 필드 추가만 언급되었으나 실제로는 ClubApplication→ClubApplicationForm 대규모 리팩토링과 컨트롤러·서비스·리포지토리·DTO 전반에 걸친 구조 변경이 함께 포함되어 있어 단일 기능 범위를 벗어난 수정이 다수 포함되었습니다. | active 상태 추가 기능 구현만을 위한 변경과 대규모 구조 리팩토링을 분리된 PR로 분리하여 리뷰 범위를 명확히 하는 것을 권장합니다. | |
| Docstring Coverage | Docstring coverage is 0.00% 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 | MOA-239 이슈의 요구 사항인 active 상태 필드 추가, 생성 시 비활성화·수정 시 활성 여부 선택 기능 구현, ACTIVE/PUBLISHED/UNPUBLISHED 상태 전환 로직을 ApplicationFormStatus.fromFlag에 반영해 해당 학기에 게시할 양식을 선택할 수 있도록 하는 기능이 정확히 구현되었습니다. |
✨ Finishing touches
- 📝 Generate Docstrings
🧪 Generate unit tests
- Create PR with unit tests
- Post copyable unit tests in a comment
- Commit unit tests in branch
feature/#748-set-active-form-MOA-239
📜 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 (2)
backend/src/main/java/moadong/club/payload/request/ClubApplicationFormCreateRequest.java(2 hunks)backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.java(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.java
🧰 Additional context used
🧠 Learnings (1)
📚 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/request/ClubApplicationFormCreateRequest.java
🔇 Additional comments (2)
backend/src/main/java/moadong/club/payload/request/ClubApplicationFormCreateRequest.java (2)
12-23: 기존 필드 검증 적절함Record 선언과 기존 필드(
title,description,questions)의 유효성 검증 제약사항이 적절하게 설정되어 있습니다.
25-31: 학기 필드 구현 적절함새로 추가된
semesterYear와semesterTerm필드가 PR 목표에 부합하며, 유효성 검증도 적절합니다:
- 연도 범위(2000-2999)는 과거부터 먼 미래까지 커버하기에 충분합니다.
- 두 필드 모두
@NotNull로 필수 입력이 보장됩니다.Integer타입 사용으로 validation annotation과의 호환성이 확보되었습니다.
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.
🧪 Early access (Sonnet 4.5): enabled
We are currently testing the Sonnet 4.5 model, which is expected to improve code review quality. However, this model may lead to increased noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience.
Note:
- Public repositories are always opted into early access features.
- You can enable or disable early access features from the CodeRabbit UI or by updating the CodeRabbit configuration file.
Comment @coderabbitai help to get the list of available commands and usage tips.
Test Results70 tests 67 ✅ 6s ⏱️ Results for commit 37b3d90. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
backend/src/main/java/moadong/club/payload/request/ClubApplicationFormEditRequest.java (1)
9-23:active필드는Boolean으로 받아야 합니다.지금처럼 primitive
boolean을 쓰면 JSON에서active를 생략해도 기본값false로 들어와서, 단순 내용 수정 요청이 의도치 않게 폼을 비활성화합니다. 실제ClubApplyService.updateClubApplicationForm도if (request.active())/else분기만 있으므로, null 여부로 “상태 변경 요청 여부”를 판별할 수 없고 매번 비활성 로직이 실행됩니다.Boolean으로 변경해 null을 허용하고, 서비스에서 null이면 상태 변경을 건너뛰도록 분기해 주세요.다음과 같이 수정하는 것을 제안합니다:
-public record ClubApplicationFormEditRequest( +public record ClubApplicationFormEditRequest( @NotBlank @Size(max = 50) String title, @NotBlank @Size(max = 3000) String description, - boolean active, + Boolean active, @NotNull @Valid List<ClubApplyQuestion> questions ) { }그리고
ClubApplyService.updateClubApplicationForm(...)내에서null체크를 추가해 주세요:- if (request.active()) { + if (Boolean.TRUE.equals(request.active())) { clubApplicationForm.updateStatus(ClubApplicationStatus.ACTIVE); - } else { + } else if (Boolean.FALSE.equals(request.active())) { clubApplicationForm.updateStatus( clubApplicationForm.getStatus() == ClubApplicationStatus.ACTIVE ? ClubApplicationStatus.PUBLISHED : ClubApplicationStatus.UNPUBLISHED ); }backend/src/test/java/moadong/fixture/ClubApplicationEditFixture.java (1)
17-21: 생성자 인자 누락으로 컴파일 실패 발생
ClubApplicationFormEditRequest레코드 생성자 시그니처가(String, String, boolean, List<...>)인데, 현재 코드에서는 불리언 플래그 인자가 빠져 있어 PR 테스트 파이프라인에서 컴파일 오류가 발생했습니다 (required: String,String,boolean,List<...>; found: String,String,ArrayList<Object>). 불리언 인자를 추가해 주세요.- return new ClubApplicationFormEditRequest( - "테스트123", - "테스트 지원서입니다", - new ArrayList<>() - ); + return new ClubApplicationFormEditRequest( + "테스트123", + "테스트 지원서입니다", + false, + new ArrayList<>() + );backend/src/main/java/moadong/club/service/ClubApplyService.java (2)
318-345: NPE 위험: 답변 값 null 처리 누락validateAnswerLength에서 null에 대해 length() 호출 가능성이 있습니다. 또한 필수 질문에 대해 공백 문자열 허용 여부를 명확히 해야 합니다.
아래 diff 적용:
- ClubApplicationFormQuestion question = questionMap.get(answer.id()); + ClubApplicationFormQuestion question = questionMap.get(answer.id()); // 질문이 없을 경우 예외 처리 if (question == null) { throw new RestApiException(ErrorCode.QUESTION_NOT_FOUND); } - validateAnswerLength(answer.value(), question.getType()); + String value = Optional.ofNullable(answer.value()).orElse(""); + if (Boolean.TRUE.equals(question.getOptions().getRequired()) && value.isBlank()) { + throw new RestApiException(ErrorCode.REQUIRED_QUESTION_MISSING); + } + validateAnswerLength(value, question.getType());
206-233: applyToClub에 상태 검증 및 null 방어 추가
- ClubApplicationForm.getStatus()가 ACTIVE가 아닐 경우 지원 차단(RestApiException(ErrorCode.APPLICATION_NOT_ACTIVE)) 분기 추가 (ApplicationFormStatus import 필요)
- Answer.value()가 null일 수 있으므로 Optional.ofNullable(answer.value()).orElse("")로 rawValue 초기화 후 암호화
- ErrorCode.APPLICATION_NOT_ACTIVE 상수가 정의되어 있지 않으므로 ErrorCode enum에 추가
backend/src/main/java/moadong/club/entity/ClubApplicant.java (1)
3-5: Mongo용 @id로 교체 권장 (JPA @id 혼용 제거)현재 jakarta.persistence.Id를 임포트하고 있어 혼동 소지가 큽니다. Spring Data MongoDB에서는 org.springframework.data.annotation.Id를 사용하세요.
아래 변경을 제안합니다:
-import jakarta.persistence.Id; +import org.springframework.data.annotation.Id;추가로, Mongo에서는 @Enumerated도 의미가 없어 제거를 권장합니다(선택).
backend/src/main/java/moadong/club/entity/ClubApplicationForm.java (1)
3-3: Mongo 엔티티 @id 어노테이션 타입 오류Spring Data Mongo에서는
org.springframework.data.annotation.Id를 사용해야 합니다. 현재jakarta.persistence.Id는 무시되거나 매핑 오류/낙관적 락 비활성화로 이어질 수 있습니다.다음으로 교체하세요:
-import jakarta.persistence.Id; +import org.springframework.data.annotation.Id;
🧹 Nitpick comments (32)
backend/src/main/java/moadong/club/payload/request/ClubApplicantEditRequest.java (1)
12-15: memo 필드의 필수 여부를 명확히 해주세요.아래처럼 조정 가능합니다(필수인 경우):
- @NotNull - @Size(max = 500) - String memo, + @NotBlank + @Size(max = 500) + String memo,backend/src/main/java/moadong/club/enums/SemesterTerm.java (1)
3-6: 편의 메서드 추가를 고려해주세요.
정렬/변환에 자주 쓰인다면 아래와 같은 헬퍼가 유용합니다.public enum SemesterTerm { FIRST, SECOND -} +{ + public int order() { return this == FIRST ? 1 : 2; } + public static SemesterTerm of(int order) { return order == 1 ? FIRST : SECOND; } +}backend/src/main/java/moadong/club/enums/ApplicantStatus.java (1)
4-8: 주석 표현(국문) 다듬기 제안.
‘불합’ → ‘불합격’으로 명확화하면 읽기 좋습니다.- DECLINED, // 불합 + DECLINED, // 불합격backend/src/main/java/moadong/club/payload/response/ClubApplicationFormsResponse.java (1)
3-11: Jackson 역직렬화가 필요하면 @Jacksonized 추가를 고려.
응답 전용이면 불필요하지만, 테스트/내부 매핑에서 빌더 역직렬화가 필요하면 아래처럼 추가하세요. 학습 노트 기준 Lombok 1.18.42 사용 가정.Based on learnings
import lombok.Builder; +import lombok.extern.jackson.Jacksonized; ... -@Builder +@Builder +@Jacksonized public record ClubApplicationFormsResponse( List<ClubApplicationFormsResult> forms ){ }backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResultItem.java (1)
3-9: 날짜/시간 직렬화 포맷 확인 요청.
LocalDateTime은 타임존이 없어 클라이언트 표시에 혼선이 생길 수 있습니다. 프로젝트 전역의 Jackson 설정(예: ISO8601, UTC 고정)과 일치하는지 확인하거나 OffsetDateTime/Instant로의 전환을 검토해주세요.backend/src/main/java/moadong/club/payload/response/SemesterOptionResponse.java (1)
6-12: 불린 컴포넌트 명명 개선 제안.
isExist는 JSON/빌더에서 ‘isIsExist’ 혼동을 유발할 수 있어 ‘exists’가 더 자연스럽습니다.public record SemesterOptionResponse( int semesterYear, SemesterTerm term, - boolean isExist //해당 학기에 이미 지원서가 존재하는지 + boolean exists //해당 학기에 이미 지원서가 존재하는지 ) { }이름 변경 시 호출부/응답 스키마도 함께 반영되었는지 확인 바랍니다.
backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResult.java (1)
6-10: semesterYear의 널 허용 여부 점검.
일반적으로 연도는 항상 존재하므로 primitive int 사용이 안전합니다(불필요한 null 처리 제거).public record ClubApplicationFormsResult( - Integer semesterYear, + int semesterYear, SemesterTerm semesterTerm, List<ClubApplicationFormsResultItem> forms ){ }서비스/리포지토리에서 null을 넣는 경로가 없는지 확인해주세요.
backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java (3)
25-33: NPE 가능성: answers가 null일 때 for-loop에서 터질 수 있습니다.
application.getAnswers()가 null일 경우 반복문에서 NPE가 발생합니다. 방어 코드를 추가해 주세요.다음과 같이 null-safe 처리 제안:
- try { - for (ClubQuestionAnswer answer : application.getAnswers()) { + try { + List<ClubQuestionAnswer> answers = application.getAnswers(); + if (answers == null) { + answers = List.of(); + } + for (ClubQuestionAnswer answer : answers) { String decryptedValue = cipher.decrypt(answer.getValue()); decryptedAnswers.add(ClubQuestionAnswer.builder() .id(answer.getId()) .value(decryptedValue) .build()); }
29-33: 필드 유실 위험: ClubQuestionAnswer 복원 시 id/value만 설정하고 나머지 메타(예: questionId 등)를 잃습니다.매핑 대상이 DTO라면 DTO로 변환하고, 엔티티를 그대로 쓴다면 기존 필드를 유지한 복사(toBuilder 등)로 값만 교체하는 편이 안전합니다.
예시(가능 시):
- decryptedAnswers.add(ClubQuestionAnswer.builder() - .id(answer.getId()) - .value(decryptedValue) - .build()); + decryptedAnswers.add(answer.toBuilder() + .value(decryptedValue) + .build());toBuilder가 없다면, 필요한 모든 필드를 명시적으로 복사해 주세요.
20-21: 응답 레이어에 엔티티 타입(ClubQuestionAnswer) 노출외부 응답에 엔티티를 직접 노출하면 스키마 변경 파급이 커집니다. 전용 응답 DTO(예: ClubApplicantAnswerResponse)로 분리하는 것을 권장합니다.
backend/src/main/java/moadong/club/repository/ClubApplicantsRepository.java (2)
9-10: 파라미터 명 혼동: formId를 받는데 이름이 questionId입니다.메서드 시그니처의 파라미터명을
formId로 맞춰 일관성을 유지해 주세요.- List<ClubApplicant> findAllByFormId(String questionId); + List<ClubApplicant> findAllByFormId(String formId);
8-13: 조회 성능을 위한 인덱스 권장해당 조회는
formId와status로 필터링합니다.formId,status, 그리고 다건 조회의 경우id(혹은_id)에 대한 복합/단일 인덱스를 검토해 주세요.backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java (1)
63-65: 컬렉션명 하드코딩 제거엔티티로부터 컬렉션명을 가져오면 리팩터링에 강합니다.
+import moadong.club.entity.ClubApplicationForm; ... - .aggregate(aggregation, "club_application_forms", ClubApplicationFormsResult.class) + .aggregate(aggregation, mongoTemplate.getCollectionName(ClubApplicationForm.class), ClubApplicationFormsResult.class)backend/src/main/java/moadong/club/payload/response/ClubApplicationFormResponse.java (1)
11-18: 응답에서 엔티티 타입(ClubApplicationFormQuestion) 직접 노출API 안정성을 위해 질문도 전용 DTO(필요한 필드만)를 사용해 주세요. 이후 엔티티 필드가 변경되면 외부 계약이 깨질 수 있습니다.
backend/src/main/java/moadong/club/payload/request/ClubApplicationFormCreateRequest.java (1)
23-26: 빈 리스트 방지 검증 추가 제안
@NotNull만으로는 빈 리스트를 허용합니다. 최소 1개 질문을 요구한다면@NotEmpty를 추가하세요.- @NotNull + @NotNull + @jakarta.validation.constraints.NotEmpty @Valid List<ClubApplyQuestion> questions,backend/src/main/java/moadong/club/controller/ClubApplyController.java (3)
52-63: mode 파라미터 동작/문서 불일치 가능성기본값 "agg"인데 설명은 “학기별로 분류”라 되어 있습니다. 현재 로직은 mode=server일 때 그룹/정렬을 수행합니다. 문구를 명확화하거나 enum 파라미터로 제한하는 걸 권장합니다.
아래처럼 설명을 보완해 주세요:
- @Operation(summary = "클럽 지원서 양식들 불러오기", description = "클럽 지원서 양식들을 학기별로 분류하여 불러옵니다") + @Operation( + summary = "클럽 지원서 양식들 불러오기", + description = "mode=server: 서버에서 학기별 그룹/정렬 결과 반환, mode=agg(기본): 집계 결과 반환" + )또한 String 대신 enum(예: ListMode { agg, server }) 사용을 고려해 주세요.
110-116: @Valid/@validated 혼용 일관화본 파일에서 @validated와 @Valid가 혼재합니다. 프로젝트 컨벤션에 맞춰 일관화해 주세요.
118-130: DELETE 본문 사용 주의DELETE에서 @RequestBody 사용은 일부 클라이언트/프록시에서 호환성 이슈가 있습니다. 경로/쿼리 파라미터로 식별자를 전달하거나 POST 액션 엔드포인트로 변경하는 방안을 검토해 주세요.
backend/src/main/java/moadong/club/service/ClubApplyService.java (5)
79-87: 학기 선택 범위 하드코딩 개선 제안현재 3개 학기만 허용합니다. 운영 요구가 변할 수 있으니 구성값(예: application.semester.selectableCount)으로 외부화하는 것을 권장합니다.
90-101: createQuestions 이중 호출(불필요 연산) 제거동일 요청으로 createQuestions를 두 번 호출합니다. 한 번만 호출하도록 단순화하세요.
아래 diff 적용:
- ClubApplicationForm clubApplicationForm = createQuestions( - ClubApplicationForm.builder() - .clubId(clubId) - .build(), - request); - clubApplicationFormsRepository.save(createQuestions(clubApplicationForm, request)); + ClubApplicationForm form = ClubApplicationForm.builder() + .clubId(clubId) + .build(); + clubApplicationFormsRepository.save(createQuestions(form, request));
169-201: 정렬 Comparator 단순화 가능termRank와 termName 두 단계 비교는 중복일 수 있습니다(SECOND/FIRST만 존재시). 가독성을 위해 단일 키(연도 desc, termRank desc)로 축약 가능.
363-398: create/update 로직 중복createQuestions/updateQuestions가 거의 동일합니다. 빌더/매퍼 유틸로 공통화하세요. 해당 중복은 과거에도 인지된 사항입니다.
Based on learnings
235-266: 상태 카운트 switch 보완 제안향후 상태가 추가될 경우를 대비해 default 분기에서 무시/로그 처리하거나 enum 전부를 처리하도록 개선을 권장합니다.
backend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.java (1)
26-28: Mongo 도메인에서 @Enumerated 제거 권장Spring Data MongoDB는 JPA 어노테이션(@Enumerated)을 사용하지 않습니다. 혼동 방지를 위해 제거를 권장합니다.
backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.java (3)
18-18: 불필요한 메서드 재정의 제거 제안MongoRepository가 이미
findById를 제공합니다. 재정의는 중복이며 유지보수 비용만 증가합니다.다음처럼 제거를 권장합니다:
- Optional<ClubApplicationForm> findById(String formId);
22-27: 프로젝션에 status 포함 고려 + 메서드명 충돌 주의
- 목록 화면/선택 UI에서 상태 노출이 필요할 가능성이 높습니다.
fields에status를 포함하세요.- 동일한 이름의 커스텀 리포지토리 메서드(ClubApplicationFormsRepositoryCustom.findClubApplicationFormsByClubId)와 혼동 소지가 큽니다. 이름을
findSlimsByClubId등으로 변경 검토 바랍니다.다음과 같이 필드 추가를 권장합니다:
@Query( value = "{'clubId': ?0}", - fields = "{'_id': 1, 'title': 1, 'editedAt': 1, 'semesterYear': 1, 'semesterTerm': 1}" + fields = "{'_id': 1, 'title': 1, 'editedAt': 1, 'semesterYear': 1, 'semesterTerm': 1, 'status': 1}" ) List<ClubApplicationFormSlim> findClubApplicationFormsByClubId(String clubId, Sort sort);
28-28: 학기 단위 ‘단일 ACTIVE’ 보장 전략 검토PR 목표상 한 학기에 선택/게시되는 폼이 1개여야 한다면, DB 레벨에서 무결성 보장을 권장합니다(예:
(clubId, semesterYear, semesterTerm, status=ACTIVE)에 유니크 파셜 인덱스). 서비스 로직만으로는 경쟁 조건에 취약합니다.원하시면 Spring Data Mongo @CompoundIndex(또는 마이그레이션 스크립트)로의 설계안을 제안하겠습니다.
backend/src/test/java/moadong/club/service/ClubApplyServiceTest.java (3)
51-56: 중복 조회 단일화
findByClubId를 두 번 호출합니다. 한 번만 조회해 로컬 변수에 담아 재사용하세요.- if (clubApplicationFormsRepository.findByClubId(club.getId()).isEmpty()){ + var forms = clubApplicationFormsRepository.findByClubId(club.getId()); + if (forms.isEmpty()){ throw new NoSuchElementException("테스트를 위한 ClubApplicationForm 문서가 DB에 존재하지 않습니다. 먼저 문서를 생성해주세요."); } - ClubApplicationForm clubApplicationForm = clubApplicationFormsRepository.findByClubId(club.getId()).get(0); + ClubApplicationForm clubApplicationForm = forms.get(0); this.clubApplicationFormId = clubApplicationForm.getId();
59-88: 주석 처리된 테스트 블록 정리장기간 주석된 코드(특히 TODO 포함)는 노이즈입니다. 필요 시 별도 테스트로 복구하고, 아니면 제거하세요.
-// TODO: OptionItem private 삭제 -// -// @Test -// void 현재학기_SECOND이면_내년_FIRST까지() { -// LocalDate base = LocalDate.of(2025,11,12); -// -// List<ClubApplyService.OptionItem> items = clubApplyService.buildOptionItems(base, 3); -// -// List<ClubApplyService.OptionItem> expected = List.of( -// new ClubApplyService.OptionItem(2025, SemesterTerm.SECOND), -// new ClubApplyService.OptionItem(2025, SemesterTerm.WINTER), -// new ClubApplyService.OptionItem(2026, SemesterTerm.FIRST) -// ); -// assertEquals(expected, items); -// } -// -// @Test -// void 현재학기_SUMMER이면_내년_WINTTER까지() { -// LocalDate base = LocalDate.of(2025,7,12); -// -// List<ClubApplyService.OptionItem> items = clubApplyService.buildOptionItems(base, 3); -// -// List<ClubApplyService.OptionItem> expected = List.of( -// new ClubApplyService.OptionItem(2025, SemesterTerm.SUMMER), -// new ClubApplyService.OptionItem(2025, SemesterTerm.SECOND), -// new ClubApplyService.OptionItem(2025, SemesterTerm.WINTER) -// ); -// assertEquals(expected, items); -// }
89-140: 낙관적 락 동시성 테스트는 적절함 + 안정성 보강 제안구현 의도에 부합합니다. 합계 검증을 추가하면 명확합니다. 또한
printStackTrace()는 지양하세요.// THEN: 정확히 하나의 스레드만 성공하고, 나머지는 모두 충돌 예외를 받아야 함 assertEquals(1, successCount.get(), "성공한 요청은 1개여야 합니다."); assertEquals(numberOfThreads - 1, conflictCount.get(), "실패(충돌)한 요청은 " + (numberOfThreads - 1) + "개여야 합니다."); + assertEquals(numberOfThreads, successCount.get() + conflictCount.get(), "성공+실패 합은 스레드 수와 같아야 합니다.");- } catch (Exception e) { - e.printStackTrace(); + } catch (Exception e) { + // 필요시 로거 사용 권장 } finally {backend/src/main/java/moadong/club/entity/ClubApplicationForm.java (2)
71-74: 질문 목록 변경 시 수정시각(editedAt) 갱신 누락데이터 변경 추적을 위해
updateEditedAt()호출을 권장합니다.public void updateQuestions(List<ClubApplicationFormQuestion> newQuestions) { this.questions.clear(); this.questions.addAll(newQuestions); + updateEditedAt(); }
80-86: 학기 정보 변경 시 수정시각 갱신학기/학기차 변경 시에도
editedAt을 갱신하세요.public void updateSemesterYear(Integer semesterYear) { this.semesterYear = semesterYear; + updateEditedAt(); } public void updateSemesterTerm(SemesterTerm semesterTerm) { this.semesterTerm = semesterTerm; + updateEditedAt(); }
📜 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 (28)
backend/src/main/java/moadong/club/controller/ClubApplyController.java(3 hunks)backend/src/main/java/moadong/club/entity/ClubApplicant.java(2 hunks)backend/src/main/java/moadong/club/entity/ClubApplicationForm.java(4 hunks)backend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.java(1 hunks)backend/src/main/java/moadong/club/enums/ApplicantStatus.java(1 hunks)backend/src/main/java/moadong/club/enums/ApplicationFormStatus.java(1 hunks)backend/src/main/java/moadong/club/enums/SemesterTerm.java(1 hunks)backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java(2 hunks)backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormSlim.java(1 hunks)backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResult.java(1 hunks)backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResultItem.java(1 hunks)backend/src/main/java/moadong/club/payload/request/ClubApplicantEditRequest.java(2 hunks)backend/src/main/java/moadong/club/payload/request/ClubApplicationFormCreateRequest.java(2 hunks)backend/src/main/java/moadong/club/payload/request/ClubApplicationFormEditRequest.java(2 hunks)backend/src/main/java/moadong/club/payload/response/ClubApplicationFormResponse.java(1 hunks)backend/src/main/java/moadong/club/payload/response/ClubApplicationFormsResponse.java(1 hunks)backend/src/main/java/moadong/club/payload/response/ClubApplicationResponse.java(0 hunks)backend/src/main/java/moadong/club/payload/response/SemesterOptionResponse.java(1 hunks)backend/src/main/java/moadong/club/repository/ClubApplicantsRepository.java(1 hunks)backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.java(1 hunks)backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java(1 hunks)backend/src/main/java/moadong/club/repository/ClubApplicationRepository.java(0 hunks)backend/src/main/java/moadong/club/repository/ClubQuestionRepository.java(0 hunks)backend/src/main/java/moadong/club/service/ClubApplyService.java(11 hunks)backend/src/main/java/moadong/global/exception/ErrorCode.java(1 hunks)backend/src/main/java/moadong/global/exception/GlobalExceptionHandler.java(2 hunks)backend/src/test/java/moadong/club/service/ClubApplyServiceTest.java(4 hunks)backend/src/test/java/moadong/fixture/ClubApplicationEditFixture.java(2 hunks)
💤 Files with no reviewable changes (3)
- backend/src/main/java/moadong/club/payload/response/ClubApplicationResponse.java
- backend/src/main/java/moadong/club/repository/ClubQuestionRepository.java
- backend/src/main/java/moadong/club/repository/ClubApplicationRepository.java
🧰 Additional context used
🧠 Learnings (2)
📚 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/test/java/moadong/fixture/ClubApplicationEditFixture.javabackend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.javabackend/src/test/java/moadong/club/service/ClubApplyServiceTest.javabackend/src/main/java/moadong/club/service/ClubApplyService.javabackend/src/main/java/moadong/club/entity/ClubApplicant.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/repository/ClubApplicantsRepository.javabackend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.javabackend/src/test/java/moadong/club/service/ClubApplyServiceTest.javabackend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.javabackend/src/main/java/moadong/club/service/ClubApplyService.javabackend/src/main/java/moadong/club/entity/ClubApplicationForm.javabackend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.javabackend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.javabackend/src/main/java/moadong/club/entity/ClubApplicant.javabackend/src/main/java/moadong/club/controller/ClubApplyController.java
🧬 Code graph analysis (7)
backend/src/main/java/moadong/club/repository/ClubApplicantsRepository.java (1)
backend/src/main/java/moadong/club/repository/ClubApplicationRepository.java (1)
ClubApplicationRepository(10-17)
backend/src/test/java/moadong/club/service/ClubApplyServiceTest.java (2)
backend/src/test/java/moadong/fixture/ClubApplicationEditFixture.java (1)
ClubApplicationEditFixture(6-23)backend/src/test/java/moadong/fixture/UserFixture.java (1)
UserFixture(9-33)
backend/src/main/java/moadong/club/service/ClubApplyService.java (2)
backend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.java (1)
AllArgsConstructor(12-36)backend/src/main/java/moadong/club/entity/ClubQuestionAnswer.java (1)
AllArgsConstructor(7-16)
backend/src/main/java/moadong/club/entity/ClubApplicationForm.java (2)
backend/src/main/java/moadong/club/entity/ClubApplicant.java (1)
Document(17-53)backend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.java (1)
AllArgsConstructor(12-36)
backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.java (1)
backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java (1)
Repository(18-69)
backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java (1)
backend/src/main/java/moadong/club/entity/ClubApplicationForm.java (1)
Document(20-96)
backend/src/main/java/moadong/club/entity/ClubApplicant.java (2)
backend/src/main/java/moadong/club/entity/ClubApplicationForm.java (1)
Document(20-96)backend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.java (1)
AllArgsConstructor(12-36)
🪛 GitHub Actions: PR Test
backend/src/test/java/moadong/fixture/ClubApplicationEditFixture.java
[error] 17-17: constructor ClubApplicationFormEditRequest in record ClubApplicationFormEditRequest cannot be applied to given types; required: String,String,boolean,List; found: String,String,ArrayList; reason: actual and formal argument lists differ in length
🔇 Additional comments (18)
backend/src/main/java/moadong/club/payload/request/ClubApplicantEditRequest.java (2)
6-6: enum 교체 적절합니다 (ApplicationStatus → ApplicantStatus).
관련 엔티티/DTO와 일관성 있어 보입니다.
16-18: 상태 타입 변경 전파 확인 요청.
컨트롤러/서비스/테스트 등에서 ApplicantStatus로 모두 교체되었는지 확인해주세요.backend/src/main/java/moadong/club/enums/SemesterTerm.java (1)
3-6: 간결하고 명확합니다.
학기 구분을 FIRST/SECOND로 단순화한 점 좋습니다.backend/src/main/java/moadong/club/enums/ApplicantStatus.java (1)
3-3: 타입명 변경 적절합니다.
Applicant(지원자) 도메인에 맞춘 명명 일관성이 좋아졌습니다.backend/src/main/java/moadong/club/payload/response/ClubApplicationFormsResponse.java (1)
8-12: 응답 컨테이너로 적절합니다.
record + @builder 조합 깔끔합니다.backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResultItem.java (1)
5-9: DTO 구성 적절합니다.
id/title/editedAt 최소 필드로 충분해 보입니다.backend/src/main/java/moadong/club/enums/ApplicationFormStatus.java (2)
3-7: 상태 정의가 요구사항과 일치합니다.
ACTIVE/PUBLISHED/UNPUBLISHED 구분이 명확합니다.
8-15: fromFlag 로직이 설명된 전이 규칙과 일치합니다.
- activeFlag=true → ACTIVE
- activeFlag=false → ACTIVE였으면 PUBLISHED, 아니면 유지
서비스 계층에서 “같은 학기/클럽에 동시에 단 하나의 ACTIVE”가 보장되는지 확인 부탁드립니다(아래 참고).
backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java (1)
50-57: 용어 정렬 로직은 적절합니다.
$indexOfArray로 FIRST/SECOND 정렬 우선순위를 부여하고 내림차순 정렬해 최신 학기→2학기→1학기 순서를 보장합니다. LGTM.
semesterTerm이 DB에 문자열(FIRST/SECOND)로 저장됨을 전제합니다. Object/Number로 저장된 경우 정렬이 깨질 수 있으니 확인 부탁드립니다.backend/src/main/java/moadong/club/payload/request/ClubApplicationFormCreateRequest.java (1)
14-34: PR 목표 준수 확인: 생성 시 활성 상태 설정 불가요청 스키마에 status/active 플래그가 없어서 “생성 시 활성화 불가, 업데이트에서만 변경” 요구사항과 일치합니다. LGTM.
업데이트 경로에서는 boolean 플래그를 받아
ApplicationFormStatus.fromFlag로 전이하는지 서비스 레이어에서 한 번만 확인해 주세요.backend/src/main/java/moadong/club/controller/ClubApplyController.java (2)
41-49: 생성 시 활성화 불가 요구사항 재확인 필요요청 DTO 수준에서 active 설정이 불가능해야 한다는 PR 설명과 일치하는지 확인 부탁드립니다. 컨트롤러에서는 별도 방어가 없어 DTO가 필드를 노출하면 활성화가 생성 시 반영될 수 있습니다.
DTO(ClubApplicationFormCreateRequest)에 active/status 관련 필드가 없는지 확인 부탁드립니다. 필요 시 생성용/수정용 DTO 분리 유지 권장.
84-91: 지원(Apply) 엔드포인트 무인증 노출 의도 확인현재 @PreAuthorize가 없습니다. 공개 지원 폼이라면 OK지만, 의도가 맞는지 확인 바랍니다. 봇/남용 방지를 위한 rate-limit, Captcha 고려도 추천합니다.
backend/src/main/java/moadong/global/exception/GlobalExceptionHandler.java (1)
24-25: 서식 정리만: 동작 영향 없음체이닝 들여쓰기 정리 확인. 동작 변화 없음. LGTM.
Also applies to: 44-45
backend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.java (1)
15-15: 클래스명 변경 적절도메인 전환(질문→양식)과 용어 일치. LGTM.
backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormSlim.java (1)
1-13: 프로젝션 인터페이스 정의 및 사용 적절ClubApplicationFormsRepository#findClubApplicationFormsByClubId 메서드와 ClubApplyService에서 ClubApplicationFormSlim 기반 프로젝션이 정상적으로 사용됨을 확인했습니다. 변경 사항 승인합니다.
backend/src/main/java/moadong/global/exception/ErrorCode.java (1)
40-45: 에러 코드 사용처 확인됨
실제 서비스 로직(ClubApplyService)에서APPLICATION_NOT_FOUND와REQUIRED_QUESTION_MISSING가 모두 참조되는 것을 확인했습니다.backend/src/main/java/moadong/club/entity/ClubApplicationForm.java (2)
57-59: 생성 시 ACTIVE 불가 제약 확인엔티티 빌더로
status를 임의 설정할 수 있습니다. “생성 시 ACTIVE 불가” 정책이 서비스/DTO 레벨에서 강제되는지 확인이 필요합니다(생성 요청 DTO에서 status 제외 또는 강제 UNPUBLISHED 세팅).원하시면 생성/수정 DTO와 서비스 계층에 대한 가드 코드 샘플을 제공하겠습니다.
48-56: 기본 학기 계산 로직 확인기본
semesterTerm이 월<7이면 FIRST, 아니면 SECOND로 고정됩니다. Enum에 SUMMER/WINTER가 존재한다면 기본값 전략이 의도와 일치하는지 재확인 바랍니다.
backend/src/main/java/moadong/club/payload/request/ClubApplicationFormCreateRequest.java
Outdated
Show resolved
Hide resolved
backend/src/main/java/moadong/club/repository/ClubApplicantsRepository.java
Show resolved
Hide resolved
backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java
Show resolved
Hide resolved
| @Transactional //test 사용 | ||
| public void editClubApplicationQuestion(String applicationFormId, CustomUserDetails user, ClubApplicationFormEditRequest request) { | ||
| ClubApplicationForm clubApplicationForm = clubApplicationFormsRepository.findById(applicationFormId) | ||
| .orElseThrow(() -> new RestApiException(ErrorCode.APPLICATION_NOT_FOUND)); | ||
|
|
||
| updateQuestions(clubQuestion, request); | ||
| clubQuestion.updateEditedAt(); | ||
| updateQuestions(clubApplicationForm, request); | ||
| clubApplicationForm.updateEditedAt(); | ||
|
|
||
| clubQuestionRepository.save(clubQuestion); | ||
| clubApplicationFormsRepository.save(clubApplicationForm); | ||
| } |
There was a problem hiding this comment.
보안: 소유자 검증 누락
editClubApplicationQuestion(...)는 컨트롤러에서 직접 노출되진 않지만 서비스 메서드 자체에 소유자 검증이 없습니다. 방어적으로 검증 추가를 권장합니다.
아래 diff 적용:
ClubApplicationForm clubApplicationForm = clubApplicationFormsRepository.findById(applicationFormId)
.orElseThrow(() -> new RestApiException(ErrorCode.APPLICATION_NOT_FOUND));
+ validateClubOwner(clubApplicationForm.getClubId(), user);
updateQuestions(clubApplicationForm, request);
clubApplicationForm.updateEditedAt();📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| @Transactional //test 사용 | |
| public void editClubApplicationQuestion(String applicationFormId, CustomUserDetails user, ClubApplicationFormEditRequest request) { | |
| ClubApplicationForm clubApplicationForm = clubApplicationFormsRepository.findById(applicationFormId) | |
| .orElseThrow(() -> new RestApiException(ErrorCode.APPLICATION_NOT_FOUND)); | |
| updateQuestions(clubQuestion, request); | |
| clubQuestion.updateEditedAt(); | |
| updateQuestions(clubApplicationForm, request); | |
| clubApplicationForm.updateEditedAt(); | |
| clubQuestionRepository.save(clubQuestion); | |
| clubApplicationFormsRepository.save(clubApplicationForm); | |
| } | |
| @Transactional //test 사용 | |
| public void editClubApplicationQuestion(String applicationFormId, CustomUserDetails user, ClubApplicationFormEditRequest request) { | |
| ClubApplicationForm clubApplicationForm = clubApplicationFormsRepository.findById(applicationFormId) | |
| .orElseThrow(() -> new RestApiException(ErrorCode.APPLICATION_NOT_FOUND)); | |
| validateClubOwner(clubApplicationForm.getClubId(), user); | |
| updateQuestions(clubApplicationForm, request); | |
| clubApplicationForm.updateEditedAt(); | |
| clubApplicationFormsRepository.save(clubApplicationForm); | |
| } |
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/club/service/ClubApplyService.java around lines
112 to 121, the editClubApplicationQuestion method lacks owner authorization
checks; update the method to verify that the provided CustomUserDetails is the
owner of the related club (or has appropriate permission) before applying
updates, and if not throw a RestApiException with a suitable error code (e.g.,
ACCESS_DENIED or FORBIDDEN); perform the check after loading clubApplicationForm
(e.g., compare user.getId() to clubApplicationForm.getClub().getOwnerId() or use
an existing ownership helper) and only call updateQuestions/updateEditedAt/save
when the check passes.
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
backend/src/main/java/moadong/club/entity/ClubApplicant.java (1)
3-6: Mongo 엔티티에 JPA 애노테이션(@id, @Enumerated) 혼용됨 — Spring Data MongoDB 전용 애노테이션 적용 필요
MongoDB 엔티티에서jakarta.persistence.Id와@Enumerated는 무시됩니다. 다음과 같이 교체하세요:-import jakarta.persistence.Id; +import org.springframework.data.annotation.Id; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; - @Enumerated(EnumType.STRING)ClubApplicant, ClubApplicationFormQuestion, ClubRecruitmentInformation 등 모든 Mongo 엔티티에서 동일하게 수정해야 합니다.
backend/src/main/java/moadong/club/service/ClubApplyService.java (1)
206-233: 지원 제출 시 ACTIVE 상태 검증 누락비활성/과거 폼에도 지원이 가능해집니다. ACTIVE 상태에서만 지원 가능하도록 차단해 주세요.
적용 diff:
ClubApplicationForm clubApplicationForm = clubApplicationFormsRepository.findByClubIdAndId(clubId, applicationFormId) .orElseThrow(() -> new RestApiException(ErrorCode.APPLICATION_NOT_FOUND)); + if (clubApplicationForm.getStatus() != moadong.club.enums.ApplicationFormStatus.ACTIVE) { + throw new RestApiException(ErrorCode.APPLICATION_NOT_FOUND); + } + validateAnswers(request.questions(), clubApplicationForm);
🧹 Nitpick comments (15)
backend/src/main/java/moadong/club/payload/response/ClubApplicationFormResponse.java (1)
14-15: 응답에 엔티티 타입 노출 최소화 권장List를 그대로 노출하면 도메인/영속성 변경이 API에 전파됩니다. 응답 전용 DTO로 변환하여 안정성을 높이는 편이 좋습니다.
backend/src/main/java/moadong/club/repository/ClubApplicantsRepository.java (2)
9-10: 파라미터명 불일치(questionId) — 혼란 유발메서드명/쿼리는 formId 기준인데 파라미터명이 questionId입니다. 가독성을 위해 formId로 정정하세요(동작에는 영향 없음).
다음 변경 제안:
- List<ClubApplicant> findAllByFormId(String questionId); + List<ClubApplicant> findAllByFormId(String formId);
8-13: 쿼리 성능을 위한 인덱스 제안조회 패턴상 formId(+status) 조합 인덱스를 권장합니다. 예: { formId: 1, status: 1 }, 그리고 id+formId 복합 인덱스.
backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java (1)
24-66: 활성 폼 단일성 보장(도메인 제약) — 운영 측면 권고“해당 학기에 게시할 지원서 폼 선택” 요구사항상 clubId+semesterYear+semesterTerm 조합에서 ACTIVE는 최대 1개여야 합니다. MongoDB Partial Unique Index로 강제하는 것을 권장합니다(예: { clubId:1, semesterYear:1, semesterTerm:1 } unique, partialFilterExpression: { status: 'ACTIVE' }).
backend/src/main/java/moadong/club/payload/request/ClubApplicationFormCreateRequest.java (1)
23-26: 질문 최소 개수 제약 추가(선택)빈 리스트 방지를 위해 @SiZe(min = 1) 추가를 권장합니다.
다음 변경 제안:
- @NotNull - @Valid - List<ClubApplyQuestion> questions, + @NotNull + @Valid + @Size(min = 1) + List<ClubApplyQuestion> questions,backend/src/test/java/moadong/club/service/ClubApplyServiceTest.java (1)
121-124: 예외 타입을 더 구체화하면 테스트 신뢰도 향상DataAccessException 대신(또는 추가로) OptimisticLockingFailureException을 명시적으로 카운트하면 의도한 충돌만 집계됩니다.
다음 변경 예시:
- } catch (DataAccessException e) { + } catch (org.springframework.dao.OptimisticLockingFailureException e) { // DataAccessException은 WriteConflict 등을 포함 conflictCount.incrementAndGet(); + } catch (DataAccessException e) { + // 기타 DataAccessException 로깅/무시 여부는 정책에 따름 + conflictCount.incrementAndGet();backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.java (2)
22-26: 슬림 조회 프로젝션에 status 포함 권장관리 화면에서 활성/비활성 표시가 필요합니다. status 필드를 함께 투영하면 후속 서버측 그룹핑/정렬에서도 유용합니다. ClubApplicationFormSlim DTO에도 status 필드 추가가 필요합니다.
적용 diff:
@Query( value = "{'clubId': ?0}", - fields = "{'_id': 1, 'title': 1, 'editedAt': 1, 'semesterYear': 1, 'semesterTerm': 1}" - ) //필드 5개만 가져옴 + fields = "{'_id': 1, 'title': 1, 'editedAt': 1, 'semesterYear': 1, 'semesterTerm': 1, 'status': 1}" + ) //필드 6개만 가져옴 (status 포함)
18-18: 중복 선언된 findById 제거 권장MongoRepository가 이미 제공하는 시그니처입니다. 인터페이스에 재선언하지 않아도 됩니다.
backend/src/main/java/moadong/club/entity/ClubApplicationForm.java (1)
20-24: 쿼리 성능/정합성 강화를 위한 인덱스 제안다음 필드 조합에 인덱스를 고려해 주세요.
- 단일 키: clubId, editedAt, status
- 복합: (clubId, semesterYear, semesterTerm) — 목록/그룹 조회 최적화
- 선택: (clubId, status=ACTIVE)에 대한 부분(unique) 인덱스 → 클럽당 단 하나의 ACTIVE 보장
부분(unique) 인덱스는 운영 DB 마이그레이션으로 적용하는 편이 안전합니다.
backend/src/main/java/moadong/club/controller/ClubApplyController.java (1)
41-50: 생성 엔드포인트 LGTM권한 체크와 서비스 위임이 명확합니다. (추가로, 생성 시 생성된 리소스 ID/Location 헤더 반환을 고려할 수 있습니다.)
backend/src/main/java/moadong/club/service/ClubApplyService.java (5)
94-101: create에서 createQuestions 이중 호출 제거동일 객체에 두 번 적용하고 있어 불필요한 연산입니다. 한 번만 호출 후 저장하세요.
적용 diff:
- ClubApplicationForm clubApplicationForm = createQuestions( - ClubApplicationForm.builder() - .clubId(clubId) - .build(), - request); - clubApplicationFormsRepository.save(createQuestions(clubApplicationForm, request)); + ClubApplicationForm clubApplicationForm = createQuestions( + ClubApplicationForm.builder() + .clubId(clubId) + .build(), + request); + clubApplicationFormsRepository.save(clubApplicationForm);
79-87: 예외 타입 일관화 제안서비스 전반에서 RestApiException을 사용 중입니다. 학기 검증 실패도 동일하게 RestApiException으로 변환하는 것이 응답 일관성에 좋습니다. ErrorCode에 적합한 항목이 없다면 추가를 고려해 주세요.
147-156: 목록 그룹핑 응답에 status 포함 고려관리 화면에서 활성 폼 강조/토글을 위해 status가 필요할 수 있습니다. Slim 프로젝션/DTO/응답에 status를 추가하면 서버/aggregation 양쪽 모두 일관된 표시가 가능합니다. (리포지토리 프로젝션 변경 코멘트 참조)
112-121: 중복 메서드 정리(테스트용 editClubApplicationQuestion)create/update 경로의 중복이 유지되고 있습니다. 테스트 편의가 필요하다면 내부 헬퍼로 공통화하고 테스트에서 해당 헬퍼를 직접 호출하는 방향을 고려해 주세요. PR 학습 기록에도 중복 제거 계획이 언급되어 있습니다.
Based on learnings
56-77: 타임존 상수화/중복 제거 제안"Asia/Seoul" 사용이 서비스/엔티티 전반에 반복됩니다. private static final ZoneId ZONE_SEOUL = ZoneId.of("Asia/Seoul")로 상수화하여 재사용하면 가독성과 변경 용이성이 향상됩니다.
📜 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 (28)
backend/src/main/java/moadong/club/controller/ClubApplyController.java(3 hunks)backend/src/main/java/moadong/club/entity/ClubApplicant.java(2 hunks)backend/src/main/java/moadong/club/entity/ClubApplicationForm.java(4 hunks)backend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.java(1 hunks)backend/src/main/java/moadong/club/enums/ApplicantStatus.java(1 hunks)backend/src/main/java/moadong/club/enums/ApplicationFormStatus.java(1 hunks)backend/src/main/java/moadong/club/enums/SemesterTerm.java(1 hunks)backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java(2 hunks)backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormSlim.java(1 hunks)backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResult.java(1 hunks)backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResultItem.java(1 hunks)backend/src/main/java/moadong/club/payload/request/ClubApplicantEditRequest.java(2 hunks)backend/src/main/java/moadong/club/payload/request/ClubApplicationFormCreateRequest.java(2 hunks)backend/src/main/java/moadong/club/payload/request/ClubApplicationFormEditRequest.java(2 hunks)backend/src/main/java/moadong/club/payload/response/ClubApplicationFormResponse.java(1 hunks)backend/src/main/java/moadong/club/payload/response/ClubApplicationFormsResponse.java(1 hunks)backend/src/main/java/moadong/club/payload/response/ClubApplicationResponse.java(0 hunks)backend/src/main/java/moadong/club/payload/response/SemesterOptionResponse.java(1 hunks)backend/src/main/java/moadong/club/repository/ClubApplicantsRepository.java(1 hunks)backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.java(1 hunks)backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java(1 hunks)backend/src/main/java/moadong/club/repository/ClubApplicationRepository.java(0 hunks)backend/src/main/java/moadong/club/repository/ClubQuestionRepository.java(0 hunks)backend/src/main/java/moadong/club/service/ClubApplyService.java(11 hunks)backend/src/main/java/moadong/global/exception/ErrorCode.java(1 hunks)backend/src/main/java/moadong/global/exception/GlobalExceptionHandler.java(2 hunks)backend/src/test/java/moadong/club/service/ClubApplyServiceTest.java(4 hunks)backend/src/test/java/moadong/fixture/ClubApplicationEditFixture.java(2 hunks)
💤 Files with no reviewable changes (3)
- backend/src/main/java/moadong/club/repository/ClubQuestionRepository.java
- backend/src/main/java/moadong/club/payload/response/ClubApplicationResponse.java
- backend/src/main/java/moadong/club/repository/ClubApplicationRepository.java
🧰 Additional context used
🧠 Learnings (2)
📚 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/entity/ClubApplicant.javabackend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.javabackend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.javabackend/src/main/java/moadong/club/controller/ClubApplyController.javabackend/src/main/java/moadong/club/repository/ClubApplicantsRepository.javabackend/src/main/java/moadong/club/entity/ClubApplicationForm.javabackend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.javabackend/src/main/java/moadong/club/service/ClubApplyService.javabackend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.javabackend/src/test/java/moadong/club/service/ClubApplyServiceTest.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/entity/ClubApplicant.javabackend/src/main/java/moadong/club/controller/ClubApplyController.javabackend/src/test/java/moadong/fixture/ClubApplicationEditFixture.javabackend/src/main/java/moadong/club/entity/ClubApplicationForm.javabackend/src/main/java/moadong/club/service/ClubApplyService.javabackend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.javabackend/src/main/java/moadong/club/payload/request/ClubApplicationFormCreateRequest.javabackend/src/test/java/moadong/club/service/ClubApplyServiceTest.java
🧬 Code graph analysis (7)
backend/src/main/java/moadong/club/entity/ClubApplicant.java (1)
backend/src/main/java/moadong/club/entity/ClubApplicationForm.java (1)
Document(20-96)
backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java (1)
backend/src/main/java/moadong/club/entity/ClubApplicationForm.java (1)
Document(20-96)
backend/src/main/java/moadong/club/repository/ClubApplicantsRepository.java (1)
backend/src/main/java/moadong/club/repository/ClubApplicationRepository.java (1)
ClubApplicationRepository(10-17)
backend/src/main/java/moadong/club/entity/ClubApplicationForm.java (2)
backend/src/main/java/moadong/club/entity/ClubApplicant.java (1)
Document(17-53)backend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.java (1)
AllArgsConstructor(12-36)
backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.java (1)
backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java (1)
Repository(18-69)
backend/src/main/java/moadong/club/service/ClubApplyService.java (2)
backend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.java (1)
AllArgsConstructor(12-36)backend/src/main/java/moadong/club/entity/ClubQuestionAnswer.java (1)
AllArgsConstructor(7-16)
backend/src/test/java/moadong/club/service/ClubApplyServiceTest.java (2)
backend/src/test/java/moadong/fixture/ClubApplicationEditFixture.java (1)
ClubApplicationEditFixture(6-24)backend/src/test/java/moadong/fixture/UserFixture.java (1)
UserFixture(9-33)
🔇 Additional comments (23)
backend/src/main/java/moadong/global/exception/GlobalExceptionHandler.java (2)
24-26: 메서드 체이닝 들여쓰기 정리 확인했습니다.
ResponseEntity 빌더 체이닝의 들여쓰기가 통일돼 가독성이 좋아졌으며 동작에는 영향이 없습니다.
44-46: 에러 응답 빌더 포맷 정돈 좋습니다.
동일한 패턴으로 들여쓰기를 맞춰서 추후 유지보수 시 읽기 쉬울 듯합니다. 로직 변화는 없어요.backend/src/main/java/moadong/global/exception/ErrorCode.java (1)
40-40: 에러 메시지 용어 정비 적절합니다.
도메인 용어를 “지원서 양식”으로 맞춰 일관성을 확보한 변경으로 동작상 문제 없습니다.backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResultItem.java (1)
5-9: 레코드 정의 깔끔합니다id/title/editedAt 필드 구성과 네이밍 일관성 좋습니다.
backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java (1)
24-46: 복호화 및 매핑 로직 적절함예외 래핑, 로깅, DTO 빌드 모두 일관적입니다. 다운스트림에서 평문 로그가 남지 않도록 유지 부탁드립니다.
backend/src/main/java/moadong/club/enums/SemesterTerm.java (1)
3-6: 학기 구분 enum 추가 적절FIRST/SECOND로 단순 명확하며, 기존 폼 엔티티의 기본값 계산 로직과도 부합합니다.
backend/src/main/java/moadong/club/enums/ApplicantStatus.java (1)
3-8: DECLINED 값 일관 확인 및 주석 수정 요청
- 코드 내에는
REJECTED참조가 없으나, 기존 API 응답 스펙·DB 필드·문서 등 외부에REJECTED를 사용한 이력이 있는지 확인해주세요.- enum 주석을 “불합격”으로 풀어 써 가독성을 높여주세요.
backend/src/main/java/moadong/club/payload/response/ClubApplicationFormsResponse.java (1)
8-11: 새 응답 DTO 설계가 명확합니다레코드에 @builder를 적용해 호출부 사용성을 높였고, 요구되는 데이터 구조를 간결하게 표현했습니다. 추가 조치 필요 없어 보입니다.
backend/src/main/java/moadong/club/payload/request/ClubApplicantEditRequest.java (1)
6-17: ApplicantStatus로의 전환이 일관됩니다상태 필드 타입이 ApplicantStatus로 교체되면서 도메인 네이밍과 정합성이 맞춰졌습니다. 관련 검증 애노테이션도 그대로 유지되어 문제 없습니다.
backend/src/main/java/moadong/club/entity/ClubApplicationFormQuestion.java (1)
15-34: 질문 엔티티 리네이밍이 자연스럽습니다Form 중심 모델에 맞춰 클래스명을 정리했고, 기존 필드와 제약이 그대로 유지되어 하위 호환에도 문제가 없습니다.
backend/src/main/java/moadong/club/payload/response/SemesterOptionResponse.java (1)
6-11: 학기 옵션 응답 구조가 직관적입니다@build(toBuilder=true)로 확장성 확보했고, isExist 주석 덕분에 의미도 명확합니다. 그대로 진행하셔도 되겠습니다.
backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormSlim.java (1)
7-13: Projection 인터페이스 정의가 적절합니다필요한 필드만 제공하는 슬림 뷰를 정의해 조회 성능과 명확성을 동시에 잡았습니다. 추가 피드백 없습니다.
backend/src/main/java/moadong/club/payload/dto/ClubApplicationFormsResult.java (1)
6-10: 학기별 결과 DTO 구성이 깔끔합니다semesterYear·semesterTerm와 폼 리스트를 묶은 구조가 사용 목적에 잘 맞습니다. 문제 없이 승인 가능합니다.
backend/src/main/java/moadong/club/enums/ApplicationFormStatus.java (1)
3-15: fromFlag 로직이 요구사항을 충족합니다활성화 플래그에 따라 ACTIVE/PUBLISHED/UNPUBLISHED 전환 규칙이 정확히 구현됐습니다. 추가 수정 필요 없습니다.
backend/src/test/java/moadong/fixture/ClubApplicationEditFixture.java (1)
7-21: Fixture가 새 EditRequest에 맞게 잘 갱신되었습니다반환 타입과 생성자 인자 모두 최신 도메인 모델과 일치합니다. 테스트 작성 시 활용하기 좋겠습니다.
backend/src/main/java/moadong/club/repository/ClubApplicantsRepository.java (1)
12-12: 상태 필터링 일관성 검토findAllByFormId는 DRAFT 제외 쿼리인데, findAllByIdInAndFormId는 상태 필터가 없습니다. 의도된 차이인지 확인하고, 동일 정책이 필요하면 쿼리를 맞춰 주세요.
[ suggest_recommended_refactor ]
예: DRAFT 제외를 적용하려면- List<ClubApplicant> findAllByIdInAndFormId(List<String> ids, String formId); + @Query("{ '_id': { $in: ?0 }, 'formId': ?1, 'status': { $exists: true, $ne: 'DRAFT' } }") + List<ClubApplicant> findAllByIdInAndFormId(List<String> ids, String formId);backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepositoryCustom.java (1)
50-56: 학기 정렬 상수 범위 확인$indexOfArray ["FIRST","SECOND"] 전제입니다. SemesterTerm에 다른 값(SUMMER/WINTER 등)이 존재하면 정렬이 -1로 섞일 수 있습니다. 용어 집합을 확인하고 필요 시 보정 로직을 추가하세요.
backend/src/test/java/moadong/club/service/ClubApplyServiceTest.java (1)
89-140: 동시 수정 충돌 시나리오 적절 — LGTM@Version 기반 낙관적 락 충돌을 잘 검증하고 있습니다. 성공 1/충돌 n-1 단언도 타당합니다.
backend/src/main/java/moadong/club/payload/response/ClubApplicationFormResponse.java (1)
10-18: Jackson record 직렬화 호환성 확인 필요
Java record 응답 DTO 사용 시 Jackson 2.12+가 필요합니다. pom.xml 또는 build.gradle에서 기본 Jackson 버전을 확인하고, 2.12 미만일 경우 Spring Boot 업그레이드 또는 jackson 모듈 추가/커스텀 Serializer 적용을 검토하세요.backend/src/main/java/moadong/club/entity/ClubApplicationForm.java (3)
48-56: 기본 학기 계산 로직 LGTM현재 날짜(Asia/Seoul) 기준으로 연도/학기를 기본값으로 설정하는 처리 적절합니다.
71-74: 질문 리스트 치환 처리 LGTM내부 리스트를 clear 후 addAll로 교체하는 방식은 참조 안정성 측면에서 무난합니다.
88-90: updateFormStatus(boolean) 규약 확인 요청PR 명세의 전환 규칙과 정확히 일치하는지 확인이 필요합니다:
- activeFlag=true → ACTIVE
- activeFlag=false → 기존 상태가 ACTIVE면 PUBLISHED, 그 외는 UNPUBLISHED
ApplicationFormStatus.fromFlag의 동작이 위 규칙과 동일한지 확인 부탁드립니다.
backend/src/main/java/moadong/club/controller/ClubApplyController.java (1)
52-63: mode 파라미터 분기 LGTM기본값 agg→Aggregation, server→서버측 그룹핑으로 분기 동작이 주석과 일치합니다.
| @GetMapping("/apply/{applicationFormId}") | ||
| @Operation(summary = "클럽 지원서 양식 불러오기", description = "클럽 지원서 양식을 불러옵니다") | ||
| public ResponseEntity<?> getClubApplication(@PathVariable String clubId, | ||
| @PathVariable String applicationFormId) { | ||
| return clubApplyService.getClubApplicationForm(clubId, applicationFormId); | ||
| } | ||
|
|
||
| @PostMapping("/apply") | ||
| @PostMapping("/apply/{applicationFormId}") | ||
| @Operation(summary = "클럽 지원", description = "클럽에 지원합니다") | ||
| public ResponseEntity<?> applyToClub(@PathVariable String clubId, | ||
| @PathVariable String applicationFormId, | ||
| @RequestBody @Validated ClubApplyRequest request) { | ||
| clubApplyService.applyToClub(clubId, request); | ||
| clubApplyService.applyToClub(clubId, applicationFormId, request); | ||
| return Response.ok("success apply"); | ||
| } |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
backend/src/main/java/moadong/club/payload/request/ClubApplicationFormCreateRequest.java
Outdated
Show resolved
Hide resolved
| boolean active, | ||
|
|
||
| @NotNull | ||
| @Valid | ||
| List<ClubApplyQuestion> questions |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
backend/src/main/java/moadong/club/repository/ClubApplicationFormsRepository.java
Outdated
Show resolved
Hide resolved
| GroupOperation groupOperation = Aggregation.group("semesterYear","semesterTerm") | ||
| .push(new Document("_id", "$_id") | ||
| .append("title", "$title") | ||
| .append("editedAt", "$editedAt")) | ||
| .as("forms"); | ||
| operations.add(groupOperation); |
This comment was marked as abuse.
This comment was marked as abuse.
Sorry, something went wrong.
| public void editClubApplication(String clubId, String applicationFormId, CustomUserDetails user, ClubApplicationFormEditRequest request) { | ||
| validateClubOwner(clubId, user); | ||
|
|
||
| ClubApplicationForm clubApplicationForm = clubApplicationFormsRepository.findById(applicationFormId) | ||
| .orElseThrow(() -> new RestApiException(ErrorCode.APPLICATION_NOT_FOUND)); | ||
|
|
||
| clubApplicationForm.updateEditedAt(); | ||
| clubApplicationFormsRepository.save(updateQuestions(clubApplicationForm, request)); | ||
| } |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
version 필드가 구현된 user로 변경
#️⃣연관된 이슈
#748
📝작업 내용
중점적으로 리뷰받고 싶은 부분(선택)
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit
New Features
Breaking Changes
Refactor