diff --git a/src/main/java/com/sparta/tdd/domain/menu/controller/MenuController.java b/src/main/java/com/sparta/tdd/domain/menu/controller/MenuController.java index dc5bb33..b6d00aa 100644 --- a/src/main/java/com/sparta/tdd/domain/menu/controller/MenuController.java +++ b/src/main/java/com/sparta/tdd/domain/menu/controller/MenuController.java @@ -5,6 +5,8 @@ import com.sparta.tdd.domain.menu.dto.MenuResponseDto; import com.sparta.tdd.domain.menu.service.MenuService; import com.sparta.tdd.domain.user.enums.UserAuthority; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.validation.Valid; import java.util.List; import java.util.UUID; import lombok.RequiredArgsConstructor; @@ -29,6 +31,10 @@ public class MenuController { private final MenuService menuService; + @Operation( + summary = "메뉴 목록 조회", + description = "가게의 메뉴 목록을 조회합니다. OWERN나 MASTER가 아니면 숨겨진 메뉴를 볼 수 없습니다." + ) @GetMapping("/{storeId}/menu") public ResponseEntity> getMenus(@PathVariable UUID storeId, @AuthenticationPrincipal UserDetailsImpl userDetails) { @@ -37,6 +43,10 @@ public ResponseEntity> getMenus(@PathVariable UUID storeId .body(menuService.getMenus(storeId, authority)); } + @Operation( + summary = "메뉴 상세 조회", + description = "가게의 특정 메뉴를 조회합니다. OWNER나 MASTER가 아니면 숨겨진 메뉴를 볼 수 없습니다. " + ) @GetMapping("/{storeId}/menu/{menuId}") public ResponseEntity getMenu(@PathVariable UUID storeId, @PathVariable UUID menuId, @@ -46,16 +56,24 @@ public ResponseEntity getMenu(@PathVariable UUID storeId, .body(menuService.getMenu(storeId, menuId, authority)); } + @Operation( + summary = "메뉴 등록", + description = "가게의 메뉴를 등록합니다. OWNER나 MASTER만 가능하며, 해당 가게 점주가 아니라면 예외가 발생합니다. " + ) @PreAuthorize("hasAnyRole('OWNER', 'MASTER')") @PostMapping("/{storeId}/menu") public ResponseEntity createMenu(@PathVariable UUID storeId, - @RequestBody MenuRequestDto menuRequestDto, + @Valid @RequestBody MenuRequestDto menuRequestDto, @AuthenticationPrincipal UserDetailsImpl userDetails) { Long userId = userDetails.getUserId(); return ResponseEntity.status(HttpStatus.CREATED) .body(menuService.createMenu(storeId, menuRequestDto, userId)); } + @Operation( + summary = "메뉴 수정", + description = "가게의 메뉴를 수정합니다. OWNER나 MASTER만 가능하며, 해당 가게 점주가 아니라면 예외가 발생합니다. " + ) @PreAuthorize("hasAnyRole('OWNER', 'MASTER')") @PatchMapping("/{storeId}/menu/{menuId}") public ResponseEntity updateMenu(@PathVariable UUID storeId, @PathVariable UUID menuId, @@ -66,6 +84,10 @@ public ResponseEntity updateMenu(@PathVariable UUID storeId, @PathVariable return ResponseEntity.noContent().build(); } + @Operation( + summary = "메뉴 상태 변경", + description = "가게의 메뉴 상태를 변경합니다. 메뉴를 숨기거나, 공개할 수 있습니다. OWNER나 MASTER만 가능하며, 해당 가게 점주가 아니라면 예외가 발생합니다. " + ) @PreAuthorize("hasAnyRole('OWNER', 'MASTER')") @PatchMapping("/{storeId}/menu/{menuId}/status") public ResponseEntity updateMenuStatus(@PathVariable UUID storeId, @@ -77,6 +99,10 @@ public ResponseEntity updateMenuStatus(@PathVariable UUID storeId, return ResponseEntity.noContent().build(); } + @Operation( + summary = "메뉴 삭제", + description = "가게의 메뉴를 삭제합니다. OWNER나 MASTER만 가능하며, 해당 가게 점주가 아니라면 예외가 발생합니다. 메뉴는 soft delete 됩니다. " + ) @PreAuthorize("hasAnyRole('OWNER', 'MASTER')") @DeleteMapping("/{storeId}/menu/{menuId}") public ResponseEntity deleteMenu(@PathVariable UUID storeId, @PathVariable UUID menuId, diff --git a/src/main/java/com/sparta/tdd/domain/menu/dto/MenuRequestDto.java b/src/main/java/com/sparta/tdd/domain/menu/dto/MenuRequestDto.java index f409d5f..0707e2a 100644 --- a/src/main/java/com/sparta/tdd/domain/menu/dto/MenuRequestDto.java +++ b/src/main/java/com/sparta/tdd/domain/menu/dto/MenuRequestDto.java @@ -2,13 +2,19 @@ import com.sparta.tdd.domain.menu.entity.Menu; import com.sparta.tdd.domain.store.entity.Store; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.Builder; +@Schema(description = "메뉴 등록 및 수정 요청 DTO") @Builder public record MenuRequestDto( - String name, + @Schema(description = "메뉴 설명", example = "바삭한 치킨과 신선한 야채가 들어간 버거") + @NotNull @Size(max = 20) String name, String description, - Integer price, + @Schema(description = "가격", example = "10000") + @NotNull Integer price, String imageUrl, boolean useAiDescription ) { @@ -22,7 +28,7 @@ public Menu toEntity(Store store, String description) { .store(store) .build(); } - + public Menu toEntity(Store store) { return Menu.builder() .name(name) diff --git a/src/main/java/com/sparta/tdd/domain/menu/dto/MenuResponseDto.java b/src/main/java/com/sparta/tdd/domain/menu/dto/MenuResponseDto.java index 114d320..27c03dd 100644 --- a/src/main/java/com/sparta/tdd/domain/menu/dto/MenuResponseDto.java +++ b/src/main/java/com/sparta/tdd/domain/menu/dto/MenuResponseDto.java @@ -1,16 +1,24 @@ package com.sparta.tdd.domain.menu.dto; import com.sparta.tdd.domain.menu.entity.Menu; +import io.swagger.v3.oas.annotations.media.Schema; import java.util.UUID; import lombok.Builder; +@Schema(description = "메뉴 응답 DTO") @Builder public record MenuResponseDto( + @Schema(description = "menu 아이디", example = "1") UUID menuId, + @Schema(description = "메뉴명", example = "햄버거") String name, + @Schema(description = "메뉴 설명", example = "바삭한 치킨과 신선한 야채가 들어간 버거") String description, + @Schema(description = "가격", example = "10000") Integer price, + @Schema(description = "메뉴 이미지 URL", example = "https://example.com/images/chicken-burger.jpg") String imageUrl, + @Schema(description = "숨김 여부", example = "Boolean.False") Boolean isHidden ) { diff --git a/src/main/java/com/sparta/tdd/domain/menu/service/MenuService.java b/src/main/java/com/sparta/tdd/domain/menu/service/MenuService.java index e576a20..280c7c6 100644 --- a/src/main/java/com/sparta/tdd/domain/menu/service/MenuService.java +++ b/src/main/java/com/sparta/tdd/domain/menu/service/MenuService.java @@ -115,7 +115,7 @@ private User findUser(Long userId) { private void validateUserOnMenu(User user, Store store) { if (!store.isOwner(user)) { - throw new BusinessException(ErrorCode.STORE_OWNERSHIP_DENIED); + throw new BusinessException(ErrorCode.MENU_PERMISSION_DENIED); } } } diff --git a/src/main/java/com/sparta/tdd/global/exception/ErrorCode.java b/src/main/java/com/sparta/tdd/global/exception/ErrorCode.java index 6f7c465..6beddec 100644 --- a/src/main/java/com/sparta/tdd/global/exception/ErrorCode.java +++ b/src/main/java/com/sparta/tdd/global/exception/ErrorCode.java @@ -48,6 +48,7 @@ public enum ErrorCode { MENU_NOT_IN_STORE(HttpStatus.BAD_REQUEST, "해당 가게의 메뉴가 아닙니다."), MENU_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 메뉴가 포함되어 있습니다."), MENU_INVALID_INFO(HttpStatus.BAD_REQUEST, "메뉴 정보가 올바르지 않습니다."), + MENU_PERMISSION_DENIED(HttpStatus.FORBIDDEN, "해당 메뉴에 대한 권한이 없습니다."), // REVIEW 도메인 관련 REVIEW_NOT_OWNED(HttpStatus.FORBIDDEN, "본인의 리뷰만 수정/삭제할 수 있습니다."),