Skip to content

[FEAT] 푸드트럭 상세조회 API 구현#54

Merged
buzz0331 merged 11 commits intodevelopfrom
feat/#53-foodtruck-detail-info
Oct 30, 2025
Merged

[FEAT] 푸드트럭 상세조회 API 구현#54
buzz0331 merged 11 commits intodevelopfrom
feat/#53-foodtruck-detail-info

Conversation

@buzz0331
Copy link
Contributor

@buzz0331 buzz0331 commented Oct 29, 2025

#️⃣연관된 이슈

📝작업 내용

단순 조회라서 딱히 특이사항이 없었습니다.

유효성 검증시에 사용자의 역할에 따라 다르게 검증하였습니다.

  • 일반 유저 -> 푸드트럭 노출 상태가 ON일 경우에만 조회 가능
  • 사장님 -> 본인 소유 푸드트럭일 경우 노출 상태 상관없이 가능 / 아닐 경우 노출 상태가 ON일 경우만 조회 가능
  • 관리자 -> 유효성 검증 패스

추가적으로 찬영님 요청에 따라 메뉴 검색 API를 구현하였습니다. 단순히 like 문을 사용해서 구현하였고, 반환 타입은 찬영님과의 합의하에 리스트 객체로 감싸지 않고 바로 리스트를 반환하도록 구현하였습니다.

스크린샷 (선택)

💬리뷰 요구사항(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

Summary by CodeRabbit

  • 새로운 기능

    • 푸드트럭 상세 조회 추가: 운영 시간, 서비스 지역, 메뉴 목록, 사진, 평점 및 사용자의 저장 여부 포함.
    • 메뉴 키워드 검색 추가: 특정 푸드트럭 내 메뉴를 키워드로 검색 가능.
    • 가용 일자 표시 개선: 가용 일자가 "시작 ~ 종료" 형식 문자열로 제공.
  • 문서

    • API 응답 및 오류 설명에 상세 조회·메뉴 검색 관련 상태 추가.

@coderabbitai
Copy link

coderabbitai bot commented Oct 29, 2025

Walkthrough

회원 검증을 전제로 푸드트럭 상세조회와 메뉴 키워드 검색 기능이 추가되었습니다. 컨트롤러, 서비스, 도메인, 레포지토리, 응답 DTO, Swagger 및 오류 코드에 관련 엔드포인트와 메서드가 도입되었습니다. (≤50단어)

Changes

Cohort / File(s) Summary
컨트롤러 엔드포인트
\src/main/java/konkuk/chacall/domain/foodtruck/presentation/FoodTruckController.java``
GET /{foodTruckId}(상세조회) 및 GET /{foodTruckId}/menus/search(메뉴 키워드 검색) 엔드포인트 추가; 기존 매핑에 누락된 선행 슬래시 수정; List import 추가.
응용 서비스
\src/main/java/konkuk/chacall/domain/foodtruck/application/FoodTruckService.java`, `src/main/java/konkuk/chacall/domain/foodtruck/application/info/FoodTruckInfoService.java``
getFoodTruckDetails(Long memberId, Long foodTruckId)searchFoodTruckMenus(Long foodTruckId, String keyword, Long memberId) 추가. 멤버 검증 후 Info/Menu 서비스로 위임하여 상세 응답 및 메뉴 검색 수행.
메뉴 서비스/레포지토리
\src/main/java/konkuk/chacall/domain/foodtruck/application/menu/FoodTruckMenuService.java`, `src/main/java/konkuk/chacall/domain/foodtruck/domain/repository/MenuRepository.java``
메뉴 키워드 검색 메서드 searchFoodTruckMenus(...) 및 JPA 쿼리 searchByKeyword(Long, String) 추가(메뉴명 LIKE + 메뉴 노출 상태 ON 필터).
응답 DTO
\src/main/java/konkuk/chacall/domain/foodtruck/presentation/dto/response/FoodTruckDetailResponse.java``
푸드트럭 상세 응답용 record FoodTruckDetailResponse 추가 및 from(...) 팩토리 메서드 구현(도메인 → DTO 매핑, 서비스지역/가능일자/메뉴카테고리/사진/평점 등 조립, isSaved 포함).
도메인 모델
\src/main/java/konkuk/chacall/domain/foodtruck/domain/model/AvailableDate.java`, `src/main/java/konkuk/chacall/domain/foodtruck/domain/model/FoodTruck.java``
AvailableDate.formatDate() 추가; FoodTruck.getAvailableDates(...) 추가; 조회 권한 검증용 validateViewableStatusForMember()validateViewableStatusForOwner(Long) 메서드 추가(멤버/오너/어드민별 검증 분기).
레포지토리 추가 쿼리
\src/main/java/konkuk/chacall/domain/foodtruck/domain/repository/AvailableDateRepository.java`, `src/main/java/konkuk/chacall/domain/member/domain/repository/SavedFoodTruckRepository.java``
findAllByFoodTruckId(Long) 추가(AvailableDate), existsByMemberIdAndFoodTruckId(Long, Long) 추가(SavedFoodTruck) — 쿼리 기반 존재 확인 메서드 도입.
예외 및 Swagger
\src/main/java/konkuk/chacall/global/common/exception/code/ErrorCode.java`, `src/main/java/konkuk/chacall/global/common/swagger/SwaggerResponseDescription.java``
새로운 오류 코드 FOOD_TRUCK_NOT_VIEWABLE 추가 및 Swagger 응답 설명 상수 GET_FOOD_TRUCK_DETAILS, SEARCH_FOOD_TRUCK_MENUS 추가.

Sequence Diagram(s)

sequenceDiagram
    participant C as 클라이언트
    participant Ctrl as FoodTruckController
    participant S as FoodTruckService
    participant V as MemberValidator
    participant Info as FoodTruckInfoService
    participant MenuS as FoodTruckMenuService
    participant Repo as Repositories

    C->>Ctrl: GET /{foodTruckId} (UserId)
    Ctrl->>S: getFoodTruckDetails(memberId, foodTruckId)
    S->>V: validateAndGetMember(memberId)
    V-->>S: Member
    S->>Info: getFoodTruckDetails(member, foodTruckId)
    Info->>Repo: find FoodTruck, serviceAreas, availableDates, saved 여부
    Repo-->>Info: domain 데이터
    Info->>Info: validateViewableStatus(...) / assemble DTO
    Info-->>S: FoodTruckDetailResponse
    S-->>Ctrl: FoodTruckDetailResponse
    Ctrl-->>C: BaseResponse<FoodTruckDetailResponse>

    C->>Ctrl: GET /{foodTruckId}/menus/search?keyword=...
    Ctrl->>S: searchFoodTruckMenus(foodTruckId, keyword, memberId)
    S->>V: validateAndGetMember(memberId)
    V-->>S: Member
    S->>MenuS: searchFoodTruckMenus(foodTruckId, keyword, member)
    MenuS->>Repo: MenuRepository.searchByKeyword(foodTruckId, keyword)
    Repo-->>MenuS: List<Menu>
    MenuS->>MenuS: map to FoodTruckMenuResponse
    MenuS-->>S: List<FoodTruckMenuResponse>
    S-->>Ctrl: List<FoodTruckMenuResponse>
    Ctrl-->>C: BaseResponse<List<FoodTruckMenuResponse>>
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

검토 시 주의할 파일/영역:

  • SavedFoodTruckRepository.existsByMemberIdAndFoodTruckId(...) 쿼리 파라미터 명칭 및 성능 영향
  • FoodTruck.validateViewableStatusForOwner(...)의 소유자 판별 로직과 예외 타입 사용
  • FoodTruckDetailResponse.from(...)의 null 안전성, 컬렉션 매핑 및 날짜 포맷 처리
  • MenuRepository.searchByKeyword(...)의 LIKE 매칭, 인코딩/SQL 주입 방지 및 인덱스 사용

Possibly related PRs

Suggested labels

☺️ 상균

Poem

"당근 단 토끼가 속삭여요,
상세 한입, 메뉴 한입 헤아려요.
멤버 확인하고 슬쩍 전해드려,
지도와 날짜, 메뉴까지 냠냠.
홉! 축하의 깡총, 냠냠 냠 🥕🐇"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed PR 제목 "[FEAT] 푸드트럭 상세조회 API 구현"은 변경 집합의 주요 내용을 정확하게 반영합니다. 실제로 코드 변경 사항은 푸드트럭 상세 조회 API를 구현하고 있으며, 역할별 유효성 검증 로직, 새로운 엔드포인트, DTO 및 관련 서비스 메서드들을 추가하고 있습니다. 추가로 구현된 메뉴 검색 API는 PR 설명에서 별도 항목으로 언급되었으므로, 제목이 모든 세부사항을 다루지 않는 것은 예상된 범위 내입니다. 제목은 간결하고 명확하며 팀 구성원들이 변경의 주요 목적을 빠르게 파악할 수 있습니다.
Linked Issues Check ✅ Passed 연결된 이슈 #53의 공식 설명은 최소한의 정보("ㅈㅁ ㄱㄷㄹ" 및 체크하지 않은 두 개의 TODO)만 포함하고 있습니다. 그러나 PR 설명은 구체적인 요구사항을 명시하고 있습니다: 푸드트럭 상세조회 API 구현(읽기 전용), 사용자 역할별 유효성 검증(일반 사용자: 노출 상태 ON 시에만, 사장님: 본인 소유 시 제한 없음, 관리자: 제한 없음), 메뉴 검색 API 구현(LIKE 쿼리). 코드 변경 사항은 이러한 모든 요구사항을 충족하고 있으며, 적절한 검증 로직과 엔드포인트가 구현되었습니다.
Out of Scope Changes Check ✅ Passed 모든 코드 변경 사항이 PR의 명시된 목표 범위 내에 있습니다. 추가된 메서드들(getFoodTruckDetails, searchFoodTruckMenus, validateViewableStatusForMember 등)과 새로운 DTO(FoodTruckDetailResponse), 저장소 쿼리, 에러 코드, Swagger 설명 모두 푸드트럭 상세조회 및 메뉴 검색 API 구현과 직접 관련이 있습니다. FoodTruckController의 기존 매핑 경로 수정(@PutMapping, @DeleteMapping에 선행 슬래시 추가)은 경로 일관성을 위한 부수적인 개선이며 범위 내로 간주됩니다. 범위를 벗어난 변경사항이 없습니다.
✨ 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 feat/#53-foodtruck-detail-info

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: 4

🧹 Nitpick comments (1)
src/main/java/konkuk/chacall/domain/foodtruck/domain/repository/AvailableDateRepository.java (1)

17-18: Spring Data JPA 메서드 네이밍 규칙을 활용할 수 있습니다.

현재 명시적인 @query를 사용하고 있지만, 메서드 이름이 이미 Spring Data JPA의 네이밍 규칙을 따르고 있어 @query 없이도 자동으로 쿼리가 생성됩니다. @query 어노테이션을 제거해도 동일하게 동작합니다.

-    @Query("SELECT ad FROM AvailableDate ad WHERE ad.foodTruck.foodTruckId = :foodTruckId")
     List<AvailableDate> findAllByFoodTruckId(Long foodTruckId);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11a880e and 926f01e.

📒 Files selected for processing (10)
  • src/main/java/konkuk/chacall/domain/foodtruck/application/FoodTruckService.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/foodtruck/application/info/FoodTruckInfoService.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/foodtruck/domain/model/AvailableDate.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/foodtruck/domain/model/FoodTruck.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/foodtruck/domain/repository/AvailableDateRepository.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/foodtruck/presentation/FoodTruckController.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/foodtruck/presentation/dto/response/FoodTruckDetailResponse.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/member/domain/repository/SavedFoodTruckRepository.java (1 hunks)
  • src/main/java/konkuk/chacall/global/common/exception/code/ErrorCode.java (1 hunks)
  • src/main/java/konkuk/chacall/global/common/swagger/SwaggerResponseDescription.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (10)
src/main/java/konkuk/chacall/domain/foodtruck/domain/model/AvailableDate.java (1)

40-42: 날짜 형식 확인이 필요합니다.

LocalDate의 기본 toString()을 사용하면 ISO-8601 형식(yyyy-MM-dd)으로 출력됩니다. 사용자에게 표시되는 날짜 형식이 이것으로 충분한지 확인해 주세요. 만약 다른 형식(예: yyyy년 MM월 dd일)이 필요하다면 DateTimeFormatter를 사용하여 포맷팅하는 것을 고려해 보세요.

src/main/java/konkuk/chacall/global/common/exception/code/ErrorCode.java (1)

86-86: LGTM!

새로운 에러 코드가 기존 패턴을 잘 따르고 있으며, 푸드트럭 관련 에러 코드 체계에 적절히 추가되었습니다.

src/main/java/konkuk/chacall/domain/foodtruck/application/FoodTruckService.java (1)

82-86: LGTM!

서비스 계층의 위임 패턴이 적절하게 구현되었습니다. 멤버 검증 후 Info 서비스로 위임하는 구조가 기존 패턴과 일관성 있게 작성되었습니다.

src/main/java/konkuk/chacall/domain/foodtruck/presentation/FoodTruckController.java (1)

133-144: LGTM!

새로운 엔드포인트가 기존 컨트롤러 패턴을 잘 따르고 있으며, Swagger 문서화도 적절히 작성되었습니다.

src/main/java/konkuk/chacall/global/common/swagger/SwaggerResponseDescription.java (1)

249-255: LGTM!

새로운 API 엔드포인트에 대한 Swagger 응답 설명이 적절히 추가되었습니다. 필요한 모든 에러 코드가 포함되어 있습니다.

src/main/java/konkuk/chacall/domain/foodtruck/application/info/FoodTruckInfoService.java (1)

138-154: 역할 기반 접근 제어 로직이 잘 구현되었습니다.

위에서 지적한 오타와 리포지토리 버그를 수정하면, 역할별(일반 유저, 사장님, 관리자) 검증 로직이 PR 목표에 부합하게 잘 구현되었습니다. Switch 표현식을 사용하여 각 역할에 맞는 검증을 명확하게 분리한 점이 좋습니다.

src/main/java/konkuk/chacall/domain/foodtruck/domain/model/FoodTruck.java (2)

146-151: 구현이 잘 되어 있습니다.

AvailableDate::formatDate를 활용하여 날짜 리스트를 포맷팅하는 로직이 깔끔하고 명확합니다.


166-170: 일반 유저 검증 로직이 올바르게 구현되었습니다.

푸드트럭 노출 상태가 ON이 아닐 때 예외를 발생시키는 로직이 PR 목표와 일치합니다.

src/main/java/konkuk/chacall/domain/foodtruck/presentation/dto/response/FoodTruckDetailResponse.java (2)

11-46: DTO 구조가 잘 설계되었습니다.

모든 필드가 적절한 타입으로 정의되어 있고, Swagger 스키마 어노테이션도 명확하게 작성되어 있습니다. 푸드트럭 상세 정보를 표현하기에 충분한 필드들이 포함되어 있습니다.


47-68: 팩토리 메서드가 올바르게 구현되었습니다.

도메인 모델로부터 DTO를 생성하는 로직이 명확하고, getServiceAreasgetAvailableDates 같은 도메인 메서드를 적절히 활용하고 있습니다. 모든 필드 매핑이 정확합니다.

List<FoodTruckServiceArea> foodTruckServiceAreas = foodTruckServiceAreaRepository.findAllByFoodTruckId(foodTruckId);
List<AvailableDate> availableDates = availableDateRepository.findAllByFoodTruckId(foodTruckId);

boolean isSaved = savedFoodTruckRepository.existsByMemberIdAndFoodTruckId(member.getUserId(), foodTruckId);
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

SavedFoodTruckRepository의 버그로 인해 이 코드가 실패합니다.

existsByMemberIdAndFoodTruckId 메서드에 파라미터 이름 불일치 버그가 있어, 이 줄이 실행될 때 런타임 오류가 발생합니다. SavedFoodTruckRepository.java 파일의 해당 메서드를 먼저 수정해야 합니다.

🤖 Prompt for AI Agents
In
src/main/java/konkuk/chacall/domain/foodtruck/application/info/FoodTruckInfoService.java
around line 151, the call to
savedFoodTruckRepository.existsByMemberIdAndFoodTruckId(member.getUserId(),
foodTruckId) fails at runtime because SavedFoodTruckRepository has a
parameter-name mismatch bug; open
src/main/java/konkuk/chacall/domain/foodtruck/repository/SavedFoodTruckRepository.java,
fix the method signature/parameter names to match memberId and foodTruckId (and
any @Param annotations if using JPQL/Query), rebuild so the
existsByMemberIdAndFoodTruckId method accepts the correct parameters and the
runtime error is resolved.

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

♻️ Duplicate comments (2)
src/main/java/konkuk/chacall/domain/foodtruck/application/info/FoodTruckInfoService.java (2)

146-146: 메서드 이름에 오타가 있습니다.

Line 146의 vaildateViewableStatusForOwnervalidateViewableStatusForOwner의 오타입니다. 이는 컴파일 오류를 발생시킵니다.

-            case OWNER -> foodTruck.vaildateViewableStatusForOwner(member.getUserId());
+            case OWNER -> foodTruck.validateViewableStatusForOwner(member.getUserId());

153-153: SavedFoodTruckRepository의 버그로 인해 런타임 오류가 발생할 수 있습니다.

existsByMemberIdAndFoodTruckId 메서드에 파라미터 이름 불일치 문제가 있어 런타임 오류가 발생할 수 있습니다. SavedFoodTruckRepository의 해당 메서드를 먼저 수정해야 합니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 926f01e and 636caa4.

📒 Files selected for processing (6)
  • src/main/java/konkuk/chacall/domain/foodtruck/application/FoodTruckService.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/foodtruck/application/info/FoodTruckInfoService.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/foodtruck/application/menu/FoodTruckMenuService.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/foodtruck/domain/repository/MenuRepository.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/foodtruck/presentation/FoodTruckController.java (4 hunks)
  • src/main/java/konkuk/chacall/global/common/swagger/SwaggerResponseDescription.java (1 hunks)
🔇 Additional comments (7)
src/main/java/konkuk/chacall/domain/foodtruck/application/FoodTruckService.java (1)

84-94: LGTM!

두 메서드 모두 적절한 회원 검증 후 하위 서비스로 올바르게 위임하고 있습니다. 구현이 깔끔하고 명확합니다.

src/main/java/konkuk/chacall/domain/foodtruck/application/info/FoodTruckInfoService.java (1)

138-156: 역할별 검증 로직이 PR 목표에 맞게 잘 구현되었습니다.

Line 146의 오타와 Line 153의 repository 이슈만 수정하면, 전반적인 로직 구조는 PR 목표에 명시된 역할별 유효성 검증 요구사항을 올바르게 구현하고 있습니다.

src/main/java/konkuk/chacall/global/common/swagger/SwaggerResponseDescription.java (1)

249-261: LGTM!

새로운 엔드포인트에 대한 Swagger 응답 설명이 적절한 에러 코드와 함께 올바르게 정의되었습니다.

src/main/java/konkuk/chacall/domain/foodtruck/presentation/FoodTruckController.java (4)

111-111: 경로 일관성 개선이 좋습니다.

@PutMapping에 leading slash를 추가하여 다른 엔드포인트와의 일관성이 향상되었습니다.


125-125: 경로 일관성 개선이 좋습니다.

@DeleteMapping에 leading slash를 추가하여 다른 엔드포인트와의 일관성이 향상되었습니다.


135-146: LGTM!

푸드트럭 상세조회 엔드포인트가 적절한 Swagger 문서화 및 예외 처리와 함께 올바르게 구현되었습니다.


148-160: LGTM!

메뉴 검색 엔드포인트가 적절한 파라미터 설명 및 Swagger 문서화와 함께 올바르게 구현되었습니다.

Comment on lines +51 to +61
public List<FoodTruckMenuResponse> searchFoodTruckMenus(Long foodTruckId, String keyword, User member) {
if(!foodTruckRepository.existsById(foodTruckId)) {
throw new EntityNotFoundException(ErrorCode.FOOD_TRUCK_NOT_FOUND);
}

List<Menu> menus = menuRepository.searchByKeyword(foodTruckId, keyword);

return menus.stream()
.map(FoodTruckMenuResponse::from)
.toList();
}
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

PR 목표에 명시된 역할별 유효성 검증 로직이 누락되었습니다.

PR 설명에 따르면 다음과 같은 역할별 검증이 필요합니다:

  • 일반 유저: 푸드트럭 노출 상태가 ON인 경우에만 조회 가능
  • 사장님: 본인 소유 푸드트럭이면 노출 상태와 상관없이 조회 가능
  • 관리자: 제한 없음

현재 구현은 member 파라미터를 받지만 전혀 사용하지 않으며, 푸드트럭 노출 상태 및 소유권 검증이 없습니다. getFoodTruckDetails 메서드와 유사한 역할별 검증 로직이 필요합니다.

다음과 같이 수정하세요:

 public List<FoodTruckMenuResponse> searchFoodTruckMenus(Long foodTruckId, String keyword, User member) {
-    if(!foodTruckRepository.existsById(foodTruckId)) {
-        throw new EntityNotFoundException(ErrorCode.FOOD_TRUCK_NOT_FOUND);
-    }
+    FoodTruck foodTruck = foodTruckRepository.findById(foodTruckId)
+            .orElseThrow(() -> new EntityNotFoundException(ErrorCode.FOOD_TRUCK_NOT_FOUND));
+
+    foodTruck.validateApprovedStatus();
+
+    switch(member.getRole()) {
+        case MEMBER -> foodTruck.validateViewableStatusForMember();
+        case OWNER -> foodTruck.validateViewableStatusForOwner(member.getUserId());
+        case ADMIN -> {}
+    }

     List<Menu> menus = menuRepository.searchByKeyword(foodTruckId, keyword);

     return menus.stream()
             .map(FoodTruckMenuResponse::from)
             .toList();
 }

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

🤖 Prompt for AI Agents
In
src/main/java/konkuk/chacall/domain/foodtruck/application/menu/FoodTruckMenuService.java
around lines 51 to 61, the method ignores the member parameter and omits
role-based validation: load the FoodTruck entity by id (throw
FOOD_TRUCK_NOT_FOUND if absent), then apply the same role-based access rules as
getFoodTruckDetails — if member is ADMIN allow, if member is OWNER allow only
when member.id equals foodTruck.ownerId, otherwise (regular user) allow only
when foodTruck.displayStatus (or equivalent visibility flag) is ON; if access is
denied throw appropriate exception (e.g., ACCESS_DENIED or
FOOD_TRUCK_NOT_VISIBLE). After validation, query menuRepository.searchByKeyword
and map to responses as before.

Comment on lines 74 to 81
@Query("""
select m
from Menu m
where m.foodTruck.foodTruckId = :foodTruckId
and m.name like concat('%', :keyword, '%')
and m.menuViewedStatus = konkuk.chacall.domain.foodtruck.domain.value.MenuViewedStatus.ON
""")
List<Menu> searchByKeyword(Long foodTruckId, String keyword);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

검색 결과에 페이지네이션이 없어 성능 문제 가능성이 있습니다.

키워드 검색 결과에 제한이 없어 대량의 메뉴가 있는 푸드트럭의 경우 많은 데이터를 반환할 수 있습니다. 또한 키워드가 null이거나 빈 문자열일 때의 처리가 없습니다.

다음 개선사항을 고려해주세요:

  1. 결과 개수 제한 추가 (예: TOP 50)
  2. 키워드 검증 로직 추가 (null/empty 체크)
 @Query("""
         select m
         from Menu m
         where m.foodTruck.foodTruckId = :foodTruckId
           and m.name like concat('%', :keyword, '%')
           and m.menuViewedStatus = konkuk.chacall.domain.foodtruck.domain.value.MenuViewedStatus.ON
+        order by m.menuId desc
         """)
-List<Menu> searchByKeyword(Long foodTruckId, String keyword);
+List<Menu> searchByKeyword(@Param("foodTruckId") Long foodTruckId, @Param("keyword") String keyword, Pageable pageable);

또는 서비스 레이어에서 키워드 검증을 추가하세요.

🤖 Prompt for AI Agents
In
src/main/java/konkuk/chacall/domain/foodtruck/domain/repository/MenuRepository.java
around lines 74-81, the keyword search query returns unlimited results and does
not handle null/empty keywords; change the repository method to support
pagination (add a Pageable parameter and return Page<Menu> or List<Menu> with
Pageable) so callers can limit results (e.g., page size 50), and add keyword
validation in the service layer (or repository caller) to check for null/empty
and return an empty list or a controlled response instead of executing the query
when keyword is blank.

ksg1227
ksg1227 previously approved these changes Oct 30, 2025
Copy link
Contributor

@ksg1227 ksg1227 left a comment

Choose a reason for hiding this comment

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

확인했습니다! 전체적으로 잘 구현해주셔서 건드릴 곳이 없네용
피드백 하나만 남겨두겠습니다~

Comment on lines +166 to +176
public void validateViewableStatusForMember() {
if (this.foodTruckViewedStatus != FoodTruckViewedStatus.ON) {
throw new DomainRuleException(ErrorCode.FOOD_TRUCK_NOT_VIEWABLE);
}
}

public void validateViewableStatusForOwner(Long userId) {
if(!isOwnedBy(userId)) { // 자신이 소유한 푸드트럭이 아니면
validateViewableStatusForMember();
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

검증 로직 따로 뺀 것 좋습니다~

description = "푸드트럭의 상세 정보를 조회합니다."
)
@ExceptionDescription(SwaggerResponseDescription.GET_FOOD_TRUCK_DETAILS)
@GetMapping("/{foodTruckId}/details")
Copy link
Contributor

Choose a reason for hiding this comment

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

푸드트럭 상세 조회 API 의 경우 그냥 /food-trucks/{foodTruckId} 로 엔드포인트를 설정해둬 괜찮을 것 같다는 생각이 드는데 어떠신가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

넵 엔드포인트 간소화시키는게 추후에 더 좋을 것 같네요. 수정하겠습니다~

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: 1

🧹 Nitpick comments (1)
src/main/java/konkuk/chacall/domain/foodtruck/presentation/FoodTruckController.java (1)

135-146: 엔드포인트 순서 정리 제안

기능상 문제는 없으나, 같은 경로(/{foodTruckId})에 대한 GET 메서드가 PUT 메서드 이후에 위치해 있습니다.

HTTP 메서드 순서(GET → PUT → DELETE)나 리소스 계층 구조에 따라 정렬하면 가독성이 향상될 수 있습니다. 예를 들어, 상세 조회(GET)를 수정(PUT) 앞에 배치하는 것을 고려해 보세요.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b53bdf1 and cb6894b.

📒 Files selected for processing (1)
  • src/main/java/konkuk/chacall/domain/foodtruck/presentation/FoodTruckController.java (4 hunks)
🔇 Additional comments (3)
src/main/java/konkuk/chacall/domain/foodtruck/presentation/FoodTruckController.java (3)

28-28: LGTM: 필요한 import 추가

새로운 메뉴 검색 엔드포인트의 List<FoodTruckMenuResponse> 반환 타입을 위해 필요한 import입니다.


111-111: LGTM: 경로 매핑 일관성 개선

경로에 leading slash를 추가하여 Spring의 베스트 프랙티스를 따르고 있으며, 클래스 내 다른 엔드포인트들과의 일관성이 향상되었습니다.

Also applies to: 125-125


135-146: LGTM: 푸드트럭 상세조회 엔드포인트 구현

엔드포인트가 RESTful 원칙을 따르며 기존 패턴과 일관성 있게 구현되었습니다. 이전 리뷰에서 논의된 대로 경로가 /food-trucks/{foodTruckId}로 간소화되어 더욱 명확합니다.

Comment on lines +148 to +160
@Operation(
summary = "푸드트럭 메뉴 검색",
description = "푸드트럭 메뉴를 이름으로 검색합니다."
)
@ExceptionDescription(SwaggerResponseDescription.SEARCH_FOOD_TRUCK_MENUS)
@GetMapping("/{foodTruckId}/menus/search")
public BaseResponse<List<FoodTruckMenuResponse>> searchFoodTruckMenus(
@Parameter(description = "푸드트럭 ID", example = "1") @PathVariable final Long foodTruckId,
@Parameter(description = "검색 키워드", example = "치킨") @RequestParam("keyword") final String keyword,
@Parameter(hidden = true) @UserId final Long memberId
) {
return BaseResponse.ok(foodTruckService.searchFoodTruckMenus(foodTruckId, keyword, memberId));
}
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

빈 문자열 검증 확인 필요

메뉴 검색 엔드포인트가 잘 구현되어 있으나, keyword 파라미터가 빈 문자열("")로 전달될 경우의 처리를 확인해 주세요.

빈 문자열로 검색 시 의도하지 않은 결과(예: 모든 메뉴 반환)가 발생할 수 있습니다. 필요시 @RequestParam 레벨 또는 서비스 레이어에서 @NotBlank 검증을 추가하는 것을 고려해 주세요.

검증 스크립트로 서비스 레이어에서 키워드 검증이 있는지 확인:


🏁 Script executed:

#!/bin/bash
# Description: Check if keyword validation exists in service layer

# Search for searchFoodTruckMenus method implementation
ast-grep --pattern $'searchFoodTruckMenus($$$) {
  $$$
}'

# Also check for blank validation patterns
rg -nP --type=java -A10 'searchFoodTruckMenus.*keyword' -g '!**/test/**'

Length of output: 2621


키워드 빈 문자열 검증 필요

코드 검토 결과, searchFoodTruckMenus 메서드에서 keyword 파라미터가 빈 문자열("")로 전달될 경우 SQL LIKE 쿼리가 모든 메뉴 레코드를 반환할 수 있습니다.

현재 구현:

  • Controller (159줄): 검증 없이 keyword를 서비스로 전달
  • FoodTruckService (90-94줄): memberId만 검증, 바로 위임
  • FoodTruckMenuService (51-61줄): menuRepository.searchByKeyword(foodTruckId, keyword) 직접 호출

해결 방안
Controller의 @RequestParam@NotBlank 추가하거나 서비스 레이어에서 빈 문자열 체크를 구현하세요.

🤖 Prompt for AI Agents
In
src/main/java/konkuk/chacall/domain/foodtruck/presentation/FoodTruckController.java
around lines 148-160, the keyword RequestParam is not validated so an empty
string can lead to unintended SQL LIKE results; add validation to reject blank
keywords (e.g., annotate the controller method/parameter with @NotBlank and
ensure the controller class is @Validated) or perform a manual check (trim the
keyword, if blank throw a 400 BadRequest with a clear message) before calling
the service so only non-empty search terms are passed to FoodTruckService.

@buzz0331 buzz0331 merged commit 0bfaec9 into develop Oct 30, 2025
2 checks passed
@buzz0331 buzz0331 deleted the feat/#53-foodtruck-detail-info branch October 30, 2025 07:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 푸드트럭 상세조회 api 구현

2 participants