[refactor] 지원서 api의 clubId path variable 삭제 및 관리자용 분리#780
[refactor] 지원서 api의 clubId path variable 삭제 및 관리자용 분리#780alsdddk merged 5 commits intodevelop/befrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
Admin API 분리 및 리네임backend/src/main/java/moadong/club/controller/ClubApplyAdminController.java, backend/src/main/java/moadong/club/service/ClubApplyAdminService.java, backend/src/test/java/moadong/club/service/ClubApplyAdminServiceTest.java |
기존 ClubApplyController/Service를 관리자 전용으로 리네임(ClubApplyAdminController/ClubApplyAdminService). 클래스 매핑을 /api/club로 변경하고 모든 엔드포인트에서 clubId 경로 매개변수 제거하여 CustomUserDetails.clubId로 조회. 소유자 검증/검증 메서드 일부 제거 및 테스트 필드명 조정. |
Public API 신설backend/src/main/java/moadong/club/controller/ClubApplyPublicController.java, backend/src/main/java/moadong/club/service/ClubApplyPublicService.java |
공용 엔드포인트 추가: 폼 조회(GET) 및 지원 제출(POST). 폼/질문 조회, 필수 항목·길이 검증, AES 암호화 적용, ClubApplicant 생성·저장 및 예외 처리 구현. |
V1 서비스 추가 및 교체backend/src/main/java/moadong/club/controller/ClubApplyControllerV1.java, backend/src/main/java/moadong/club/service/ClubApplyServiceV1.java |
컨트롤러가 ClubApplyServiceV1에 의존하도록 변경. ClubApplyServiceV1 추가(폼 조회, 지원 제출, 지원정보 조회, 지원자 편집·삭제 등), 소유자 검증·답변 정렬·트랜잭션 처리 포함. |
User 모델·회원가입 변경backend/src/main/java/moadong/user/entity/User.java, backend/src/main/java/moadong/user/payload/CustomUserDetails.java, backend/src/main/java/moadong/user/service/UserCommandService.java |
User와 CustomUserDetails에 clubId 필드 추가 및 초기화. 회원가입 흐름에서 userId·clubId 생성(ObjectId)하고 클럽 생성 로직을 조정하며 registerUser에 @Transactional 추가. |
도메인/엔티티 보조 변경backend/src/main/java/moadong/club/entity/Club.java |
Club에 Club(String id, String userId) 생성자 추가(사전 생성된 id로 인스턴스 생성 가능). |
Sequence Diagram(s)
sequenceDiagram
autonumber
actor Admin as 관리자
participant AC as ClubApplyAdminController
participant AS as ClubApplyAdminService
participant Repo as Repository
Note over Admin,AC: 관리자용 API (경로에서 clubId 제거)
Admin->>AC: 요청 (예: GET /api/club/forms)
AC->>AS: 현재 사용자 정보 (CustomUserDetails, user.clubId)
AS->>Repo: user.clubId 기준 조회/수정
Repo-->>AS: 결과 반환
AS-->>AC: 응답 데이터
AC-->>Admin: HTTP 응답
sequenceDiagram
autonumber
actor Applicant as 사용자
participant PC as ClubApplyPublicController
participant PS as ClubApplyPublicService
participant Repo as Repository
participant AES as AESCipher
Note over Applicant,PC: 공용 지원 제출 흐름
Applicant->>PC: POST /api/club/{clubId}/apply/{applicationFormId} + answers
PC->>PS: applyToClub(clubId, applicationFormId, request)
PS->>Repo: 폼 및 질문 조회
Repo-->>PS: 폼 데이터
PS->>PS: 필수/질문 유효성 검사
loop 각 답변
PS->>AES: encrypt(answer)
AES-->>PS: ciphertext
end
PS->>Repo: ClubApplicant 및 암호화된 답변 저장
PS-->>PC: 처리 완료
PC-->>Applicant: HTTP 200 OK
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~60 minutes
Possibly related issues
- [refactor] MOA-283 백엔드 clubId path variable를 삭제한다 #778: 관리자 API에서
clubId경로 변수 제거 및 공용/관리자 API 분리 목표와 직접적으로 일치 — 본 PR이 해당 목표를 구현함. - Moadong/moadong#7781 (MOA-283): 이 이슈의 목적(관리자 API에서 path variable 삭제 및 공용/관리자 분리)이 본 변경 사항과 일치함 — 구현 대상과 매칭됨.
Possibly related PRs
- [release] 모아동 BE v1.0.4 배포 #579: ClubApply 컨트롤러/서비스 분리·리네임과 AESCipher/CustomUserDetails 관련 변경을 다루어 코드 수준 연관성이 높음.
- [refactor] 지원서를 여러개 수정할 수 있다. -BE #703: editApplicantDetail의 배치 업데이트 변경과 시그니처 연동 측면에서 관련됨.
- [feautre] 지원서 관리 API #622: 지원자 편집·삭제 API 시그니처 및 소유자 검증 흐름과 교차하는 변경이 있어 관련됨.
Suggested labels
📬 API
Suggested reviewers
- Zepelown
- lepitaaar
- PororoAndFriends
- yw6938
Pre-merge checks and finishing touches
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| 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 (4 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title Check | ✅ Passed | 제목은 지원서 API에서 clubId 경로 변수를 삭제하고 관리자용 API를 분리한다는 주요 변경 사항을 명확하게 요약하고 있어 PR 내용과 완전히 부합합니다. |
| Linked Issues Check | ✅ Passed | 관리자용 API에서 clubId 경로 변수를 제거하고 userDetails에서 clubId를 획득하도록 변경했으며, Public 및 V1 API를 분리·유지하여 MOA-283의 모든 체크리스트를 충족합니다. |
| Out of Scope Changes Check | ✅ Passed | 제공된 linked issue의 목적과 관계없이 범위를 벗어난 변경 사항이 발견되지 않았으며 모든 변경이 경로 변수 제거 및 API 분리 목표에 부합합니다. |
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
✨ 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
refactor/#778-clubId-pathVariable-MOA-283
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 ✅ 8s ⏱️ Results for commit ac6db67. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Actionable comments posted: 2
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/user/service/UserCommandService.java (1)
43-54: registerUser에 @transactional 추가하여 사용자 저장→클럽 생성→재저장이 한 트랜잭션으로 묶이도록 하세요.
MongoConfig에 MongoTransactionManager가 설정되어 있으며, 다른 서비스에서도 @transactional을 사용 중입니다.backend/src/main/java/moadong/club/service/ClubApplyAdminService.java (1)
248-277: 클럽 소속 검증 누락으로 인한 권한 우회 가능성Line 248와 Line 270에서
applicationFormId만으로 지원자 정보를 수정/삭제합니다.user.getClubId()기반의 소속 검증이 빠져 있어, 타 클럽 관리자가 다른 클럽의applicationFormId와 지원자 ID를 알면 그대로 수정·삭제가 가능해집니다. 관리자용 API에서 clubId path 변수를 제거한 후 반드시 사용자 소속으로 한 번 더 필터링해야 합니다. 아래처럼findByClubIdAndId검증을 선행해 주세요.@Transactional public void editApplicantDetail(String applicationFormId, List<ClubApplicantEditRequest> request, CustomUserDetails user) { + clubApplicationFormsRepository.findByClubIdAndId(user.getClubId(), applicationFormId) + .orElseThrow(() -> new RestApiException(ErrorCode.APPLICATION_NOT_FOUND)); Map<String, ClubApplicantEditRequest> requestMap = request.stream() .collect(Collectors.toMap(ClubApplicantEditRequest::applicantId, Function.identity(), (prev, next) -> next)); @@ @Transactional public void deleteApplicant(String applicationFormId, ClubApplicantDeleteRequest request, CustomUserDetails user) { + clubApplicationFormsRepository.findByClubIdAndId(user.getClubId(), applicationFormId) + .orElseThrow(() -> new RestApiException(ErrorCode.APPLICATION_NOT_FOUND)); List<ClubApplicant> applicants = clubApplicantsRepository.findAllByIdInAndFormId(request.applicantIds(), applicationFormId);
♻️ Duplicate comments (1)
backend/src/main/java/moadong/club/service/ClubApplyPublicService.java (1)
36-124: 코드 중복은 ClubApplyServiceV1에서 이미 지적되었습니다.이 서비스의 모든 메서드가 ClubApplyServiceV1과 중복됩니다. 앞서 제안한 공통 로직 추출 방식을 적용하세요.
Based on learnings
🧹 Nitpick comments (3)
backend/src/main/java/moadong/club/controller/ClubApplyPublicController.java (1)
37-41: 주석 처리된 코드를 제거하세요.주석 처리된 코드는 코드베이스를 혼란스럽게 만듭니다. 이 엔드포인트가 향후 구현 예정이라면 TODO 주석을 추가하거나, 그렇지 않다면 제거하는 것이 좋습니다.
- /*@GetMapping("/apply") -@Operation(summary = "클럽의 활성화된 지원서 목록 불러오기", description = "클럽의 활성화된 모든 지원서 목록을 불러옵니다") -public ResponseEntity<?> getActiveApplicationForms(@PathVariable String clubId) { - return Response.ok(clubApplyService.getActiveApplicationForms(clubId)); -}*/backend/src/main/java/moadong/club/service/ClubApplyServiceV1.java (1)
212-218: 불필요한 검증을 최적화하세요.이제 CustomUserDetails에 clubId가 포함되므로, validateClubOwner에서 club을 조회하고 userId를 비교하는 대신, 직접 user.getClubId()와 clubId를 비교할 수 있습니다.
private void validateClubOwner(String clubId, CustomUserDetails user) { - Club club = clubRepository.findById(clubId) - .orElseThrow(() -> new RestApiException(ErrorCode.CLUB_NOT_FOUND)); - if (!user.getId().equals(club.getUserId())) { + if (!clubId.equals(user.getClubId())) { throw new RestApiException(ErrorCode.USER_UNAUTHORIZED); } }backend/src/main/java/moadong/club/service/ClubApplyPublicService.java (1)
33-33: 미사용 필드를 제거하세요.
ClubApplicationFormsRepositoryCustom필드가 선언되었지만 이 서비스의 어떤 메서드에서도 사용되지 않습니다.private final ClubApplicationFormsRepository clubApplicationFormsRepository; private final ClubApplicantsRepository clubApplicantsRepository; private final AESCipher cipher; -private final ClubApplicationFormsRepositoryCustom clubApplicationFormsRepositoryCustom;
📜 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 (10)
backend/src/main/java/moadong/club/controller/ClubApplyAdminController.java(4 hunks)backend/src/main/java/moadong/club/controller/ClubApplyControllerV1.java(6 hunks)backend/src/main/java/moadong/club/controller/ClubApplyPublicController.java(1 hunks)backend/src/main/java/moadong/club/service/ClubApplyAdminService.java(9 hunks)backend/src/main/java/moadong/club/service/ClubApplyPublicService.java(1 hunks)backend/src/main/java/moadong/club/service/ClubApplyServiceV1.java(1 hunks)backend/src/main/java/moadong/user/entity/User.java(2 hunks)backend/src/main/java/moadong/user/payload/CustomUserDetails.java(1 hunks)backend/src/main/java/moadong/user/service/UserCommandService.java(2 hunks)backend/src/test/java/moadong/club/service/ClubApplyAdminServiceTest.java(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 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/controller/ClubApplyControllerV1.javabackend/src/main/java/moadong/club/service/ClubApplyPublicService.javabackend/src/main/java/moadong/club/service/ClubApplyAdminService.javabackend/src/main/java/moadong/club/controller/ClubApplyAdminController.javabackend/src/main/java/moadong/club/service/ClubApplyServiceV1.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/ClubApplyAdminService.java
📚 Learning: 2025-09-30T05:26:41.788Z
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.788Z
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/service/ClubApplyAdminService.java
🧬 Code graph analysis (3)
backend/src/main/java/moadong/club/service/ClubApplyPublicService.java (1)
backend/src/main/java/moadong/club/service/ClubApplyServiceV1.java (1)
Service(31-219)
backend/src/main/java/moadong/club/controller/ClubApplyPublicController.java (3)
backend/src/main/java/moadong/club/controller/ClubApplyAdminController.java (1)
RestController(32-109)backend/src/main/java/moadong/club/controller/ClubApplyControllerV1.java (1)
RestController(28-104)backend/src/main/java/moadong/club/controller/ClubApplyController.java (1)
RestController(31-111)
backend/src/main/java/moadong/club/service/ClubApplyServiceV1.java (3)
backend/src/main/java/moadong/global/exception/GlobalExceptionHandler.java (1)
Slf4j(13-47)backend/src/main/java/moadong/club/service/ClubApplyAdminService.java (1)
Service(35-355)backend/src/main/java/moadong/club/service/ClubApplyPublicService.java (1)
Service(26-125)
🔇 Additional comments (6)
backend/src/main/java/moadong/user/entity/User.java (1)
87-89: LGTM!updateClubId 메서드는 단순하고 명확하며, UserCommandService.registerUser에서 적절히 사용되고 있습니다.
backend/src/test/java/moadong/club/service/ClubApplyAdminServiceTest.java (1)
30-32: LGTM!테스트 클래스와 서비스 필드의 이름 변경이 관리자 서비스 분리와 일치합니다.
backend/src/main/java/moadong/club/controller/ClubApplyControllerV1.java (1)
15-15: LGTM!ClubApplyServiceV1로의 의존성 변경이 올바르게 적용되었으며, 구버전 호환성을 위한 임시 API 역할이 명확히 문서화되어 있습니다.
Also applies to: 38-38
backend/src/main/java/moadong/user/service/UserCommandService.java (1)
162-165: LGTM!createClub 메서드가 Club ID를 반환하도록 수정되어 registerUser 흐름과 잘 통합됩니다.
backend/src/main/java/moadong/club/controller/ClubApplyPublicController.java (1)
21-35: LGTM!공용 지원서 API가 ClubApplyPublicService로 적절히 분리되었으며, clubId를 path variable로 유지하는 것은 공개 API의 특성상 타당합니다.
backend/src/main/java/moadong/user/payload/CustomUserDetails.java (1)
16-16: 기존 사용자 clubId Null 처리 검증 및 방어 로직 추가
- 기존 데이터에 대한 마이그레이션 또는 초기값 설정 실행 여부 확인
- CustomUserDetails 생성자나 User.getClubId() 호출 시 null 방어 로직 추가 고려
| @NotNull | ||
| private String clubId; |
There was a problem hiding this comment.
@NotNull 필드에 기본값 또는 빌더 검증을 추가하세요.
clubId 필드가 @NotNull로 선언되었지만, @Builder.Default가 없어 빌더 패턴 사용 시 null이 전달될 수 있습니다. 이는 데이터 무결성 문제를 일으킬 수 있습니다.
다음 중 하나를 고려하세요:
- @Builder.Default를 추가하여 기본값 설정 (예: 빈 문자열 또는 특정 초기값)
- 또는 User 빌더 사용 시 clubId가 항상 제공되도록 보장
@NotNull
+@Builder.Default
-private String clubId;
+private String clubId = "";📝 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.
| @NotNull | |
| private String clubId; | |
| @NotNull | |
| @Builder.Default | |
| private String clubId = ""; |
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/user/entity/User.java around lines 45-46, the
clubId field is annotated @NotNull but has no builder default or builder
validation, so using the Lombok @Builder can produce null values; fix by either
adding a @Builder.Default with a safe initial value (e.g., private String clubId
= ""; keeping @NotNull) or by adding a non-null check in the
User.Builder.build() method to throw an explicit exception if clubId is null
(ensuring the builder always supplies a value).
nosql에서 java.persistance.Id를 사용하면 save 메소드 사용시 중복 체크가 제대로 되지 않아 중복 저장시 upsert가 아닌 duplicate key error를 내게 된다고 한다
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
backend/src/main/java/moadong/user/entity/User.java (1)
45-46: 이전 리뷰 코멘트와 동일한 이슈입니다.이 필드에 대한
@NotNull검증 누락 문제는 이미 이전 리뷰에서 지적되었습니다.@Builder.Default를 추가하거나 빌더에서 null 체크를 추가해야 합니다.
📜 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/user/entity/User.java(3 hunks)
🔇 Additional comments (1)
backend/src/main/java/moadong/user/entity/User.java (1)
14-14: LGTM! Import가 Spring Data MongoDB와 일관되게 수정되었습니다.
jakarta.persistence.Id에서org.springframework.data.annotation.Id로의 변경은 이 파일이 이미 Spring Data MongoDB를 사용하고 있는 것(@Document,@Field등)과 일치합니다. 이는 일관성을 개선하는 좋은 변경입니다.
| public void updateClubId(String clubId) { | ||
| this.clubId = clubId; | ||
| } |
There was a problem hiding this comment.
입력 파라미터에 null 검증을 추가하세요.
clubId 필드가 @NotNull로 선언되어 있지만, updateClubId 메서드는 null 파라미터를 검증하지 않습니다. 이로 인해 제약 조건 위반이나 데이터 무결성 문제가 발생할 수 있습니다.
다음 diff를 적용하여 null 검증을 추가하세요:
public void updateClubId(String clubId) {
+ if (clubId == null) {
+ throw new IllegalArgumentException("clubId는 null일 수 없습니다");
+ }
this.clubId = clubId;
}또는 Java의 Objects.requireNonNull을 사용할 수도 있습니다:
+import java.util.Objects;
+
public void updateClubId(String clubId) {
+ this.clubId = Objects.requireNonNull(clubId, "clubId는 null일 수 없습니다");
- this.clubId = clubId;
}📝 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.
| public void updateClubId(String clubId) { | |
| this.clubId = clubId; | |
| } | |
| public void updateClubId(String clubId) { | |
| if (clubId == null) { | |
| throw new IllegalArgumentException("clubId는 null일 수 없습니다"); | |
| } | |
| this.clubId = clubId; | |
| } |
| public void updateClubId(String clubId) { | |
| this.clubId = clubId; | |
| } | |
| import java.util.Objects; | |
| public void updateClubId(String clubId) { | |
| this.clubId = Objects.requireNonNull(clubId, "clubId는 null일 수 없습니다"); | |
| } |
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/user/entity/User.java around lines 87 to 89,
the updateClubId method lacks null validation even though clubId is annotated
@NotNull; add a null check (e.g., Objects.requireNonNull(clubId, "clubId must
not be null") or if (clubId == null) throw new IllegalArgumentException("clubId
must not be null")) before assigning to this.clubId to enforce the contract and
preserve data integrity.
- save를 insert로 변경 : 신규 생성
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
backend/src/main/java/moadong/club/entity/Club.java (1)
63-71: 중복 초기화 제거를 제안드립니다.
Club(String userId)생성자에서 이미 동일한 초기화 작업과userId세팅을 하고 있으니, 이번 생성자에서 재사용하면 중복을 줄일 수 있습니다. 아래처럼 위임하면 유지보수성이 좋아집니다.- public Club(String id, String userId) { - this.id = id; - this.name = ""; - this.category = ""; - this.division = ""; - this.state = ClubState.UNAVAILABLE; - this.clubRecruitmentInformation = ClubRecruitmentInformation.builder().build(); - this.userId = userId; - } + public Club(String id, String userId) { + this(userId); + this.id = id; + }
📜 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 (3)
backend/src/main/java/moadong/club/entity/Club.java(1 hunks)backend/src/main/java/moadong/user/entity/User.java(3 hunks)backend/src/main/java/moadong/user/service/UserCommandService.java(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- backend/src/main/java/moadong/user/entity/User.java
🧰 Additional context used
🧬 Code graph analysis (1)
backend/src/main/java/moadong/club/entity/Club.java (1)
frontend/src/types/club.ts (1)
Club(3-12)
🔇 Additional comments (1)
backend/src/main/java/moadong/user/service/UserCommandService.java (1)
46-55: 몽고DB 트랜잭션 지원 여부 확인 필요
@Transactional로 다문서 트랜잭션을 기대하신다면, MongoDB가 replica set 구성이고 애플리케이션에MongoTransactionManager가 등록되어 있어야 합니다. 환경이 이를 만족하지 않으면 런타임에 트랜잭션 시작 단계에서 예외가 발생할 수 있으니 한번 확인 부탁드립니다.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (2)
backend/src/main/java/moadong/user/entity/User.java (2)
45-46: @NotNull 필드에 @Builder.Default를 추가하세요.
clubId필드가@NotNull로 선언되었지만@Builder.Default가 없어, 빌더 패턴 사용 시 null이 전달될 수 있습니다. 이는 데이터 무결성 문제를 일으킬 수 있습니다.다음을 적용하여 기본값을 설정하세요:
@NotNull +@Builder.Default -private String clubId; +private String clubId = "";
91-93: 입력 파라미터에 null 검증을 추가하세요.
clubId필드가@NotNull로 선언되어 있지만,updateClubId메서드는 null 파라미터를 검증하지 않습니다. 이로 인해 제약 조건 위반이나 데이터 무결성 문제가 발생할 수 있습니다.다음을 적용하여 null 검증을 추가하세요:
+import java.util.Objects; + public void updateClubId(String clubId) { + this.clubId = Objects.requireNonNull(clubId, "clubId는 null일 수 없습니다"); - this.clubId = clubId; }
📜 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 (3)
backend/src/main/java/moadong/club/entity/Club.java(1 hunks)backend/src/main/java/moadong/user/entity/User.java(3 hunks)backend/src/main/java/moadong/user/service/UserCommandService.java(4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
backend/src/main/java/moadong/club/entity/Club.java (1)
frontend/src/types/club.ts (1)
Club(3-12)
🔇 Additional comments (5)
backend/src/main/java/moadong/club/entity/Club.java (1)
63-71: 새 생성자가 올바르게 구현되었습니다.새로 추가된
Club(String id, String userId)생성자는 기존 생성자들과 일관된 패턴으로 구현되어 있으며, 모든 필수 필드를 적절히 초기화합니다. UserCommandService의 새로운 ID 생성 플로우를 지원합니다.backend/src/main/java/moadong/user/entity/User.java (2)
14-14: MongoDB 마이그레이션을 위한 올바른 import 변경입니다.
jakarta.persistence.Id에서org.springframework.data.annotation.Id로의 변경은 JPA에서 Spring Data MongoDB로의 전환을 올바르게 반영합니다.
79-81: ID 설정 메서드가 올바르게 구현되었습니다.
updateId메서드는 UserCommandService의 새로운 ID 생성 플로우를 지원하기 위해 적절히 추가되었습니다.backend/src/main/java/moadong/user/service/UserCommandService.java (2)
167-176: 새로운 User 및 Club 생성 플로우가 올바르게 구현되었습니다.ObjectId를 사용한 ID 생성과
createUser,createClub헬퍼 메서드를 통한 리팩토링이 적절합니다. User와 Club의 연관 관계가 명확하게 설정됩니다.
48-59: Club 생성 실패 시 User 저장도 롤백되도록 트랜잭션 설정 확인 필요
MongoDB 트랜잭션 활성화 및@Transactional적용이 요구됩니다.
- application.yml/.properties에
replica-set(또는replicaSet) 설정 존재 여부MongoTransactionManager빈 등록 여부수동으로 설정을 검증해 주세요.
| import jakarta.servlet.http.HttpServletResponse; | ||
| import java.util.Date; | ||
|
|
||
| import jakarta.transaction.Transactional; |
There was a problem hiding this comment.
트랜잭션 어노테이션을 Spring의 @transactional로 변경하세요.
jakarta.transaction.Transactional을 사용하고 있지만, Spring Data MongoDB와 함께 사용하려면 별도의 JTA 설정이 필요합니다. Spring의 @Transactional을 사용하는 것이 더 적합합니다.
다음을 적용하세요:
-import jakarta.transaction.Transactional;
+import org.springframework.transaction.annotation.Transactional;Also applies to: 46-46
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/user/service/UserCommandService.java around
lines 7 and 46, replace the import and usages of
jakarta.transaction.Transactional with Spring's
org.springframework.transaction.annotation.Transactional; update the import
statement at line 7 to org.springframework.transaction.annotation.Transactional
and ensure any method or class-level @Transactional annotations use the Spring
one (adjust imports and remove the jakarta import) so Spring Data MongoDB
transaction semantics are used without requiring JTA configuration.
lepitaaar
left a comment
There was a problem hiding this comment.
path variable 삭제 좋습니다 수고하셨어요
#️⃣연관된 이슈
#778
📝작업 내용
중점적으로 리뷰받고 싶은 부분(선택)
기존에는 userRepository.save() 호출 후 MongoDB에서 자동 생성된 user의 _id를 이용해 Club을 생성하고, 다시 User를 갱신해야 했습니다.
→ 결과적으로 userRepository.save()가 두 번 호출되는 구조였습니다.
이번 수정에서는 서버에서 ObjectId를 사전에 생성하여
User와 Club 모두 동일한 흐름 안에서 한 번씩만 저장되도록 개선했습니다.
논의하고 싶은 부분(선택)
🫡 참고사항
Summary by CodeRabbit