Skip to content

Comments

[refactor] club api 리팩토링#492

Merged
Due-IT merged 12 commits intodevelop/befrom
refactor/#471-club-api-MOA-19
Jun 10, 2025
Merged

[refactor] club api 리팩토링#492
Due-IT merged 12 commits intodevelop/befrom
refactor/#471-club-api-MOA-19

Conversation

@Due-IT
Copy link
Collaborator

@Due-IT Due-IT commented Jun 4, 2025

#️⃣연관된 이슈

📝작업 내용

API 단위별 작업

  • GET /api/club/search/

    • 각 파라미터에 뭘 넣을 수 있는지 볼 수 있으면 좋겠음. 아니면 Enum으로 변경하면 좋을듯
  • POST /api/club

    • 테스트용으로 두었던거라 없애도 될듯함.
  • PUT /api/club/description

    • id를 없애고 토큰으로 처리하는게 좋을듯 함
    • 기능상 문제 없음
  • PUT /api/club/info

    • 분류, 분과에 대한 제약이 필요
    • 핸드폰 번호 형식 검증 필요
    • 태그 개수 및 글자수 제한 검증 필요
    • inrtoduction 글자수 제한 검증 필요
    • 얘도 id 받을 필요 없을듯

클럽 정보 업데이트 로직 개선

  • ClubProfileService에서 클럽 생성 메서드를 제거 하였고, ClubProfileController와 ClubProfileServiceTest에 반영되었습니다.
  • Club.java에서 태그 개수 및 길이, 한 줄 소개 길이에 대한 유효성 검사가 추가되었습니다.
  • ClubInfoRequest는 이제 ClubCategory 및 ClubDivision 열거형을 직접 사용하여 유형 안정성을 높입니다.
    • ClubCategory와 ClubDivision에는 JSON에서 객체로 역직렬화시 없는 값을 선택한다면 api가 구체적인 예외메시지를 반환하도록 도록 구현되었습니다.

클럽 검색 기능 강화

  • ClubSearchController의 searchClubsByKeyword 엔드포인트 설명(Swagger)이 명확성을 위해 업데이트되었으며, recruitmentStatus, division, category와 같은 검색 매개변수에 대한 더 자세한 정보를 제공합니다.
  • JwtAuthenticationFilter는 이제 유효하지 않은 JWT 토큰을 감지할 시, 클라이언트에 명확한 오류 메시지를 제공합니다.

사소한 코드 정리

  • 여러 파일에서 불필요한 import 문과 사용되지 않는 코드가 제거되었습니다.
  • API 문서화를 개선하기 위해 Swagger 어노테이션의 @operation 설명이 보충되었습니다.

Summary by CodeRabbit

  • 신규 기능

    • 동아리 분과(ClubDivision) 선택 시, 올바르지 않은 값에 대한 에러 처리가 추가되었습니다.
    • 동아리 분류(ClubCategory) 선택 시, 올바르지 않은 값에 대한 에러 처리가 추가되었습니다.
    • 태그는 최대 3개, 각 태그는 최대 5글자, 소개는 최대 24글자까지 입력 가능하도록 제한 및 검증이 추가되었습니다.
    • 동아리 정보 입력 시 분과와 분류를 직접 선택할 수 있도록 변경되었습니다.
    • 동아리 검색 API 문서 설명이 필터링 조건과 검색 방식에 대해 더 명확하게 개선되었습니다.
  • 버그 수정

    • 토큰이 유효하지 않을 때 보다 명확한 에러 메시지와 함께 401 에러가 반환됩니다.
  • 기타

    • 동아리 생성 기능이 제거되었습니다.
    • 입력값 검증 및 에러 코드가 세분화되었습니다.
    • 동아리 정보 및 모집 정보 수정 시 권한 검증 로직이 간소화되었습니다.

@Due-IT Due-IT self-assigned this Jun 4, 2025
@Due-IT Due-IT added 🐞 Bug Something isn't working 🔨 Refactor 코드 리팩토링 💾 BE Backend labels Jun 4, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 4, 2025

"""

Walkthrough

이 변경사항은 클럽 생성 API의 제거, 클럽 정보 및 모집 정보 업데이트 요청에서 id 필드 제거, 클럽 분류와 분과를 Enum으로 변경, 태그·소개글 길이 및 개수 검증, 핸드폰 번호 형식 검증, 그리고 관련 예외 코드 추가 및 Swagger 문서 개선 등 클럽 관련 API 전반에 대한 리팩토링을 포함합니다.

Changes

파일/경로 그룹 변경 요약
.../controller/ClubProfileController.java
.../service/ClubProfileService.java
.../unit/club/ClubProfileServiceTest.java
클럽 생성(POST) API 및 관련 서비스, 테스트 메서드 완전 제거
.../payload/request/ClubInfoRequest.java
.../payload/request/ClubRecruitmentInfoUpdateRequest.java
id 필드 삭제, category/division을 Enum으로 변경, presidentPhoneNumber에 @phonenumber 추가
.../entity/Club.java update 메서드에 태그 개수/길이, 소개글 길이 검증 로직 및 예외 처리 추가, category/division을 Enum name으로 저장
.../enums/ClubCategory.java Json 직렬화/역직렬화 지원, from(String) 팩토리 메서드 및 예외 처리 추가
.../enums/ClubDivision.java ClubDivision Enum 신설, Json 직렬화/역직렬화, from(String) 메서드 및 예외 처리 추가
.../global/exception/ErrorCode.java 클럽 분과/분류/태그/소개글 관련 신규 에러코드 추가, TOKEN_INVALID 메시지 수정
.../controller/ClubSearchController.java Swagger 문서(검색 API) 설명 보강 및 Enum 값 명시, 코드/로직 변화 없음
.../global/util/JwtAuthenticationFilter.java 토큰 username 추출 시 RestApiException 발생 시 401 응답 및 JSON 에러 반환 로직 추가
.../global/exception/GlobalExceptionHandler.java 불필요한 import 제거 및 사소한 포매팅

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant JwtFilter
    participant ClubProfileService
    participant ClubRepository
    participant Club

    Client->>JwtFilter: API 요청 (PUT /api/club/info)
    JwtFilter->>JwtFilter: 토큰에서 username 추출 (예외 발생 시 401 반환)
    JwtFilter-->>Client: (성공 시) SecurityContext 설정
    Client->>ClubProfileService: updateClubInfo 요청
    ClubProfileService->>ClubRepository: findClubByUserId(userId)
    ClubRepository-->>ClubProfileService: Club 반환 or 예외
    ClubProfileService->>Club: update(ClubInfoRequest)
    Club->>Club: validateTags, validateIntroduction 등 검증
    Club-->>ClubProfileService: 업데이트 성공 or 예외
    ClubProfileService-->>Client: 응답 반환
Loading

Assessment against linked issues

Objective Addressed Explanation
클럽 생성(POST) API 제거 (MOA-19)
클럽 정보/모집 정보 업데이트에서 id 파라미터 제거 및 토큰 기반 처리 (MOA-19)
클럽 분류(category), 분과(division) Enum 적용 및 유효성 검증 (MOA-19)
클럽 정보 업데이트 시 핸드폰 번호 형식 검증 (MOA-19)
태그 개수/글자수, 소개글 길이 제한 검증 및 관련 에러코드 추가 (MOA-19)

Assessment against linked issues: Out-of-scope changes

(해당 사항 없음)

Possibly related issues

Possibly related PRs

  • [release] 모아동 BE ver 1.0.2 #329: 기존 ClubController 및 createClub 엔드포인트 제거와 이어지는 리팩토링 작업으로 내용이 밀접하게 연결되어 있습니다.

Suggested labels

📬 API

Suggested reviewers

  • Zepelown
  • PororoAndFriends
    """

📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6c6df34 and c739137.

📒 Files selected for processing (4)
  • backend/src/main/java/moadong/club/entity/Club.java (2 hunks)
  • backend/src/main/java/moadong/club/service/ClubProfileService.java (1 hunks)
  • backend/src/test/java/moadong/fixture/ClubRequestFixture.java (2 hunks)
  • backend/src/test/java/moadong/unit/club/ClubProfileServiceTest.java (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • backend/src/test/java/moadong/fixture/ClubRequestFixture.java
🚧 Files skipped from review as they are similar to previous changes (3)
  • backend/src/main/java/moadong/club/entity/Club.java
  • backend/src/main/java/moadong/club/service/ClubProfileService.java
  • backend/src/test/java/moadong/unit/club/ClubProfileServiceTest.java
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: test
✨ Finishing Touches
  • 📝 Generate Docstrings

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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • 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

Documentation and Community

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

@github-actions
Copy link

github-actions bot commented Jun 4, 2025

Test Results

76 tests   76 ✅  2s ⏱️
12 suites   0 💤
12 files     0 ❌

Results for commit c739137.

♻️ This comment has been updated with latest results.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors the club API by replacing raw strings with enums for category/division, enhancing validation logic, and improving error handling and documentation.

  • Switched category/division fields to use enums with JSON deserialization and custom error codes
  • Added tag/introduction length checks in Club entity and improved JWT filter to return JSON errors
  • Removed obsolete club creation endpoint and related tests, cleaned up imports

Reviewed Changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ClubProfileServiceTest.java Removed outdated createClub unit test
JwtAuthenticationFilter.java Catch invalid JWT, return structured JSON error
GlobalExceptionHandler.java Removed unused imports
ErrorCode.java Added new codes for division, category, tags, intro
ClubProfileService.java Deleted createClub, updated update methods
ClubRecruitmentInfoUpdateRequest.java Removed id field
ClubInfoRequest.java Replaced String category/division with enums, added @PhoneNumber
ClubDivision.java & ClubCategory.java Added @JsonCreator for enum deserialization
Club.java Enforced tag and introduction length constraints
ClubSearchController.java Expanded Swagger descriptions, imported enum
ClubProfileController.java Removed POST /api/club creation endpoint
Comments suppressed due to low confidence (3)

backend/src/main/java/moadong/club/service/ClubProfileService.java:24

  • Using findClubByUserId and throwing CLUB_NOT_FOUND for unauthorized access conflates 404 Not Found and 403 Forbidden; consider distinguishing permission errors by returning USER_UNAUTHORIZED when the club exists but the user lacks rights.
Club club = clubRepository.findClubByUserId(user.getId())

backend/src/main/java/moadong/club/controller/ClubSearchController.java:33

  • [nitpick] Missing <br> or punctuation between the keyword description and the next line; the concatenated string runs two sentences together. Add a line break or separator for clarity.
+            + "keyword는 대소문자 구분 없이 자유롭게 검색"

backend/src/main/java/moadong/club/controller/ClubSearchController.java:39

  • Imported ClubRecruitmentStatus enum but still using String for the parameter. Consider changing the parameter type to ClubRecruitmentStatus to leverage automatic validation and clearer API contract.
@RequestParam(value = "recruitmentStatus", required = false, defaultValue = "all") String recruitmentStatus,

Response errorResponse = new Response(e.getErrorCode().getCode(),
e.getErrorCode().getMessage(), null);

ObjectMapper objectMapper = new ObjectMapper();
Copy link

Copilot AI Jun 4, 2025

Choose a reason for hiding this comment

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

Instantiating ObjectMapper on each request can be costly; consider injecting a singleton ObjectMapper bean or reusing a static instance to improve performance.

Suggested change
ObjectMapper objectMapper = new ObjectMapper();

Copilot uses AI. Check for mistakes.
this.clubRecruitmentInformation.update(request);
}

private void validateTags(List<String> tags) {
Copy link

Copilot AI Jun 4, 2025

Choose a reason for hiding this comment

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

No null check on tags before calling tags.size(); this could cause an NPE if the request omits tags. Consider annotating tags as @NotNull or adding a null guard.

Suggested change
private void validateTags(List<String> tags) {
private void validateTags(List<String> tags) {
if (tags == null) {
throw new RestApiException(ErrorCode.NULL_TAGS);
}

Copilot uses AI. Check for mistakes.
}
}

private void validateIntroduction(String introduction) {
Copy link

Copilot AI Jun 4, 2025

Choose a reason for hiding this comment

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

No null check on introduction before checking its length; this may lead to an NPE if introduction is null. Consider annotating or guarding against null.

Suggested change
private void validateIntroduction(String introduction) {
private void validateIntroduction(String introduction) {
if (introduction == null) {
throw new RestApiException(ErrorCode.NULL_INTRODUCTION);
}

Copilot uses AI. Check for mistakes.
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: 5

🧹 Nitpick comments (5)
backend/src/main/java/moadong/club/payload/request/ClubRecruitmentInfoUpdateRequest.java (1)

5-9: 필드 검증 추가를 고려해보세요.

현재 요청 객체에 validation 어노테이션이 없어 잘못된 데이터가 입력될 수 있습니다. 특히 recruitmentStartrecruitmentEnd의 날짜 순서 검증, recruitmentTargetdescription의 길이 제한 등을 고려해보세요.

public record ClubRecruitmentInfoUpdateRequest(
+    @NotNull @Future
    LocalDateTime recruitmentStart,
+    @NotNull @Future
    LocalDateTime recruitmentEnd,
+    @NotBlank @Size(max = 100)
    String recruitmentTarget,
+    @NotBlank @Size(max = 500)
    String description
) {
backend/src/main/java/moadong/club/enums/ClubDivision.java (2)

21-35: 메서드 일관성 개선을 고려해보세요.

fromStringfrom 메서드가 비슷한 기능을 하지만 동작이 다릅니다. fromString은 대소문자를 구분하지 않고 null을 반환하지만, from은 대문자 변환 후 예외를 던집니다. 일관성 있는 동작을 위해 통일을 고려해보세요.

public static ClubDivision fromString(String division) {
    return Arrays.stream(values())
-        .filter(rs -> rs.name().equalsIgnoreCase(division))
+        .filter(rs -> rs.name().equals(division))
        .findFirst()
        .orElse(null);
}

@JsonCreator
public static ClubDivision from(String value) {
    try {
-        return ClubDivision.valueOf(value.toUpperCase());
+        return ClubDivision.valueOf(value);
    } catch (IllegalArgumentException e) {
        throw new RestApiException(ErrorCode.CLUB_DIVISION_INVALID);
    }
}

12-13: 단일 enum 상수의 확장성을 고려해보세요.

현재 중동 하나의 상수만 정의되어 있습니다. 향후 다른 분과가 추가될 가능성이 있다면 enum 설계 시 확장성을 고려하는 것이 좋겠습니다.

backend/src/main/java/moadong/club/controller/ClubSearchController.java (2)

6-6: 사용하지 않는 import 제거 필요

ClubRecruitmentStatus import가 추가되었지만 해당 클래스에서 실제로 사용되지 않습니다.

-import moadong.club.enums.ClubRecruitmentStatus;

6-6: 사용되지 않는 import를 제거하세요.

ClubRecruitmentStatus가 import되었지만 실제로 사용되지 않습니다.

-import moadong.club.enums.ClubRecruitmentStatus;
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between b7b2aad and 6c6df34.

📒 Files selected for processing (12)
  • backend/src/main/java/moadong/club/controller/ClubProfileController.java (4 hunks)
  • backend/src/main/java/moadong/club/controller/ClubSearchController.java (2 hunks)
  • backend/src/main/java/moadong/club/entity/Club.java (2 hunks)
  • backend/src/main/java/moadong/club/enums/ClubCategory.java (2 hunks)
  • backend/src/main/java/moadong/club/enums/ClubDivision.java (1 hunks)
  • backend/src/main/java/moadong/club/payload/request/ClubInfoRequest.java (1 hunks)
  • backend/src/main/java/moadong/club/payload/request/ClubRecruitmentInfoUpdateRequest.java (1 hunks)
  • backend/src/main/java/moadong/club/service/ClubProfileService.java (1 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/main/java/moadong/global/util/JwtAuthenticationFilter.java (4 hunks)
  • backend/src/test/java/moadong/unit/club/ClubProfileServiceTest.java (0 hunks)
💤 Files with no reviewable changes (1)
  • backend/src/test/java/moadong/unit/club/ClubProfileServiceTest.java
🧰 Additional context used
🧠 Learnings (1)
backend/src/main/java/moadong/club/controller/ClubSearchController.java (1)
Learnt from: Due-IT
PR: Moadong/moadong#329
File: backend/src/main/java/moadong/club/controller/ClubSearchController.java:0-0
Timestamp: 2025-05-01T08:32:09.398Z
Learning: ClubSearchController의 searchClubsByKeyword 메서드와 ClubSearchService의 searchClubsByKeyword 메서드 사이에 파라미터 순서 일치가 중요하다. 현재 컨트롤러의 매개변수 순서는 'keyword, recruitmentStatus, category, division'인 반면, 서비스 메서드의 순서는 'keyword, recruitmentStatus, division, category'이다. 컨트롤러에서 서비스 호출 시 'keyword, recruitmentStatus, division, category' 순서로 전달하면 category와 division 값이 바뀌어 검색 결과가 잘못될 수 있다.
🧬 Code Graph Analysis (1)
backend/src/main/java/moadong/club/controller/ClubProfileController.java (1)
backend/src/main/java/moadong/club/controller/ClubSearchController.java (1)
  • RestController (18-55)
🔇 Additional comments (25)
backend/src/main/java/moadong/global/exception/GlobalExceptionHandler.java (1)

11-21: 코드 정리가 잘 되었습니다.

불필요한 import 제거와 포맷팅 개선으로 코드가 더 깔끔해졌습니다.

backend/src/main/java/moadong/club/controller/ClubProfileController.java (2)

50-53: Swagger 문서 개선이 좋습니다.

태그 개수 제한(최대 2개)과 글자 수 제한(태그 5글자, 소개 24글자)에 대한 명확한 설명이 추가되어 API 사용성이 향상되었습니다.


19-24: 클럽 생성 기능 제거가 적절히 반영되었습니다.

불필요한 import들이 정리되고 POST 매핑이 제거되어 코드가 더 명확해졌습니다. 남은 엔드포인트들만으로 클럽 프로필 관리 기능이 충분히 제공됩니다.

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

24-25: 리팩토링이 잘 되었습니다!

사용자 ID를 통한 직접 조회 방식으로 변경하여 코드가 더 간결하고 명확해졌습니다. 사용자가 자신의 클럽만 수정할 수 있도록 보장하는 방식도 적절합니다.

Also applies to: 33-34

backend/src/main/java/moadong/club/controller/ClubSearchController.java (4)

28-36: API 문서 개선 승인

Swagger 문서가 상세하고 명확하게 개선되어 API 사용성이 향상되었습니다. 필터링 로직과 검색 방식에 대한 설명이 잘 정리되어 있습니다.


44-49:

Details

✅ Verification successful

서비스 메서드 파라미터 순서 검증 필요

이전 리뷰에서 지적된 컨트롤러와 서비스 메서드 간 파라미터 순서 불일치 문제가 해결되었는지 확인이 필요합니다. 현재 호출 순서는 keyword, recruitmentStatus, division, category입니다.

다음 스크립트로 서비스 메서드의 파라미터 순서를 확인해주세요:


🏁 Script executed:

#!/bin/bash
# ClubSearchService의 searchClubsByKeyword 메서드 시그니처 확인
ast-grep --pattern 'searchClubsByKeyword($$$) {
  $$$
}'

Length of output: 58


아래 스크립트로 ClubSearchServicesearchClubsByKeyword 시그니처를 다시 확인해주세요:


🏁 Script executed:

#!/bin/bash
rg -n -A3 "searchClubsByKeyword" backend/src/main/java/moadong/club/service/ClubSearchService.java

Length of output: 573


파라미터 순서 일치 확인됨

컨트롤러 호출(keyword, recruitmentStatus, division, category)과 서비스 메서드 시그니처가 완전히 일치하므로 추가 검증이나 수정이 필요 없습니다.


28-36: Swagger 문서 개선이 훌륭합니다.

API 문서가 더욱 상세하고 명확해졌습니다. 파라미터별 설명과 사용 가능한 값들이 잘 정리되어 있습니다.


44-49:

Details

✅ Verification successful

서비스 호출 시 파라미터 순서를 검증해주세요.

기존 학습 내용에 따르면 컨트롤러와 서비스 메서드 간 파라미터 순서 불일치 문제가 있었습니다. 현재 서비스 호출에서 category와 division 파라미터 순서가 올바른지 확인이 필요합니다.


🏁 Script executed:

#!/bin/bash
# Description: ClubSearchService의 searchClubsByKeyword 메서드 시그니처 확인
# Expected: 파라미터 순서가 keyword, recruitmentStatus, division, category인지 확인

# ClubSearchService의 searchClubsByKeyword 메서드 시그니처 찾기
ast-grep --pattern $'public $_ searchClubsByKeyword($$$) {
  $$$
}'

Length of output: 8196


파라미터 순서 일치 확인 완료: 추가 조치 불필요

컨트롤러(backend/src/main/java/moadong/club/controller/ClubSearchController.java 44–49행)에서 호출하는
searchClubsByKeyword(keyword, recruitmentStatus, division, category) 순서가
서비스 시그니처(String keyword, String recruitmentStatus, String division, String category)와 완전히 일치함을 확인했습니다.

backend/src/main/java/moadong/club/payload/request/ClubInfoRequest.java (6)

6-8: 필요한 import 추가 승인

새로운 enum 타입과 유효성 검증 어노테이션을 위한 import가 적절히 추가되었습니다.


13-14: 타입 안전성 개선 승인

categorydivision 필드를 String에서 enum 타입으로 변경한 것은 타입 안전성을 크게 향상시키는 우수한 개선사항입니다. 이는 잘못된 값 입력을 컴파일 시점에 방지할 수 있습니다.


18-18: 전화번호 유효성 검증 추가 승인

@PhoneNumber 어노테이션 추가로 전화번호 형식 검증이 강화되어 데이터 무결성이 향상되었습니다.


6-8: enum 기반 타입 안전성 개선이 훌륭합니다.

새로운 import들이 타입 안전성과 검증 강화를 위해 적절히 추가되었습니다.


13-14: enum 타입 변경으로 타입 안전성이 향상되었습니다.

String에서 ClubCategory와 ClubDivision enum으로 변경하면서 컴파일 타임 타입 안전성이 확보되었고, @notblank 제거도 적절합니다. enum은 기본적으로 null 값을 허용하지 않으며, JSON 역직렬화 시 enum 레벨에서 유효성 검사가 수행됩니다.


18-18: 전화번호 형식 검증 강화가 우수합니다.

@phonenumber 어노테이션 추가로 전화번호 형식 검증이 강화되었습니다.

backend/src/main/java/moadong/global/exception/ErrorCode.java (4)

13-17: 새로운 유효성 검증 에러 코드 추가 승인

클럽 정보 유효성 검증을 위한 새로운 에러 코드들이 적절히 추가되었습니다. 에러 메시지가 명확하고 사용자 친화적이며, HTTP 상태 코드도 적절합니다.


33-33: 토큰 에러 메시지 한국어 개선 승인

토큰 관련 에러 메시지가 한국어로 개선되어 일관성이 향상되었습니다.


13-17: 클럽 검증을 위한 포괄적인 에러 코드 추가가 우수합니다.

새로 추가된 에러 코드들이 클럽 검증 로직을 충분히 커버하고 있습니다:

  • enum 타입 검증 (CLUB_DIVISION_INVALID, CLUB_CATEGORY_INVALID)
  • 태그 검증 (TOO_MANY_TAGS, TOO_LONG_TAG)
  • 소개글 검증 (TOO_LONG_INTRODUCTION)

모든 에러 코드가 적절한 HTTP 상태 코드(BAD_REQUEST)와 명확한 한국어 메시지를 가지고 있습니다.


33-33: 토큰 에러 메시지 개선이 좋습니다.

"유효하지 않은 토큰입니다." 메시지가 더욱 명확하고 사용자 친화적입니다.

backend/src/main/java/moadong/club/entity/Club.java (7)

17-18: 예외 처리를 위한 import 추가 승인

새로운 유효성 검증 로직을 위한 예외 처리 관련 import가 적절히 추가되었습니다.


80-82: 유효성 검증 로직 추가 승인

업데이트 전에 태그와 소개글에 대한 유효성 검증을 수행하는 것은 데이터 무결성을 보장하는 우수한 방법입니다.


84-85: enum 사용 방식 개선 승인

enum의 .name() 메서드를 사용하여 문자열 값을 할당하는 방식이 올바르게 구현되었습니다.


91-107: 유효성 검증 메서드 구현 승인

태그와 소개글에 대한 유효성 검증 로직이 명확하고 올바르게 구현되었습니다. 검증 실패 시 적절한 에러 코드와 함께 예외를 발생시키는 방식이 좋습니다.


17-18: 검증 로직을 위한 적절한 import 추가입니다.

ErrorCode와 RestApiException import가 새로운 검증 메서드에서 사용되기 위해 적절히 추가되었습니다.


80-81: 검증 메서드 호출이 적절히 배치되었습니다.

업데이트 로직 시작 부분에서 검증을 수행하는 것이 좋은 패턴입니다.


84-85: enum의 name() 메서드 사용이 적절합니다.

ClubCategory와 ClubDivision enum의 name() 메서드를 사용하여 String 필드에 할당하는 방식이 타입 안전성을 유지하면서도 기존 DB 구조와 호환됩니다.

Comment on lines +49 to +50
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(errorResponse);
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

ObjectMapper 인스턴스를 재사용하여 성능을 개선하세요.

ObjectMapper 인스턴스를 매번 생성하는 것은 비효율적입니다. ObjectMapper는 스레드 세이프하므로 클래스 레벨에서 한 번만 생성하여 재사용할 수 있습니다.

클래스 레벨에 ObjectMapper를 선언하세요:

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
+    private static final ObjectMapper objectMapper = new ObjectMapper();

    private final JwtProvider jwtProvider;
    private final UserDetailsService userDetailsService;

그리고 메서드 내에서 재사용하세요:

-                ObjectMapper objectMapper = new ObjectMapper();
                 String json = objectMapper.writeValueAsString(errorResponse);
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/global/util/JwtAuthenticationFilter.java around
lines 49 to 50, the ObjectMapper instance is created inside the method which is
inefficient. To fix this, declare a private static final ObjectMapper instance
at the class level and reuse this instance inside the method instead of creating
a new one each time.

Comment on lines +40 to +47
@JsonCreator
public static ClubCategory from(String value) {
try {
return ClubCategory.valueOf(value.toUpperCase());
} catch (IllegalArgumentException e) {
throw new RestApiException(ErrorCode.CLUB_CATEGORY_INVALID);
}
}
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

from() 메서드의 구현을 개선하세요.

현재 구현의 문제점:

  1. toUpperCase()는 한글 enum 값에 대해 의미가 없습니다.
  2. fromString() 메서드와 달리 대소문자를 구분하여 일관성이 없습니다.

기존 fromString() 메서드를 재사용하여 일관성을 유지하는 것이 좋습니다.

@JsonCreator
public static ClubCategory from(String value) {
-    try {
-        return ClubCategory.valueOf(value.toUpperCase());
-    } catch (IllegalArgumentException e) {
+    ClubCategory category = fromString(value);
+    if (category == null) {
        throw new RestApiException(ErrorCode.CLUB_CATEGORY_INVALID);
    }
+    return category;
}
📝 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
@JsonCreator
public static ClubCategory from(String value) {
try {
return ClubCategory.valueOf(value.toUpperCase());
} catch (IllegalArgumentException e) {
throw new RestApiException(ErrorCode.CLUB_CATEGORY_INVALID);
}
}
@JsonCreator
public static ClubCategory from(String value) {
ClubCategory category = fromString(value);
if (category == null) {
throw new RestApiException(ErrorCode.CLUB_CATEGORY_INVALID);
}
return category;
}
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/club/enums/ClubCategory.java around lines 40 to
47, the from() method uses toUpperCase() which is ineffective for Korean enum
values and inconsistent with the case sensitivity of fromString(). Refactor
from() to reuse the existing fromString() method to maintain consistent case
handling and improve clarity.

Comment on lines +103 to +107
private void validateIntroduction(String introduction) {
if (introduction.length() > 24) {
throw new RestApiException(ErrorCode.TOO_LONG_INTRODUCTION);
}
}
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

소개글 검증 로직 개선 제안

introduction이 null인 경우에 대한 처리가 필요합니다.

다음과 같이 null 체크를 추가하는 것을 권장합니다:

 private void validateIntroduction(String introduction) {
+    if (introduction == null) {
+        return;
+    }
     if (introduction.length() > 24) {
         throw new RestApiException(ErrorCode.TOO_LONG_INTRODUCTION);
     }
 }
📝 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 void validateIntroduction(String introduction) {
if (introduction.length() > 24) {
throw new RestApiException(ErrorCode.TOO_LONG_INTRODUCTION);
}
}
private void validateIntroduction(String introduction) {
+ if (introduction == null) {
+ return;
+ }
if (introduction.length() > 24) {
throw new RestApiException(ErrorCode.TOO_LONG_INTRODUCTION);
}
}
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/club/entity/Club.java around lines 103 to 107,
the validateIntroduction method lacks a null check for the introduction
parameter. To fix this, add a condition to check if introduction is null before
checking its length, and handle the null case appropriately, such as throwing a
RestApiException or allowing empty introductions based on requirements.

Comment on lines +96 to +100
for (String tag : tags) {
if (tag.length() > 5) {
throw new RestApiException(ErrorCode.TOO_LONG_TAG);
}
}
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

태그 검증 로직 개선 제안

현재 태그 검증에서 null 체크가 누락되어 있습니다. tags가 null인 경우 NullPointerException이 발생할 수 있습니다.

다음과 같이 null 체크를 추가하는 것을 권장합니다:

 private void validateTags(List<String> tags) {
+    if (tags == null) {
+        return;
+    }
+    
     if (tags.size() > 3) {
         throw new RestApiException(ErrorCode.TOO_MANY_TAGS);
     }

     for (String tag : tags) {
+        if (tag == null) {
+            continue;
+        }
         if (tag.length() > 5) {
             throw new RestApiException(ErrorCode.TOO_LONG_TAG);
         }
     }
 }
📝 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
for (String tag : tags) {
if (tag.length() > 5) {
throw new RestApiException(ErrorCode.TOO_LONG_TAG);
}
}
private void validateTags(List<String> tags) {
if (tags == null) {
return;
}
if (tags.size() > 3) {
throw new RestApiException(ErrorCode.TOO_MANY_TAGS);
}
for (String tag : tags) {
if (tag == null) {
continue;
}
if (tag.length() > 5) {
throw new RestApiException(ErrorCode.TOO_LONG_TAG);
}
}
}
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/club/entity/Club.java around lines 96 to 100,
the tag validation loop does not check if the tags list is null, which can cause
a NullPointerException. Add a null check before the loop to ensure tags is not
null, and only then iterate over it to validate each tag's length.

Comment on lines +91 to +107
private void validateTags(List<String> tags) {
if (tags.size() > 3) {
throw new RestApiException(ErrorCode.TOO_MANY_TAGS);
}

for (String tag : tags) {
if (tag.length() > 5) {
throw new RestApiException(ErrorCode.TOO_LONG_TAG);
}
}
}

private void validateIntroduction(String introduction) {
if (introduction.length() > 24) {
throw new RestApiException(ErrorCode.TOO_LONG_INTRODUCTION);
}
}
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

검증 로직에 null 체크를 추가하세요.

검증 메서드들이 잘 구현되었지만 null 안전성을 개선할 필요가 있습니다.

 private void validateTags(List<String> tags) {
+    if (tags == null) {
+        return;
+    }
     if (tags.size() > 3) {
         throw new RestApiException(ErrorCode.TOO_MANY_TAGS);
     }

     for (String tag : tags) {
+        if (tag == null) {
+            continue;
+        }
         if (tag.length() > 5) {
             throw new RestApiException(ErrorCode.TOO_LONG_TAG);
         }
     }
 }

 private void validateIntroduction(String introduction) {
+    if (introduction == null) {
+        return;
+    }
     if (introduction.length() > 24) {
         throw new RestApiException(ErrorCode.TOO_LONG_INTRODUCTION);
     }
 }
🤖 Prompt for AI Agents
In backend/src/main/java/moadong/club/entity/Club.java around lines 91 to 107,
the validateTags and validateIntroduction methods lack null checks, which can
cause NullPointerExceptions. Add null checks at the start of each method to
handle null inputs safely, either by throwing an appropriate exception or by
returning early, ensuring the methods do not proceed with null values.

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.

수고하셨습니다

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

Labels

💾 BE Backend 🐞 Bug Something isn't working 🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants