Skip to content

[Release] BE v1.0.6 배포#675

Merged
lepitaaar merged 10 commits intomainfrom
develop/be
Aug 19, 2025
Merged

[Release] BE v1.0.6 배포#675
lepitaaar merged 10 commits intomainfrom
develop/be

Conversation

@Zepelown
Copy link
Member

@Zepelown Zepelown commented Aug 18, 2025

#️⃣연관된 이슈

📝작업 내용

  • 동아리 상세 페이지에 동아리 추천 기능 추가
  • 지원서 요약 API에 메모 필드 추가

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

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

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

🫡 참고사항

Summary by CodeRabbit

  • New Features
    • 클럽 상세 화면에 추천 클럽 노출(동일 카테고리 우선, 최대 6개, 중복 제거 및 모집중 우선).
    • 지원자 목록 응답에 메모 필드 추가로 정보 확인성 향상.
  • Changes
    • 지원 상태 단계 간소화(SUBMITTED/INTERVIEW_SCHEDULED/ACCEPTED/DECLINED)로 대시보드·집계 기준이 조정되었습니다.
  • Documentation
    • 지원서 수정/삭제 API의 한글 설명 문구를 정정하고 appId(지원서 아이디) 설명을 추가했습니다.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 18, 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 문서 문구를 수정하고, ApplicationStatus enum을 대폭 축소했습니다. 지원자 DTO에 memo 필드를 추가했습니다. 클럽 상세 DTO에 추천 클럽 리스트를 포함하도록 확장하고, ClubSearchRepository에 추천 검색 로직을 추가했으며, ClubProfileService에서 이를 사용하도록 연계했습니다. 상태 집계 로직을 단순화했습니다.

Changes

Cohort / File(s) Summary of Changes
API 문서 정정
backend/src/main/java/moadong/club/controller/ClubApplyController.java
PUT/DELETE /apply/{appId}의 Swagger 설명에서 오타 수정(“자원자”→“지원자”), “appId - 지원서 아이디” 문구 추가. 코드 로직 변경 없음.
지원 상태 체계 축소
backend/src/main/java/moadong/club/enums/ApplicationStatus.java
다수 상태 제거(DRAFT, SCREENING 등) 후 SUBMITTED, INTERVIEW_SCHEDULED, ACCEPTED, DECLINED만 유지. 상수 순서 변경 및 주석 수정.
지원자 DTO 확장
backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java
record에 memo(String) 필드 추가로 시그니처 변경. of(...)에서 application.getMemo() 매핑 추가.
클럽 상세 DTO 확장 및 연계
backend/src/main/java/moadong/club/payload/dto/ClubDetailedResult.java, backend/src/main/java/moadong/club/service/ClubProfileService.java
ClubDetailedResult에 List<ClubSearchResult> recommendClubs 추가. of(Club) → of(Club, List)로 변경. ClubProfileService가 ClubSearchRepository로 추천 클럽 조회 후 DTO에 주입.
추천 클럽 검색 추가
backend/src/main/java/moadong/club/repository/ClubSearchRepository.java
public List<ClubSearchResult> searchRecommendClubs(String category, String excludeClubId) 추가. 동일 카테고리/모집중 우선→카테고리 보강→랜덤 풀에서 모집상태 우선 선별하는 3단계 파이프라인과 중복 배제 헬퍼들 추가.
상태 집계 로직 단순화
backend/src/main/java/moadong/club/service/ClubApplyService.java
getClubApplyInfo의 상태 스위치 단순화: SUBMITTED만 검토대상, INTERVIEW_SCHEDULED만 인터뷰 예정, ACCEPTED만 합격으로 카운트. 제거된 상태 반영.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant ClubProfileService
  participant ClubSearchRepository
  participant DB
  participant DTO as ClubDetailedResult

  Client->>ClubProfileService: getClubDetail(clubId)
  ClubProfileService->>DB: find Club by clubId
  DB-->>ClubProfileService: Club
  ClubProfileService->>ClubSearchRepository: searchRecommendClubs(category, excludeClubId)
  ClubSearchRepository->>DB: fetch category & recruiting clubs
  DB-->>ClubSearchRepository: clubs subset
  ClubSearchRepository->>DB: fetch fallback/random pool
  DB-->>ClubSearchRepository: random pool
  ClubSearchRepository-->>ClubProfileService: List<ClubSearchResult>
  ClubProfileService->>DTO: of(club, recommendClubs)
  DTO-->>Client: ClubDetailedResult
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

✨ Feature, 📬 API, 💾 BE, 📈 release

Suggested reviewers

  • lepitaaar
  • PororoAndFriends
  • seongwon030

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch develop/be

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

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

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@vercel
Copy link

vercel bot commented Aug 18, 2025

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

Project Deployment Preview Comments Updated (UTC)
moadong Ready Ready Preview Comment Aug 18, 2025 9:59am

Copy link
Contributor

@lepitaaar lepitaaar left a comment

Choose a reason for hiding this comment

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

다들 수고하셨습니다

Copy link
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: 3

🧹 Nitpick comments (11)
backend/src/main/java/moadong/club/enums/ApplicationStatus.java (1)

7-7: 주석 표현 통일 제안: ‘불합’ → ‘불합격’

한국어 사용자 문맥상 ‘불합격’이 자연스럽습니다.

-    DECLINED,                  // 불합
+    DECLINED,                  // 불합격
backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java (1)

22-24: memo 필드 노출에 대한 NPE/민감정보 취급 점검

  • NPE/일관성: API 응답에서 memo가 null이 되지 않도록 빈 문자열로 normalize하는 것을 권장합니다.
  • 민감정보: memo가 심사 메모(개인식별/평가 코멘트 포함)라면 저장 시 암호화 또는 최소한 접근 제어 재확인 필요합니다. 현재 answers만 암복호 처리되고 memo는 평문으로 보입니다. 의도라면 OK, 아니라면 저장/조회 경로에 동일한 보호수단 적용을 검토해 주세요.

선호 시 아래처럼 null을 빈 문자열로 변환할 수 있습니다.

-                .memo(application.getMemo())
+                .memo(Optional.ofNullable(application.getMemo()).orElse(""))

추가로, Optional 사용을 위해 상단에 import가 필요합니다(변경 범위 밖 코드 참고).

import java.util.Optional;

원하시면 edit 경로(저장 시)에서도 memo 암호화를 포함한 일관 보호 로직을 제안드릴 수 있습니다.

Also applies to: 40-46

backend/src/main/java/moadong/club/service/ClubApplyService.java (1)

112-116: 상태 카운팅 축소 적용 OK. DECLINED 명시 여부만 판단해주세요

제품 의도대로 SUBMITTED/INTERVIEW_SCHEDULED/ACCEPTED만 카운팅하는 것으로 이해됩니다. 의사 표현을 위해 DECLINED에 대한 명시적 no-op case를 추가하면 코드 독해성이 약간 올라갑니다(동작 동일).

             switch (app.getStatus()) {
                 case SUBMITTED -> reviewRequired++;
                 case INTERVIEW_SCHEDULED -> scheduledInterview++;
                 case ACCEPTED -> accepted++;
+                case DECLINED -> { /* count 미포함(의도) */ }
             }

또한 과거 Enum 값이 DB에 남아있다면 본 루프에 도달하기 전 역직렬화에서 예외가 날 수 있습니다. Enum 축소에 대한 마이그레이션/컨버터 적용 여부를 위 파일 코멘트(Enums) 참고해 재확인 부탁드립니다.

backend/src/main/java/moadong/club/service/ClubProfileService.java (1)

55-59: 추천 목록 null/오류 내성 및 성능 고려(캐싱) 제안

  • null 내성: searchRecommendClubs가 null 대신 빈 리스트를 반환하도록 보장하거나, 호출부에서 방어로직을 두는 것을 권장합니다.
  • 성능: 카테고리+excludeClubId 조합 기준 캐싱(SPRING Cache 등)으로 상세 페이지 트래픽을 흡수할 수 있습니다. TTL 기반 캐시면 충분.

예시(선호 시):

-        List<ClubSearchResult> clubSearchResults = clubSearchRepository.searchRecommendClubs(club.getCategory(), clubId);
+        List<ClubSearchResult> clubSearchResults =
+                java.util.Optional.ofNullable(
+                        clubSearchRepository.searchRecommendClubs(club.getCategory(), clubId)
+                ).orElseGet(java.util.List::of);

Repository 측에서 non-null 반환을 계약으로 명시한다면 호출부 변경은 생략 가능합니다. 캐싱 적용 필요 여부는 평균 호출량/지연시간을 기준으로 결정하면 됩니다. 원하시면 Cache 설정 제안드립니다.

backend/src/main/java/moadong/club/payload/dto/ClubDetailedResult.java (3)

41-43: DateTimeFormatter 재생성 비용 제거 (상수화 권장)

메서드 호출 시마다 포매터를 생성할 필요가 없습니다. 상수로 올려 재사용하면 가독성과 성능이 모두 개선됩니다.

적용 예시:

- DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm");
- period = clubRecruitmentInformation.getRecruitmentStart().format(formatter) + " ~ "
-         + clubRecruitmentInformation.getRecruitmentEnd().format(formatter);
+ period = clubRecruitmentInformation.getRecruitmentStart().format(RECRUITMENT_PERIOD_FMT) + " ~ "
+         + clubRecruitmentInformation.getRecruitmentEnd().format(RECRUITMENT_PERIOD_FMT);

그리고 레코드 내부에 정적 상수를 추가해 주세요:

// 레코드 본문(필드 선언부 아래)에 추가
private static final DateTimeFormatter RECRUITMENT_PERIOD_FMT =
        DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm");

73-78: 중복 호출 제거 및 NPE 방지 여지 축소

이미 지역 변수 clubRecruitmentInformation을 보유하고 있으므로 동일 객체에 대한 게터를 반복 호출하지 않는 편이 안전하고 간결합니다.

- .externalApplicationUrl(club.getClubRecruitmentInformation().getExternalApplicationUrl() == null ? "" :
-         club.getClubRecruitmentInformation().getExternalApplicationUrl())
+ .externalApplicationUrl(
+         clubRecruitmentInformation == null || clubRecruitmentInformation.getExternalApplicationUrl() == null
+                 ? "" : clubRecruitmentInformation.getExternalApplicationUrl()
+ )
...
- .faqs(club.getClubRecruitmentInformation().getFaqs() == null ? List.of()
-         : club.getClubRecruitmentInformation().getFaqs())
+ .faqs(clubRecruitmentInformation == null || clubRecruitmentInformation.getFaqs() == null
+         ? List.of() : clubRecruitmentInformation.getFaqs())

79-79: recommendClubs null 안전 처리

프런트에서 배열을 기대한다면 null 대신 빈 리스트를 내려주는 편이 호환성이 높습니다.

- .recommendClubs(recommendClubs)
+ .recommendClubs(recommendClubs == null ? List.of() : recommendClubs)
backend/src/main/java/moadong/club/repository/ClubSearchRepository.java (4)

111-117: 추천에서 ‘모집중’의 정의 일치 여부 확인 (UPCOMING 포함 여부)

키워드 검색의 필터 로직(Line 206-215)에서는 OPEN 필터 시 ALWAYS/OPEN/UPCOMING을 모두 모집중으로 취급합니다. 반면 여기서는 ALWAYS/OPEN만 포함합니다. 의도일 수 있으나, 일관성 측면에서 확인이 필요합니다. 포함이 맞다면 다음과 같이 보완하세요.

 criteria = criteria.and("recruitmentInformation.clubRecruitmentStatus")
         .in(
                 ClubRecruitmentStatus.ALWAYS.toString(),
-                ClubRecruitmentStatus.OPEN.toString()
+                ClubRecruitmentStatus.OPEN.toString(),
+                ClubRecruitmentStatus.UPCOMING.toString()
         );

77-95: 매직 넘버 상수화로 튜닝 용이성 확보

maxCategoryCount=4, totalNeeded=6, 랜덤 풀 10 등은 후속 운영에서 쉽게 조정될 수 있도록 상수화하는 편이 좋습니다.

- int maxCategoryCount = 4;
+ int maxCategoryCount = RECOMMEND_CATEGORY_MAX;
...
- int totalNeeded = 6;
+ int totalNeeded = RECOMMEND_TOTAL;
...
- List<ClubSearchResult> randomPool = findRandomClubs(excludeIds, 10);
+ List<ClubSearchResult> randomPool = findRandomClubs(excludeIds, RANDOM_POOL_SIZE);

클래스 상단(필드 아래)에 상수를 추가해 주세요:

private static final int RECOMMEND_TOTAL = 6;
private static final int RECOMMEND_CATEGORY_MAX = 4;
private static final int RANDOM_POOL_SIZE = 10;

90-101: 반환 컬렉션 변경 가능성 관리

현재는 result가 비어있지 않으면 변경 가능한 리스트를 그대로 반환합니다. 외부에서 결과를 변형하는 것을 막고 싶다면 List.copyOf(result)로 불변 리스트를 반환하는 것도 고려해 볼만 합니다.

- return result.isEmpty() ? Collections.emptyList() : result;
+ return result.isEmpty() ? Collections.emptyList() : List.copyOf(result);

104-135: 쿼리 필드 인덱스 점검 제안

카테고리/상태/모집상태로 매칭 및 샘플링을 수행하므로, MongoDB 인덱스가 없다면 추천 질의가 느려질 수 있습니다. 다음 필드들에 대한 복합/단일 인덱스 구성이 적절한지 점검해 주세요: state, category, recruitmentInformation.clubRecruitmentStatus.

원하시면 인덱스 제안(SR/읽기 패턴 기준) 및 마이그레이션 스크립트 작성 도와드릴게요.

📜 Review details

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

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear 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 0b9327b and ff4c17c.

📒 Files selected for processing (7)
  • backend/src/main/java/moadong/club/controller/ClubApplyController.java (2 hunks)
  • backend/src/main/java/moadong/club/enums/ApplicationStatus.java (1 hunks)
  • backend/src/main/java/moadong/club/payload/dto/ClubApplicantsResult.java (2 hunks)
  • backend/src/main/java/moadong/club/payload/dto/ClubDetailedResult.java (1 hunks)
  • backend/src/main/java/moadong/club/repository/ClubSearchRepository.java (2 hunks)
  • backend/src/main/java/moadong/club/service/ClubApplyService.java (1 hunks)
  • backend/src/main/java/moadong/club/service/ClubProfileService.java (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-05-19T05:45:52.957Z
Learnt from: lepitaaar
PR: Moadong/moadong#406
File: backend/src/main/java/moadong/club/service/ClubApplyService.java:34-38
Timestamp: 2025-05-19T05:45:52.957Z
Learning: The code duplication between createClubApplication and editClubApplication methods in ClubApplyService.java is acknowledged but will be addressed in a future refactoring, as per the developer's plan.

Applied to files:

  • backend/src/main/java/moadong/club/service/ClubApplyService.java
🧬 Code Graph Analysis (1)
backend/src/main/java/moadong/club/payload/dto/ClubDetailedResult.java (1)
frontend/src/types/club.ts (1)
  • Club (3-12)
🔇 Additional comments (5)
backend/src/main/java/moadong/club/enums/ApplicationStatus.java (1)

3-8: ApplicationStatus enum 변경에 따른 호환성 점검 결과

  • 제거된 enum 값(DRAFT, SCREENING, …​)에 대한 코드·문자열 참조 없음
  • @Enumerated(EnumType.ORDINAL) 사용 사례 없음

권장 대응

  • JPA Entity 필드에 @Enumerated(EnumType.STRING) 명시
  • Mongo 저장 시 문자열 여부 확인
  • 기존 데이터 마이그레이션: 제거된 상태→신규 상태 매핑 (예: SCREENING→SUBMITTED 등)
  • 알 수 없는 문자열 기본값 매핑용 컨버터 추가 (Spring Data Mongo ReadConverter 등)

필요 시 Mongo 마이그레이션 스크립트 초안 제공 가능합니다.

backend/src/main/java/moadong/club/controller/ClubApplyController.java (1)

75-77: Swagger 문구 교정 및 파라미터 안내 추가 LGTM

‘클럽 지원자의 …’로의 교정과 appId 안내 문구 추가로 가독성이 좋아졌습니다. 필요 시 @parameter를 통해 PathVariable에 직접 설명을 붙이는 것도 고려 가능하나 현재도 충분히 명확합니다.

Also applies to: 90-92

backend/src/main/java/moadong/club/service/ClubProfileService.java (1)

26-28: 추천 검색 리포지토리 주입 및 사용 연계 방향성 좋습니다

의존성 주입과 서비스 경계 분리가 명확합니다. 해당 Repository가 빈으로 등록되어 있고 통합테스트에서 카테고리별 결과가 보장되는지만 확인되면 좋겠습니다.

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

37-44: null 검사 불필요 – clubRecruitmentInformation은 항상 non-null입니다
Club의 무인자 생성자에서 clubRecruitmentInformation = ClubRecruitmentInformation.builder().build()로 초기화되며, MongoDB 매핑 시에도 빈 객체가 유지되어 절대 null이 될 수 없습니다. 기존 코드대로 hasRecruitmentPeriod()를 바로 호출해도 NPE 우려가 없으므로 해당 null 가드 제안은 무시해 주세요.

Likely an incorrect or invalid review comment.

backend/src/main/java/moadong/club/repository/ClubSearchRepository.java (1)

68-101: 추천 검색 파이프라인 전반 설계는 명확합니다

  • 카테고리 기반(모집중 우선 → 마감 보충) 후 랜덤 풀에서 상태 우선 선별로 마무리하는 3단계 접근이 깔끔합니다.
  • 중복 방지를 excludeIds로 일관되게 처리한 점 좋습니다.

Comment on lines +104 to +121
private List<ClubSearchResult> findClubsByCategoryAndState(String category, Set<String> excludeIds,
boolean onlyRecruitAvailable, int limit) {
List<AggregationOperation> ops = new ArrayList<>();

Criteria criteria = Criteria.where("category").is(category)
.and("_id").nin(excludeIds);

if (onlyRecruitAvailable) {
criteria = criteria.and("recruitmentInformation.clubRecruitmentStatus")
.in(
ClubRecruitmentStatus.ALWAYS.toString(),
ClubRecruitmentStatus.OPEN.toString()
);
}

ops.add(Aggregation.match(criteria));
ops.add(Aggregation.sample((long) limit));

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

추천 조회에 state=AVAILABLE 필터가 누락되어 비공개/비활성 동아리 노출 위험

키워드 검색(searchClubsByKeyword)에서는 Line 31에서 state=AVAILABLE을 강제하지만, 추천 조회 경로에서는 해당 필터가 없습니다. 비활성(숨김) 클럽이 추천에 섞일 수 있습니다. 추천 노출 품질과 정책 측면에서 치명적일 수 있으니 필수 반영을 권장합니다.

- Criteria criteria = Criteria.where("category").is(category)
-         .and("_id").nin(excludeIds);
+ Criteria criteria = Criteria.where("category").is(category)
+         .and("_id").nin(excludeIds)
+         .and("state").is(ClubState.AVAILABLE.getName());
📝 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
private List<ClubSearchResult> findClubsByCategoryAndState(String category, Set<String> excludeIds,
boolean onlyRecruitAvailable, int limit) {
List<AggregationOperation> ops = new ArrayList<>();
Criteria criteria = Criteria.where("category").is(category)
.and("_id").nin(excludeIds);
if (onlyRecruitAvailable) {
criteria = criteria.and("recruitmentInformation.clubRecruitmentStatus")
.in(
ClubRecruitmentStatus.ALWAYS.toString(),
ClubRecruitmentStatus.OPEN.toString()
);
}
ops.add(Aggregation.match(criteria));
ops.add(Aggregation.sample((long) limit));
private List<ClubSearchResult> findClubsByCategoryAndState(String category, Set<String> excludeIds,
boolean onlyRecruitAvailable, int limit) {
List<AggregationOperation> ops = new ArrayList<>();
Criteria criteria = Criteria.where("category").is(category)
.and("_id").nin(excludeIds)
.and("state").is(ClubState.AVAILABLE.getName());
if (onlyRecruitAvailable) {
criteria = criteria.and("recruitmentInformation.clubRecruitmentStatus")
.in(
ClubRecruitmentStatus.ALWAYS.toString(),
ClubRecruitmentStatus.OPEN.toString()
);
}
ops.add(Aggregation.match(criteria));
ops.add(Aggregation.sample((long) limit));
// …rest of method…
}
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/club/repository/ClubSearchRepository.java
around lines 104 to 121, the aggregation criteria for recommended clubs lacks a
filter for state=AVAILABLE, so hidden/inactive clubs can be returned; update the
Criteria used before Aggregation.match to include a condition requiring the club
state to be AVAILABLE (use the same representation as other queries, e.g.
ClubState.AVAILABLE.toString() or the string literal "AVAILABLE"), then run the
aggregation; ensure the new criterion is combined with existing category,
exclusion and recruitment-status checks so only AVAILABLE clubs are sampled.

Comment on lines +129 to +130
.and(ConditionalOperators.ifNull("$recruitmentInformation.tags").then(Collections.emptyList()))
.as("tags")
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

tags 기본값 타입 일관성: 빈 리스트 유지 권장 (기존 메서드와 불일치)

여기서는 tags의 기본값을 Collections.emptyList()로 설정(좋음)하지만, searchClubsByKeyword에서는 빈 문자열을 기본값으로 내려보냅니다(Line 56-57). ClubSearchResult.tagsList<String>라면, 기존 메서드는 역직렬화/매핑 단계에서 타입 불일치 문제가 날 수 있습니다. 기존 메서드도 빈 리스트로 통일하는 것을 권장합니다.

기존 메서드 수정 예시(참고용):

// searchClubsByKeyword 의 project 단계에서
.and(ConditionalOperators.ifNull("$recruitmentInformation.tags").then(Collections.emptyList()))
.as("tags")

🏁 Script executed:

#!/bin/bash
set -e
# 검색 메서드 시그니처와 tags 처리 부분 확인
rg -n 'searchClubsByKeyword' -C5 backend/src/main/java/moadong/club/repository/ClubSearchRepository.java
rg -n 'ifNull' -C5 backend/src/main/java/moadong/club/repository/ClubSearchRepository.java

Length of output: 3526


🏁 Script executed:

#!/bin/bash
set -e
# ClubSearchResult 클래스 내부의 tags 필드 타입 확인
rg -n 'class ClubSearchResult' -C5 backend/src/main/java/moadong/club/repository/ClubSearchResult.java
rg -n 'tags' -C5 backend/src/main/java/moadong/club/repository/ClubSearchResult.java

Length of output: 221


🏁 Script executed:

#!/bin/bash
set -e
# ClubSearchResult 클래스 파일 경로 탐색
find backend/src/main/java -type f -name "*ClubSearchResult*.java"

Length of output: 146


🏁 Script executed:

#!/bin/bash
set -e
# ClubSearchResult 클래스의 tags 필드 선언부 확인
rg -n 'tags' -C5 backend/src/main/java/moadong/club/payload/dto/ClubSearchResult.java

Length of output: 387


searchClubsByKeyword에서 tags 기본값을 빈 리스트로 통일하세요

현재 searchClubsByKeyword 메서드에서는 tags의 null 대체값으로 빈 문자열("")을 사용하지만, 이후 유사 메서드에서는 Collections.emptyList()를 사용하고 있습니다. ClubSearchResult.tagsList<String> 타입이므로, 역직렬화 시 타입 불일치 문제가 발생할 수 있습니다.

수정 대상:

  • 파일: backend/src/main/java/moadong/club/repository/ClubSearchRepository.java
  • 54–57행(Aggregation.project 내부 tags 처리 부분)

변경 예시:

- .and(ConditionalOperators.ifNull("$recruitmentInformation.tags").then(""))
+ .and(ConditionalOperators.ifNull("$recruitmentInformation.tags").then(Collections.emptyList()))

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In backend/src/main/java/moadong/club/repository/ClubSearchRepository.java
around lines 129-130, the Aggregation.project step in searchClubsByKeyword sets
tags' null replacement to an empty string which mismatches ClubSearchResult.tags
(List<String>); change the ConditionalOperators.ifNull(...).then(...) call so it
returns Collections.emptyList() instead of "" (and add/import
java.util.Collections if missing) so tags deserialize as a List<String>.

Comment on lines +182 to +185
List<AggregationOperation> ops = new ArrayList<>();
ops.add(Aggregation.match(Criteria.where("_id").nin(excludeIds)));
ops.add(Aggregation.sample((long) sampleSize));

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

랜덤 풀 생성에도 state=AVAILABLE 조건 적용 필요

위와 동일한 이유로, 랜덤 풀 또한 비활성 클럽을 포함하지 않도록 필터링해야 합니다.

- ops.add(Aggregation.match(Criteria.where("_id").nin(excludeIds)));
+ ops.add(Aggregation.match(
+     Criteria.where("_id").nin(excludeIds)
+             .and("state").is(ClubState.AVAILABLE.getName())
+ ));
📝 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
List<AggregationOperation> ops = new ArrayList<>();
ops.add(Aggregation.match(Criteria.where("_id").nin(excludeIds)));
ops.add(Aggregation.sample((long) sampleSize));
List<AggregationOperation> ops = new ArrayList<>();
ops.add(Aggregation.match(
Criteria.where("_id").nin(excludeIds)
.and("state").is(ClubState.AVAILABLE.getName())
));
ops.add(Aggregation.sample((long) sampleSize));
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/club/repository/ClubSearchRepository.java
around lines 182 to 185, the aggregation that builds the random sample currently
only filters out excluded IDs and thus may include inactive clubs; modify the
match stage to also require state = AVAILABLE by combining the existing
Criteria.where("_id").nin(excludeIds) with a state check (e.g.,
Criteria.where("state").is(State.AVAILABLE) or .is("AVAILABLE") depending on the
enum/field type) so the sample pool excludes inactive clubs before the sample
operation.

@Zepelown Zepelown requested review from oesnuj and seongwon030 August 18, 2025 11:42
Copy link
Member

@seongwon030 seongwon030 left a comment

Choose a reason for hiding this comment

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

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments