Skip to content

Conversation

@seojelee9999
Copy link
Contributor

@seojelee9999 seojelee9999 commented Dec 16, 2025

✨ 변경 사항


✅ 테스트


  • 수동 테스트 완료
  • 테스트 코드 완료

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 메뉴 ID로 단일 메뉴 정보를 조회하는 신규 API 엔드포인트가 추가되었습니다.
  • 개선사항

    • 메뉴 등록 시 이미지 URL 입력이 이제 필수로 변경되어 데이터 완성도가 향상됩니다.
    • API 문서와 엔드포인트 설명이 개선되어 사용성 및 이해도가 향상됩니다.
    • 인증 오류의 응답 상태가 일부 상황에서 보다 적절한 HTTP 상태 코드(권한 관련)로 조정되었습니다.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 16, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

메뉴 도메인에 단일 메뉴 조회 기능을 추가하고 API 문서를 확장했으며, 메뉴 이미지 URL 입력에 대한 필수 검증을 추가하고 인증 관련 일부 에러 코드/처리를 조정합니다.

Changes

Cohort / File(s) 변경 요약
메뉴 컨트롤러
src/main/java/com/campustable/be/domain/menu/controller/MenuController.java
GET /{menuId} 엔드포인트(getMenuById) 추가, menuService.getMenuById로 위임
메뉴 서비스
src/main/java/com/campustable/be/domain/menu/service/MenuService.java
getMenuById(Long menuId) 메서드 추가; 일부 orElseThrow 람다의 예외 반환 방식 변경 및 불필요 import 제거
API 문서화
src/main/java/com/campustable/be/domain/menu/controller/MenuControllerDocs.java
getMenuById 문서화 추가 및 Swagger/OpenAPI 주석 확장/수정
입력 검증
src/main/java/com/campustable/be/domain/menu/dto/MenuRequest.java
menuUrl 필드에 @NotBlank(message = "이미지를 위한url은 필수입니다.") 검증 추가
인증 / 에러 코드
src/main/java/com/campustable/be/domain/auth/service/AuthService.java,
src/main/java/com/campustable/be/global/exception/ErrorCode.java
리프레시 토큰 재발급 시 예외 코드 변경(REFRESH_TOKEN_EXPIRED / REFRESH_TOKEN_INVALID 사용) 및 JWT_INVALID의 HTTP 상태를 UNAUTHORIZED로 변경

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • MenuService: 새 메서드 로직과 기존 조회/예외 처리(특히 orElseThrow 변경) 일관성 확인
  • MenuRequest: @NotBlank 적용이 생성/수정 흐름과 예외 응답에 미치는 영향 점검
  • AuthService / ErrorCode: 토큰 재발급 예외 매핑 변경이 클라이언트 응답 및 인증 플로우에 미치는 영향 확인
  • ControllerDocs: Swagger 주석과 실제 엔드포인트 동작 일치 여부 검증

Possibly related PRs

Suggested labels

feat

Poem

🐰 메뉴 한 조각 찾아 폴짝,
ID로 불러와 빛나는 접시,
URL은 꼭 채워줘야 해,
문서도 빛나고 토큰도 단정,
토끼가 기쁘게 춤을 추네 ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 개별 메뉴 조회 API 추가와 menuUrl 검증 강화라는 변경사항의 주요 내용을 명확하고 구체적으로 요약하고 있습니다.

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3efea72 and e37fae6.

📒 Files selected for processing (2)
  • src/main/java/com/campustable/be/domain/auth/service/AuthService.java (1 hunks)
  • src/main/java/com/campustable/be/global/exception/ErrorCode.java (1 hunks)

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.

Copy link

@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

🧹 Nitpick comments (2)
src/main/java/com/campustable/be/domain/menu/service/MenuService.java (1)

58-69: 로그 레벨 일관성을 고려해주세요.

메뉴가 존재하지 않는 경우는 클라이언트 오류(404)에 가까우므로, log.error 대신 log.warn을 사용하는 것이 더 적절할 수 있습니다. 같은 파일의 Line 39와 Line 84에서는 유사한 상황에 log.warn을 사용하고 있습니다.

-          log.error("getMenuById : 유효하지않은 menuId");
+          log.warn("getMenuById: 유효하지 않은 menuId");
src/main/java/com/campustable/be/domain/menu/controller/MenuController.java (1)

38-87: 경로 변수 명명 규칙의 일관성을 고려해주세요.

엔드포인트 간 경로 변수 명명 규칙이 일관되지 않습니다:

  • Line 38: category_id (snake_case)
  • Line 50: menuId (camelCase) - 신규 엔드포인트
  • Line 57: cafeteria-id (kebab-case)
  • Line 74, 87: menu_id (snake_case)

REST API 모범 사례에서는 일관된 명명 규칙(일반적으로 kebab-case)을 권장합니다. 향후 유지보수성을 위해 팀 내에서 명명 규칙을 통일하는 것을 고려해보세요.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4cb81d0 and 3efea72.

📒 Files selected for processing (4)
  • src/main/java/com/campustable/be/domain/menu/controller/MenuController.java (2 hunks)
  • src/main/java/com/campustable/be/domain/menu/controller/MenuControllerDocs.java (1 hunks)
  • src/main/java/com/campustable/be/domain/menu/dto/MenuRequest.java (1 hunks)
  • src/main/java/com/campustable/be/domain/menu/service/MenuService.java (3 hunks)
🔇 Additional comments (4)
src/main/java/com/campustable/be/domain/menu/service/MenuService.java (2)

38-41: 예외 처리 패턴이 올바르게 수정되었습니다.

람다 표현식 내에서 return new CustomException(...)을 사용하는 것은 올바른 패턴입니다.


82-86: 예외 처리 패턴이 올바르게 수정되었습니다.

람다 표현식 내에서 return new CustomException(...)을 사용하는 것은 올바른 패턴입니다.

src/main/java/com/campustable/be/domain/menu/controller/MenuControllerDocs.java (1)

33-46: 새로운 API 문서가 잘 작성되었습니다.

getMenuById 메서드의 API 문서가 명확하고 포괄적입니다. 성공 및 오류 응답이 적절히 문서화되었습니다.

src/main/java/com/campustable/be/domain/menu/controller/MenuController.java (1)

48-53: 새로운 엔드포인트가 올바르게 구현되었습니다.

단일 메뉴 조회 엔드포인트가 간결하고 올바르게 구현되었으며, 서비스 레이어로 적절히 위임됩니다.

Comment on lines +18 to +126
/**
* 메뉴 관리 시스템의 API 명세를 정의하는 인터페이스입니다.
* 메뉴의 등록, 수정, 삭제 및 다양한 조건별 조회 기능을 제공합니다.
*/
@Tag(name = "Menu Management", description = "메뉴 CRUD 및 조회 API")
public interface MenuControllerDocs {

@Operation(summary = "메뉴 전체 조회", description = "모든 메뉴 목록을 조회합니다.")
@ApiResponse(responseCode = "200", description = "조회 성공")
ResponseEntity<List<MenuResponse>> getAllMenus();
/**
* 시스템에 등록된 모든 메뉴 목록을 조회합니다.
* * @return 메뉴 정보 리스트를 담은 ResponseEntity
*/
@Operation(summary = "메뉴 전체 조회", description = "모든 메뉴 목록을 조회합니다.")
@ApiResponse(responseCode = "200", description = "조회 성공")
ResponseEntity<List<MenuResponse>> getAllMenus();

@Operation(summary = "카테고리별 메뉴 조회", description = "특정 카테고리 ID에 해당하는 메뉴 목록을 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "해당 카테고리를 찾을 수 없습니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<List<MenuResponse>> getAllMenusByCategoryId(
@Parameter(description = "조회할 카테고리 ID", example = "1")
Long categoryId
);
/**
* 고유 식별자를 통해 단일 메뉴의 상세 정보를 조회합니다.
* * @param menuId 조회하고자 하는 메뉴의 ID
* @return 해당 메뉴의 상세 정보를 담은 ResponseEntity
*/
@Operation(summary = "단일 메뉴 상세 조회", description = "특정 ID에 해당하는 메뉴의 상세 정보를 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "해당 메뉴를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> getMenuById(
@Parameter(description = "조회할 메뉴 ID", example = "1") Long menuId
);

@Operation(summary = "식당별 메뉴 조회", description = "식당 ID에 해당하는 메뉴 목록을 조회합니다.")
ResponseEntity<List<MenuResponse>> getAllMenusByCafeteriaId(
@Parameter(description = "조회할 식당 ID", example = "1")
Long cafeteriaId
);
/**
* 특정 카테고리에 속한 모든 메뉴를 조회합니다.
* * @param categoryId 카테고리 고유 식별자
* @return 해당 카테고리의 메뉴 리스트를 담은 ResponseEntity
*/
@Operation(summary = "카테고리별 메뉴 조회", description = "특정 카테고리 ID에 해당하는 메뉴 목록을 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "해당 카테고리를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<List<MenuResponse>> getAllMenusByCategoryId(
@Parameter(description = "조회할 카테고리 ID", example = "1") Long categoryId
);

@Operation(
summary = "신규 메뉴 생성 (관리자 전용)",
description = "새로운 메뉴를 등록합니다."
)
@ApiResponses({
@ApiResponse(responseCode = "201", description = "메뉴 생성 성공"),
@ApiResponse(responseCode = "400", description = "입력값 오류(이름/가격/사용 가능)",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "409", description = "해당 카테고리에 이미 존재하는 메뉴입니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> createMenu(MenuRequest menuRequest);
/**
* 특정 식당에서 제공하는 모든 메뉴를 조회합니다.
* * @param cafeteriaId 식당 고유 식별자
* @return 해당 식당의 메뉴 리스트를 담은 ResponseEntity
*/
@Operation(summary = "식당별 메뉴 조회", description = "식당 ID에 해당하는 메뉴 목록을 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "해당 식당을 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<List<MenuResponse>> getAllMenusByCafeteriaId(
@Parameter(description = "조회할 식당 ID", example = "1") Long cafeteriaId
);

@Operation(
summary = "메뉴 정보 수정(관리자 전용)",
description = "특정 ID의 메뉴 정보를 수정합니다."
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "메뉴 수정 성공"),
@ApiResponse(responseCode = "400", description = "입력값 오류" ,
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> updateMenu(
@Parameter(description = "수정할 메뉴의 ID", example = "1")
Long menuId,
MenuUpdateRequest menuUpdateRequest
);
/**
* 새로운 메뉴를 시스템에 등록합니다. (관리자 권한 필요)
* * @param menuRequest 생성할 메뉴의 상세 정보 DTO
* @return 생성된 메뉴 정보를 담은 ResponseEntity
*/
@Operation(summary = "신규 메뉴 생성 (관리자 전용)", description = "새로운 메뉴를 등록합니다.")
@ApiResponses({
@ApiResponse(responseCode = "201", description = "메뉴 생성 성공"),
@ApiResponse(responseCode = "400", description = "입력값 오류(이름/가격 등)",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "409", description = "이미 존재하는 메뉴입니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> createMenu(MenuRequest menuRequest);

@Operation(
summary = "메뉴 삭제 (관리자 전용)",
description = "특정 ID의 메뉴를 삭제 합니다."
)
@ApiResponses({
@ApiResponse(responseCode = "204", description = "메뉴 삭제 성공"),
@ApiResponse(responseCode = "404", description = "해당 메뉴를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<Void> deleteMenu(
@Parameter(description = "삭제할 메뉴의 ID", example = "1")
Long menuId
);
}
/**
* 기존 메뉴 정보를 수정합니다. (관리자 권한 필요)
* * @param menuId 수정할 메뉴의 ID
* @param menuUpdateRequest 수정할 내용이 담긴 DTO
* @return 수정 완료된 메뉴 정보를 담은 ResponseEntity
*/
@Operation(summary = "메뉴 정보 수정 (관리자 전용)", description = "특정 ID의 메뉴 정보를 수정합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "메뉴 수정 성공"),
@ApiResponse(responseCode = "400", description = "입력값 오류",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "404", description = "해당 메뉴를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> updateMenu(
@Parameter(description = "수정할 메뉴 ID", example = "1") Long menuId,
MenuUpdateRequest menuUpdateRequest
);

/**
* 특정 메뉴를 시스템에서 삭제합니다. (관리자 권한 필요)
* * @param menuId 삭제할 메뉴의 ID
* @return 삭제 성공 시 빈 바디를 담은 ResponseEntity (204 No Content)
*/
@Operation(summary = "메뉴 삭제 (관리자 전용)", description = "특정 ID의 메뉴를 삭제합니다.")
@ApiResponses({
@ApiResponse(responseCode = "204", description = "메뉴 삭제 성공"),
@ApiResponse(responseCode = "404", description = "해당 메뉴를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<Void> deleteMenu(
@Parameter(description = "삭제할 메뉴 ID", example = "1") Long menuId
);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Javadoc 형식 오류를 수정해주세요.

여러 메서드의 Javadoc에서 * * @param 또는 * * @return 패턴이 발견됩니다(Lines 27, 35, 50, 65, 80, 95, 114). 이는 * @param 또는 * @return으로 수정되어야 합니다.

예시 수정:

  /**
   * 시스템에 등록된 모든 메뉴 목록을 조회합니다.
-  * * @return 메뉴 정보 리스트를 담은 ResponseEntity
+  * @return 메뉴 정보 리스트를 담은 ResponseEntity
   */

모든 메서드의 Javadoc에서 동일한 패턴을 찾아 수정해주세요.

📝 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
/**
* 메뉴 관리 시스템의 API 명세를 정의하는 인터페이스입니다.
* 메뉴의 등록, 수정, 삭제 다양한 조건별 조회 기능을 제공합니다.
*/
@Tag(name = "Menu Management", description = "메뉴 CRUD 및 조회 API")
public interface MenuControllerDocs {
@Operation(summary = "메뉴 전체 조회", description = "모든 메뉴 목록을 조회합니다.")
@ApiResponse(responseCode = "200", description = "조회 성공")
ResponseEntity<List<MenuResponse>> getAllMenus();
/**
* 시스템에 등록된 모든 메뉴 목록을 조회합니다.
* * @return 메뉴 정보 리스트를 담은 ResponseEntity
*/
@Operation(summary = "메뉴 전체 조회", description = "모든 메뉴 목록을 조회합니다.")
@ApiResponse(responseCode = "200", description = "조회 성공")
ResponseEntity<List<MenuResponse>> getAllMenus();
@Operation(summary = "카테고리별 메뉴 조회", description = "특정 카테고리 ID에 해당하는 메뉴 목록을 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "해당 카테고리를 찾을 수 없습니다.", content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<List<MenuResponse>> getAllMenusByCategoryId(
@Parameter(description = "조회할 카테고리 ID", example = "1")
Long categoryId
);
/**
* 고유 식별자를 통해 단일 메뉴의 상세 정보를 조회합니다.
* * @param menuId 조회하고자 하는 메뉴의 ID
* @return 해당 메뉴의 상세 정보를 담은 ResponseEntity
*/
@Operation(summary = "단일 메뉴 상세 조회", description = "특정 ID에 해당하는 메뉴의 상세 정보를 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "해당 메뉴를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> getMenuById(
@Parameter(description = "조회할 메뉴 ID", example = "1") Long menuId
);
@Operation(summary = "식당별 메뉴 조회", description = "식당 ID에 해당하는 메뉴 목록을 조회합니다.")
ResponseEntity<List<MenuResponse>> getAllMenusByCafeteriaId(
@Parameter(description = "조회할 식당 ID", example = "1")
Long cafeteriaId
);
/**
* 특정 카테고리에 속한 모든 메뉴를 조회합니다.
* * @param categoryId 카테고리 고유 식별자
* @return 해당 카테고리의 메뉴 리스트를 담은 ResponseEntity
*/
@Operation(summary = "카테고리별 메뉴 조회", description = "특정 카테고리 ID에 해당하는 메뉴 목록을 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "해당 카테고리를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<List<MenuResponse>> getAllMenusByCategoryId(
@Parameter(description = "조회할 카테고리 ID", example = "1") Long categoryId
);
@Operation(
summary = "신규 메뉴 생성 (관리자 전용)",
description = "새로운 메뉴를 등록합니다."
)
@ApiResponses({
@ApiResponse(responseCode = "201", description = "메뉴 생성 성공"),
@ApiResponse(responseCode = "400", description = "입력값 오류(이름/가격/사용 가능)",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "409", description = "해당 카테고리에 이미 존재하는 메뉴입니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> createMenu(MenuRequest menuRequest);
/**
* 특정 식당에서 제공하는 모든 메뉴를 조회합니다.
* * @param cafeteriaId 식당 고유 식별자
* @return 해당 식당의 메뉴 리스트를 담은 ResponseEntity
*/
@Operation(summary = "식당별 메뉴 조회", description = "식당 ID에 해당하는 메뉴 목록을 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "해당 식당을 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<List<MenuResponse>> getAllMenusByCafeteriaId(
@Parameter(description = "조회할 식당 ID", example = "1") Long cafeteriaId
);
@Operation(
summary = "메뉴 정보 수정(관리자 전용)",
description = "특정 ID의 메뉴 정보를 수정합니다."
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "메뉴 수정 성공"),
@ApiResponse(responseCode = "400", description = "입력값 오류" ,
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> updateMenu(
@Parameter(description = "수정할 메뉴의 ID", example = "1")
Long menuId,
MenuUpdateRequest menuUpdateRequest
);
/**
* 새로운 메뉴를 시스템에 등록합니다. (관리자 권한 필요)
* * @param menuRequest 생성할 메뉴의 상세 정보 DTO
* @return 생성된 메뉴 정보를 담은 ResponseEntity
*/
@Operation(summary = "신규 메뉴 생성 (관리자 전용)", description = "새로운 메뉴를 등록합니다.")
@ApiResponses({
@ApiResponse(responseCode = "201", description = "메뉴 생성 성공"),
@ApiResponse(responseCode = "400", description = "입력값 오류(이름/가격 등)",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "409", description = "이미 존재하는 메뉴입니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> createMenu(MenuRequest menuRequest);
@Operation(
summary = "메뉴 삭제 (관리자 전용)",
description = "특정 ID의 메뉴를 삭제 합니다."
)
@ApiResponses({
@ApiResponse(responseCode = "204", description = "메뉴 삭제 성공"),
@ApiResponse(responseCode = "404", description = "해당 메뉴를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<Void> deleteMenu(
@Parameter(description = "삭제할 메뉴의 ID", example = "1")
Long menuId
);
}
/**
* 기존 메뉴 정보를 수정합니다. (관리자 권한 필요)
* * @param menuId 수정할 메뉴의 ID
* @param menuUpdateRequest 수정할 내용이 담긴 DTO
* @return 수정 완료된 메뉴 정보를 담은 ResponseEntity
*/
@Operation(summary = "메뉴 정보 수정 (관리자 전용)", description = "특정 ID의 메뉴 정보를 수정합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "메뉴 수정 성공"),
@ApiResponse(responseCode = "400", description = "입력값 오류",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "404", description = "해당 메뉴를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> updateMenu(
@Parameter(description = "수정할 메뉴 ID", example = "1") Long menuId,
MenuUpdateRequest menuUpdateRequest
);
/**
* 특정 메뉴를 시스템에서 삭제합니다. (관리자 권한 필요)
* * @param menuId 삭제할 메뉴의 ID
* @return 삭제 성공 바디를 담은 ResponseEntity (204 No Content)
*/
@Operation(summary = "메뉴 삭제 (관리자 전용)", description = "특정 ID의 메뉴를 삭제합니다.")
@ApiResponses({
@ApiResponse(responseCode = "204", description = "메뉴 삭제 성공"),
@ApiResponse(responseCode = "404", description = "해당 메뉴를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<Void> deleteMenu(
@Parameter(description = "삭제할 메뉴 ID", example = "1") Long menuId
);
}
/**
* 메뉴 관리 시스템의 API 명세를 정의하는 인터페이스입니다.
* 메뉴의 등록, 수정, 삭제 다양한 조건별 조회 기능을 제공합니다.
*/
@Tag(name = "Menu Management", description = "메뉴 CRUD 및 조회 API")
public interface MenuControllerDocs {
/**
* 시스템에 등록된 모든 메뉴 목록을 조회합니다.
* @return 메뉴 정보 리스트를 담은 ResponseEntity
*/
@Operation(summary = "메뉴 전체 조회", description = "모든 메뉴 목록을 조회합니다.")
@ApiResponse(responseCode = "200", description = "조회 성공")
ResponseEntity<List<MenuResponse>> getAllMenus();
/**
* 고유 식별자를 통해 단일 메뉴의 상세 정보를 조회합니다.
* @param menuId 조회하고자 하는 메뉴의 ID
* @return 해당 메뉴의 상세 정보를 담은 ResponseEntity
*/
@Operation(summary = "단일 메뉴 상세 조회", description = "특정 ID에 해당하는 메뉴의 상세 정보를 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "해당 메뉴를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> getMenuById(
@Parameter(description = "조회할 메뉴 ID", example = "1") Long menuId
);
/**
* 특정 카테고리에 속한 모든 메뉴를 조회합니다.
* @param categoryId 카테고리 고유 식별자
* @return 해당 카테고리의 메뉴 리스트를 담은 ResponseEntity
*/
@Operation(summary = "카테고리별 메뉴 조회", description = "특정 카테고리 ID에 해당하는 메뉴 목록을 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "해당 카테고리를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<List<MenuResponse>> getAllMenusByCategoryId(
@Parameter(description = "조회할 카테고리 ID", example = "1") Long categoryId
);
/**
* 특정 식당에서 제공하는 모든 메뉴를 조회합니다.
* @param cafeteriaId 식당 고유 식별자
* @return 해당 식당의 메뉴 리스트를 담은 ResponseEntity
*/
@Operation(summary = "식당별 메뉴 조회", description = "식당 ID에 해당하는 메뉴 목록을 조회합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "조회 성공"),
@ApiResponse(responseCode = "404", description = "해당 식당을 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<List<MenuResponse>> getAllMenusByCafeteriaId(
@Parameter(description = "조회할 식당 ID", example = "1") Long cafeteriaId
);
/**
* 새로운 메뉴를 시스템에 등록합니다. (관리자 권한 필요)
* @param menuRequest 생성할 메뉴의 상세 정보 DTO
* @return 생성된 메뉴 정보를 담은 ResponseEntity
*/
@Operation(summary = "신규 메뉴 생성 (관리자 전용)", description = "새로운 메뉴를 등록합니다.")
@ApiResponses({
@ApiResponse(responseCode = "201", description = "메뉴 생성 성공"),
@ApiResponse(responseCode = "400", description = "입력값 오류(이름/가격 등)",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "409", description = "이미 존재하는 메뉴입니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> createMenu(MenuRequest menuRequest);
/**
* 기존 메뉴 정보를 수정합니다. (관리자 권한 필요)
* @param menuId 수정할 메뉴의 ID
* @param menuUpdateRequest 수정할 내용이 담긴 DTO
* @return 수정 완료된 메뉴 정보를 담은 ResponseEntity
*/
@Operation(summary = "메뉴 정보 수정 (관리자 전용)", description = "특정 ID의 메뉴 정보를 수정합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "메뉴 수정 성공"),
@ApiResponse(responseCode = "400", description = "입력값 오류",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "404", description = "해당 메뉴를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<MenuResponse> updateMenu(
@Parameter(description = "수정할 메뉴 ID", example = "1") Long menuId,
MenuUpdateRequest menuUpdateRequest
);
/**
* 특정 메뉴를 시스템에서 삭제합니다. (관리자 권한 필요)
* @param menuId 삭제할 메뉴의 ID
* @return 삭제 성공 바디를 담은 ResponseEntity (204 No Content)
*/
@Operation(summary = "메뉴 삭제 (관리자 전용)", description = "특정 ID의 메뉴를 삭제합니다.")
@ApiResponses({
@ApiResponse(responseCode = "204", description = "메뉴 삭제 성공"),
@ApiResponse(responseCode = "404", description = "해당 메뉴를 찾을 수 없습니다.",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<Void> deleteMenu(
@Parameter(description = "삭제할 메뉴 ID", example = "1") Long menuId
);
}
🤖 Prompt for AI Agents
In
src/main/java/com/campustable/be/domain/menu/controller/MenuControllerDocs.java
around lines 18 to 126, several Javadoc lines (notably lines 27, 35, 50, 65, 80,
95, 114) contain the erroneous token "* * @param" or "* * @return"; replace each
occurrence with the correct single asterisk form "* @param" or "* @return"
respectively, ensuring each Javadoc tag follows the standard format and that
spacing/indentation remains consistent across all method comments.

@Min(value = 0, message = "가격은 0원 이상이어야 합니다.")
private Integer price;

@NotBlank(message = "이미지를 위한url은 필수입니다.")
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

echo "=== 1. Menu 엔티티와 MenuRequest 정의 확인 ==="
find . -name "Menu.java" -type f | head -5 | xargs ls -la 2>/dev/null || echo "Menu.java not found"

echo -e "\n=== 2. MenuRequest.java 파일 전체 확인 ==="
find . -name "MenuRequest.java" -type f | head -1 | xargs cat -n 2>/dev/null

echo -e "\n=== 3. Menu 엔티티에서 menuUrl 필드 확인 ==="
find . -name "Menu.java" -type f | head -1 | xargs grep -n "menuUrl" 2>/dev/null

echo -e "\n=== 4. menuUrl 필드 사용 현황 (전체 코드베이스) ==="
rg -n "menuUrl" --type java -C 2 | head -60

echo -e "\n=== 5. MenuRequest 관련 컨트롤러 찾기 ==="
rg -n "MenuRequest" --type java -C 1 | head -40

echo -e "\n=== 6. Menu 관련 테스트 파일 확인 ==="
find . -path "*test*" -name "*Menu*" -type f | grep -E "\.(java|kt)$"

echo -e "\n=== 7. 기존 null/empty 체크 패턴 ==="
rg -n "menuUrl\s*(==|!=|isNull|isEmpty|isBlank)" --type java

Repository: CampusTable/campus-table-be

Length of output: 7391


🏁 Script executed:

#!/bin/bash

echo "=== MenuUpdateRequest.java 전체 파일 확인 ==="
find . -name "MenuUpdateRequest.java" -type f | head -1 | xargs cat -n

echo -e "\n=== Menu 엔티티 전체 확인 ==="
find . -name "Menu.java" -path "*/entity/*" -type f | head -1 | xargs cat -n

Repository: CampusTable/campus-table-be

Length of output: 3540


menuUrl 필드의 @notblank 검증 추가 - 주의 필요

이 변경은 데이터 무결성을 개선하지만 다음 문제점들을 해결해야 합니다:

  1. API 계약 변경 (Breaking Change): MenuRequest에서 menuUrl이 이제 필수이므로, 기존 클라이언트의 null/빈 값 전송이 모두 거부됩니다. 기존 데이터베이스의 Menu 레코드 중 menuUrl이 null인 경우도 영향받습니다.

  2. 검증 일관성 부족: MenuUpdateRequest는 menuUrl에 검증 어노테이션이 없어 업데이트 시 null 전송이 가능합니다. 생성(MenuRequest)과 업데이트(MenuUpdateRequest) 로직의 일관성이 맞지 않습니다. MenuUpdateRequest의 menuUrl도 @notblank를 추가하거나, 명확한 이유를 문서화해야 합니다.

  3. 테스트 커버리지 부재: 리포지토리에 Menu 관련 테스트 파일이 없으므로, 이 변경사항의 검증과 기존 동작의 회귀 테스트가 필요합니다. 최소한 null/빈 menuUrl 검증 테스트와 기존 데이터 호환성 테스트를 추가하세요.

@seojelee9999 seojelee9999 merged commit 7cca723 into main Dec 17, 2025
2 of 3 checks passed
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.

2 participants