Skip to content

[refactor] 지원서 api의 clubId path variable 삭제 및 관리자용 분리#780

Merged
alsdddk merged 5 commits intodevelop/befrom
refactor/#778-clubId-pathVariable-MOA-283
Oct 12, 2025
Merged

[refactor] 지원서 api의 clubId path variable 삭제 및 관리자용 분리#780
alsdddk merged 5 commits intodevelop/befrom
refactor/#778-clubId-pathVariable-MOA-283

Conversation

@alsdddk
Copy link
Collaborator

@alsdddk alsdddk commented Oct 10, 2025

#️⃣연관된 이슈

#778

📝작업 내용

ClubApplyController, ClubApplyService를 Public과 Admin으로 분리

  • ClubApplyAdminController에는 path에 clubId를 삭제하고, userDetails에서 clubId를 가져옵니다.
  • ClubApplyServiceV1과 ClubApplyControllerV1에는 이번 연동과정에서 포함되지 않는 api들이 지원되도록 합니다.
  • ClubApplyPublicController는 지원 시 동아리 정보가 필요하기에 여전히 path로 clubId를 받습니다.

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

기존에는 userRepository.save() 호출 후 MongoDB에서 자동 생성된 user의 _id를 이용해 Club을 생성하고, 다시 User를 갱신해야 했습니다.
→ 결과적으로 userRepository.save()가 두 번 호출되는 구조였습니다.

이번 수정에서는 서버에서 ObjectId를 사전에 생성하여
User와 Club 모두 동일한 흐름 안에서 한 번씩만 저장되도록 개선했습니다.

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

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

🫡 참고사항

Summary by CodeRabbit

  • 신기능
    • 클럽 지원서 공개 조회 및 지원 제출용 퍼블릭 API가 추가되었습니다.
  • 변경 사항
    • 관리자용 신청 관리 API가 관리자 전용 경로로 통합되어 클럽 식별자 입력 없이 관리자 권한으로 동작합니다.
    • 회원가입 시 내부적으로 클럽이 생성되어 계정에 연결됩니다.
  • 리팩터링
    • 공개/관리자 관련 서비스와 컨트롤러가 역할별로 재구성되어 엔드포인트가 정리되었습니다.
  • 테스트
    • 관리자용 서비스 테스트 이름과 의존성이 갱신되었습니다.

@vercel
Copy link

vercel bot commented Oct 10, 2025

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

Project Deployment Preview Comments Updated (UTC)
moadong Ready Ready Preview Comment Oct 10, 2025 0:26am

@alsdddk alsdddk added 🔨 Refactor 코드 리팩토링 💾 BE Backend labels Oct 10, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 10, 2025

Warning

.coderabbit.yaml has a parsing error

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

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

Walkthrough

관리자용과 공용 API로 분리하고 관련 컨트롤러·서비스명을 리네임했으며, 관리자 API에서 경로 변수 clubId를 제거하고 CustomUserDetails.clubId로 조회하도록 변경했다. 공용 컨트롤러/서비스(V1 포함)와 사용자·회원가입(클럽 생성) 관련 필드가 추가·확장되었다.

Changes

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
UserCustomUserDetailsclubId 필드 추가 및 초기화. 회원가입 흐름에서 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 응답
Loading
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
Loading

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

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 ⚠️ Warning 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Oct 10, 2025

Test Results

70 tests   67 ✅  8s ⏱️
11 suites   3 💤
11 files     0 ❌

Results for commit ac6db67.

♻️ This comment has been updated with latest results.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 1eeea25 and f51bfb6.

📒 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.java
  • backend/src/main/java/moadong/club/service/ClubApplyPublicService.java
  • backend/src/main/java/moadong/club/service/ClubApplyAdminService.java
  • backend/src/main/java/moadong/club/controller/ClubApplyAdminController.java
  • backend/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 방어 로직 추가 고려

Comment on lines +45 to +46
@NotNull
private String clubId;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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

Suggested change
@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를 내게 된다고 한다
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ 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.

📥 Commits

Reviewing files that changed from the base of the PR and between f51bfb6 and 47cf1d6.

📒 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 등)과 일치합니다. 이는 일관성을 개선하는 좋은 변경입니다.

Comment on lines +87 to +89
public void updateClubId(String clubId) {
this.clubId = clubId;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

입력 파라미터에 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.

Suggested change
public void updateClubId(String clubId) {
this.clubId = clubId;
}
public void updateClubId(String clubId) {
if (clubId == null) {
throw new IllegalArgumentException("clubId는 null일 수 없습니다");
}
this.clubId = clubId;
}
Suggested change
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로 변경 : 신규 생성
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (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.

📥 Commits

Reviewing files that changed from the base of the PR and between 47cf1d6 and ed8fa95.

📒 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가 등록되어 있어야 합니다. 환경이 이를 만족하지 않으면 런타임에 트랜잭션 시작 단계에서 예외가 발생할 수 있으니 한번 확인 부탁드립니다.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ 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.

📥 Commits

Reviewing files that changed from the base of the PR and between 47cf1d6 and ac6db67.

📒 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;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

트랜잭션 어노테이션을 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.

Copy link
Member

@Zepelown Zepelown left a comment

Choose a reason for hiding this comment

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

고생하셨습니다

Copy link
Contributor

@lepitaaar lepitaaar left a comment

Choose a reason for hiding this comment

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

path variable 삭제 좋습니다 수고하셨어요

@alsdddk alsdddk merged commit fe1316b into develop/be Oct 12, 2025
5 checks passed
@alsdddk alsdddk deleted the refactor/#778-clubId-pathVariable-MOA-283 branch November 19, 2025 03:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💾 BE Backend 🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants