[FEAT] 일반 유저 - 예약 목록 및 상세정보 조회 api 구현#20
Conversation
Walkthrough회원 예약 목록/상세 조회 기능이 추가되었습니다. 컨트롤러와 서비스에 엔드포인트 및 위임 로직이 도입되었고, 예약 레포지토리에 커서 기반 조회가 추가되었습니다. 응답/요청 DTO 신설, Reservation/ReservationInfo 보조 메서드 추가, 일부 레포지토리 페치 전략을 EntityGraph로 변경, Swagger 주석 형식이 정리되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant C as Client
participant MC as MemberController
participant MS as MemberService
participant MRS as MemberReservationService
participant RR as ReservationRepository
rect rgb(240,248,255)
note over C,MC: GET /members/me/reservations (무한스크롤)
C->>MC: GetReservationHistoryRequest
MC->>MS: getMemberReservations(request, memberId)
MS->>MS: 멤버 검증
MS->>MRS: getMemberReservations(member, request.status, lastCursor, pageSize)
MRS->>RR: findMemberReservationsByStatusWithCursor(memberId, status, lastCursor, pageable)
RR-->>MRS: Slice<Reservation{foodTruck}>
MRS-->>MS: CursorPagingResponse<MemberReservationHistoryResponse>
MS-->>MC: BaseResponse<CursorPagingResponse<...>>
MC-->>C: 200 OK
end
rect rgb(245,255,250)
note over C,MC: GET /members/me/reservations/{reservationId}
C->>MC: reservationId
MC->>MS: getMemberReservationDetail(reservationId, memberId)
MS->>MS: 멤버 검증
MS->>MRS: getMemberReservationDetail(reservationId, member)
MRS->>RR: findById(reservationId) (연관 로딩 포함)
RR-->>MRS: Reservation{member, foodTruck}
MRS->>MRS: reservation.isReservedBy(memberId) 확인
alt 소유자 아님
MRS-->>MS: BusinessException
MS-->>MC: 에러 응답
MC-->>C: 403/404
else 소유자 맞음
MRS-->>MS: MemberReservationDetailResponse
MS-->>MC: BaseResponse<...>
MC-->>C: 200 OK
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings, 1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (17)
src/main/java/konkuk/chacall/domain/user/presentation/UserController.java (2)
25-28: Swagger @operation 멀티라인 포맷 변경 OK동작 변화 없이 가독성만 개선된 것으로 보입니다. 필요 시 @ApiResponses/@apiresponse로 성공/에러 스펙을 명시해 주면 문서 품질이 더 좋아집니다.
37-40: updateUserInfo의 응답 설계 검토 제안BaseResponse.ok(null) 대신 204 No Content를 고려하면 불필요한 payload를 줄일 수 있습니다. API 일관성 측면에서 팀 컨벤션 확인 바랍니다.
src/main/java/konkuk/chacall/domain/reservation/domain/model/Reservation.java (1)
52-54: 소유자 확인 메서드 안정성 보강 제안현재 구현은 정상이나, 방어적 차원에서 NPE 방지를 위해 Objects.equals 사용을 권장합니다.
- public boolean isReservedBy(Long userId) { - return this.member.getUserId().equals(userId); - } + public boolean isReservedBy(Long userId) { + return this.member != null && java.util.Objects.equals(this.member.getUserId(), userId); + }src/main/java/konkuk/chacall/domain/member/domain/repository/SavedFoodTruckRepository.java (1)
21-29: 첫 페이지(lastCursor null) 처리 및 커서 조건 보강 제안lastCursor가 null일 경우 조회가 불가능합니다. JPQL에 null 허용 조건을 추가하면 최초 페이지 로딩이 쉬워집니다.
- @Query("SELECT sft FROM SavedFoodTruck sft " + - "WHERE sft.member = :member " + - "AND sft.savedFoodTruckId < :lastCursor " + - "ORDER BY sft.savedFoodTruckId DESC") + @Query("SELECT sft FROM SavedFoodTruck sft " + + "WHERE sft.member = :member " + + "AND (:lastCursor IS NULL OR sft.savedFoodTruckId < :lastCursor) " + + "ORDER BY sft.savedFoodTruckId DESC")추가로 savedFoodTruckId DESC + range 조건을 활용 중이므로 해당 컬럼 인덱스가 있는지 확인 부탁드립니다.
src/main/java/konkuk/chacall/domain/member/domain/repository/RatingRepository.java (1)
17-21: @Param 누락 가능성 — 파라미터 바인딩 안전성 확보컴파일 옵션(-parameters)에 의존하지 않도록 @Param("member")를 명시해 주세요. 런타임 바인딩 오류를 예방합니다.
- List<Rating> findAllByMemberAndIsRatedFalse(User member); + List<Rating> findAllByMemberAndIsRatedFalse(@org.springframework.data.repository.query.Param("member") User member);src/main/java/konkuk/chacall/domain/reservation/domain/value/ReservationInfo.java (3)
51-53: 네이밍 미세개선 제안parsingIsUserElectricity → formatElectricityInfo 처럼 “parsing”보다 “format” 계열 네이밍이 의도(표시용 가공)를 더 잘 드러냅니다. 선택사항입니다.
55-57: 금액 표기 천단위 구분자 적용 제안“50000원” 대신 “50,000원” 형태가 일반적입니다. 간단히 NumberFormat을 적용하세요.
- public String parsingReservationDeposit() { - return reservationDeposit + "원"; - } + public String parsingReservationDeposit() { + java.text.NumberFormat nf = java.text.NumberFormat.getInstance(java.util.Locale.KOREA); + return nf.format(reservationDeposit) + "원"; + }
9-11: 불필요한 import 정리org.apache.catalina.LifecycleState, java.time.LocalDate는 사용되지 않습니다. 제거해 주세요.
-import org.apache.catalina.LifecycleState; - -import java.time.LocalDate;src/main/java/konkuk/chacall/domain/reservation/domain/repository/ReservationRepository.java (1)
36-46: 멤버 예약 커서 조회: null 커서 허용 및 N+1 점검
- lastCursor null 시 첫 페이지 조회가 불가합니다. null 허용 조건을 추가하세요.
- DTO에서 foodTruck의 대표 사진 접근 시 추가 연관 로딩이 필요하다면 EntityGraph에 연쇄 경로를 포함해 N+1을 방지하세요(예: foodTruck.photoList 등, 실제 필드명 확인 필요).
- @Query("SELECT r FROM Reservation r " + - "WHERE r.member.userId = :memberId " + - "AND r.reservationStatus = :status " + - "AND r.reservationId < :lastCursor " + - "ORDER BY r.reservationId DESC") + @Query("SELECT r FROM Reservation r " + + "WHERE r.member.userId = :memberId " + + "AND r.reservationStatus = :status " + + "AND (:lastCursor IS NULL OR r.reservationId < :lastCursor) " + + "ORDER BY r.reservationId DESC")src/main/java/konkuk/chacall/domain/member/presentation/dto/request/MemberReservationHistoryResponse.java (2)
23-33: 대표 사진 접근 시 NPE 방지foodTruckPhotoList 또는 mainPhotoUrl이 null일 가능성에 대비한 안전 가드가 필요합니다. 기본 이미지 사용 정책이 있다면 그 URL을 적용하세요.
- public static MemberReservationHistoryResponse of(Reservation reservation, FoodTruck foodTruck) { - List<String> dateTimeList = reservation.getReservationInfo().getFormattedDateTimeInfos(); - - return new MemberReservationHistoryResponse( - reservation.getReservationId(), - foodTruck.getFoodTruckPhotoList().getMainPhotoUrl(), - foodTruck.getName(), - reservation.getReservationInfo().getReservationAddress(), - dateTimeList - ); - } + public static MemberReservationHistoryResponse of(Reservation reservation, FoodTruck foodTruck) { + List<String> dateTimeList = reservation.getReservationInfo().getFormattedDateTimeInfos(); + String mainPhotoUrl = null; + if (foodTruck.getFoodTruckPhotoList() != null) { + mainPhotoUrl = foodTruck.getFoodTruckPhotoList().getMainPhotoUrl(); + } + return new MemberReservationHistoryResponse( + reservation.getReservationId(), + mainPhotoUrl, + foodTruck.getName(), + reservation.getReservationInfo().getReservationAddress(), + dateTimeList + ); + }
18-20: 스키마 설명(최대 2개)와 실제 데이터 제한 불일치문서에 “최대 2개”라고 되어 있으나 제한 로직이 없습니다. 스트림에서 limit(2) 적용을 권장합니다.
- List<String> dateTimeList = reservation.getReservationInfo().getFormattedDateTimeInfos(); + List<String> dateTimeList = reservation.getReservationInfo() + .getFormattedDateTimeInfos() + .stream() + .limit(2) + .toList();스펙상 ‘최대 2개’가 진짜 비즈니스 제약인지(백엔드에서 강제) 혹은 문서 표현인지(프론트 가이드) 확인 부탁드립니다.
src/main/java/konkuk/chacall/domain/member/presentation/dto/request/MemberReservationDetailResponse.java (2)
9-39: 패키지/네이밍 정합성Response DTO가
dto.request패키지에 위치합니다.dto.response로 이동하는 것이 일관성 측면에서 바람직합니다.
41-55: 사진 NPE 가드 추가 — PDF 게터명(getPdfUrl) 확인 완료foodTruck.getFoodTruckPhotoList()가 null이면 NPE 발생 가능하므로 아래 패치 적용 권장. reservation.getPdfUrl()는 코드베이스에서 일관되게 사용되고 있어 변경 불필요합니다.
public static MemberReservationDetailResponse of(Reservation reservation, FoodTruck foodTruck) { List<String> dateTimeList = reservation.getReservationInfo().getFormattedDateTimeInfos(); + String photoUrl = (foodTruck.getFoodTruckPhotoList() == null) + ? null + : foodTruck.getFoodTruckPhotoList().getMainPhotoUrl(); return new MemberReservationDetailResponse( - foodTruck.getFoodTruckPhotoList().getMainPhotoUrl(), + photoUrl, foodTruck.getName(), reservation.getReservationInfo().getReservationAddress(), dateTimeList, reservation.getPdfUrl(), reservation.getReservationInfo().getMenu(), reservation.getReservationInfo().parsingReservationDeposit(), reservation.getReservationInfo().parsingIsUserElectricity(), reservation.getReservationInfo().getEtcRequest() ); }src/main/java/konkuk/chacall/domain/member/presentation/MemberController.java (1)
96-106: 예약 상세 API: 예외 스키마 명시 권장
RESERVATION_NOT_FOUND,RESERVATION_NOT_OWNED에 대한@ExceptionDescription추가 시 문서 신뢰도가 높아집니다.src/main/java/konkuk/chacall/domain/member/application/reservation/MemberReservationService.java (2)
40-49: 소유권 검증 및 상세 매핑 흐름 적절엔티티 조회 → 소유권 체크 → DTO 매핑 순서 명확합니다. 다만 현재 쿼리에 불필요한
memberJOIN이 포함되어 있다면, 멤버 전용 상세 조회용 경량 쿼리(예:findByIdWithFoodTruck)로 분리해도 좋습니다.
28-38: 확인: 리포지토리 쿼리에서 정렬·커서 보장됨 — pageSize 상한 추가 필요
- 정렬·커서: src/main/java/konkuk/chacall/domain/reservation/domain/repository/ReservationRepository.java (Query에
AND r.reservationId < :lastCursor ORDER BY r.reservationId DESC) — 현재 쿼리에서 커서 조건과 정렬이 보장됩니다.- 페이지 크기 제약: src/main/java/konkuk/chacall/global/common/dto/CursorPagingRequest.java에는
@Min(1)만 존재(하한 OK), 상한(@Max) 없음. 조치: CursorPagingRequest.size에@Max(예:100)추가하거나 서비스 호출부에서pageSize = Math.min(pageSize, MAX_PAGE_SIZE)로 클램프 적용.src/main/java/konkuk/chacall/domain/member/presentation/dto/request/GetReservationHistoryRequest.java (1)
18-21: 중첩 페이징 기본값은 안전하나 size 상한 미정 — 상한 추가 권장HasPaging#pagingOrDefault()는 cursorPagingRequest()가 null일 때 new CursorPagingRequest(null, null)를 반환하고, CursorPagingRequest의 생성자에서 cursor=Long.MAX_VALUE와 size=20으로 채워 기본값 제공은 안전합니다. 다만 size에 대한 상한(@max 또는 MAX_PAGE_SIZE 상수 및 검증)이 정의되어 있지 않으므로 과도한 요청을 막기 위해 상한을 추가하세요.
수정 위치: src/main/java/konkuk/chacall/global/common/dto/CursorPagingRequest.java
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
src/main/java/konkuk/chacall/domain/member/application/MemberService.java(3 hunks)src/main/java/konkuk/chacall/domain/member/application/reservation/MemberReservationService.java(1 hunks)src/main/java/konkuk/chacall/domain/member/domain/repository/RatingRepository.java(2 hunks)src/main/java/konkuk/chacall/domain/member/domain/repository/SavedFoodTruckRepository.java(2 hunks)src/main/java/konkuk/chacall/domain/member/presentation/MemberController.java(6 hunks)src/main/java/konkuk/chacall/domain/member/presentation/dto/request/GetReservationHistoryRequest.java(1 hunks)src/main/java/konkuk/chacall/domain/member/presentation/dto/request/MemberReservationDetailResponse.java(1 hunks)src/main/java/konkuk/chacall/domain/member/presentation/dto/request/MemberReservationHistoryResponse.java(1 hunks)src/main/java/konkuk/chacall/domain/owner/presentation/dto/response/OwnerReservationDetailResponse.java(1 hunks)src/main/java/konkuk/chacall/domain/reservation/domain/model/Reservation.java(1 hunks)src/main/java/konkuk/chacall/domain/reservation/domain/repository/ReservationRepository.java(2 hunks)src/main/java/konkuk/chacall/domain/reservation/domain/value/ReservationInfo.java(1 hunks)src/main/java/konkuk/chacall/domain/user/presentation/UserController.java(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/konkuk/chacall/domain/member/application/reservation/MemberReservationService.java (2)
src/main/java/konkuk/chacall/global/common/exception/EntityNotFoundException.java (1)
EntityNotFoundException(6-11)src/main/java/konkuk/chacall/domain/member/application/MemberService.java (1)
Service(18-74)
🔇 Additional comments (9)
src/main/java/konkuk/chacall/domain/owner/presentation/dto/response/OwnerReservationDetailResponse.java (1)
52-54: 표시 로직의 도메인 이동 OKReservationInfo의 포맷터를 재사용하도록 정리된 점 좋습니다. Member/Owner 응답 간 표현 일관성 유지에 도움이 됩니다.
현재 getFormattedDateTimeInfos()가 “yyyy.MM.dd ~ yyyy.MM.dd 13시~19시” 형태를 반환합니다. 스키마 예시와 실제 포맷이 일치하는지 문서/클라이언트 측 기대치 확인 부탁드립니다.
src/main/java/konkuk/chacall/domain/member/application/MemberService.java (2)
24-24: 의존성 주입 정합성 OK
MemberReservationService주입 및 사용 흐름이 자연스럽습니다.
68-73: 상세 조회 위임 흐름 적절멤버 검증 후 서비스 계층으로 위임하는 구조가 명확합니다.
src/main/java/konkuk/chacall/domain/member/presentation/MemberController.java (5)
30-33: Swagger 주석 정리 LGTM가독성 개선에 동의합니다.
44-47: Swagger 주석 정리 LGTM변경 내용 문제 없습니다.
57-60: Swagger 주석 정리 LGTM문제 없습니다.
71-74: Swagger 주석 정리 LGTM문제 없습니다.
83-94: 예약 내역 목록 API — 예외 주석 추가 및 중첩 쿼리파라미터 노출 확인
- MemberController#getMemberReservations에 @ExceptionDescription이 없습니다. OwnerController의 사례와 동일하게 예외 스키마 주석을 추가하세요. (파일: src/main/java/konkuk/chacall/domain/member/presentation/MemberController.java — getMemberReservations)
- GetReservationHistoryRequest는 CursorPagingRequest(cursorPagingRequest)를 포함합니다. 현재 컨트롤러 파라미터에만 @ParameterObject가 적용되어 있어 springdoc가 중첩 필드(cursor, size)를 의도대로 노출하는지 확인해야 합니다. 노출되지 않으면 GetReservationHistoryRequest의 cursorPagingRequest 구성요소에 @ParameterObject를 추가하거나 컨트롤러에서 CursorPagingRequest를 직접 수신하도록 변경하세요. (파일: src/main/java/konkuk/chacall/domain/member/presentation/dto/request/GetReservationHistoryRequest.java, CursorPagingRequest: src/main/java/konkuk/chacall/global/common/dto/CursorPagingRequest.java)
- 검증 방법: 빌드 후 OpenAPI 스펙 또는 swagger-ui에서 cursor/size 쿼리파라미터가 정상 노출되는지 확인하세요.
src/main/java/konkuk/chacall/domain/member/presentation/dto/request/GetReservationHistoryRequest.java (1)
11-16: 확인 완료 — allowableValues가 Enum과 일치함
GetReservationHistoryRequest의 allowableValues(PENDING,CONFIRMED,CANCELLED)이 ReservationStatus enum(PENDING, CONFIRMED, CANCELLED)과 정확히 일치하므로 변경 불필요.
| public CursorPagingResponse<MemberReservationHistoryResponse> getMemberReservations(GetReservationHistoryRequest request, Long memberId) { | ||
| // 멤버 유효성 검사 및 조회 | ||
| User member = memberValidator.validateAndGetMember(memberId); | ||
|
|
||
| CursorPagingRequest cursorPagingRequest = request.pagingOrDefault(); | ||
|
|
||
| return memberReservationService.getMemberReservations(member, request, cursorPagingRequest.cursor(), cursorPagingRequest.size()); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
페이지 크기 상한 및 기본값 보장 확인 필요
request.pagingOrDefault()와 cursorPagingRequest.size()에 상한/하한 검증이 내장됐는지 확인해 주세요. 과도한 size는 데이터베이스/네트워크 부하를 유발할 수 있습니다.
아래 스크립트로 CursorPagingRequest 제약과 HasPaging#pagingOrDefault 존재 여부를 점검해 주세요.
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# CursorPagingRequest 정의 및 size 제약(@Min/@Max 등) 확인
rg -nP --type=java 'record\s+CursorPagingRequest\b|class\s+CursorPagingRequest\b' -C3
rg -n --type=java '@Min|@Max|MAX_PAGE_SIZE|\bsize\s*\(' -C2
# HasPaging 인터페이스에 pagingOrDefault 기본 메서드 있는지 확인
rg -n --type=java 'interface\s+HasPaging\b|default\s+pagingOrDefault\s*\(' -C3Length of output: 7990
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== CursorPagingRequest.java ==="
sed -n '1,240p' src/main/java/konkuk/chacall/global/common/dto/CursorPagingRequest.java || true
echo
echo "=== HasPaging.java ==="
sed -n '1,240p' src/main/java/konkuk/chacall/global/common/dto/HasPaging.java || true
echo
echo "=== SavedFoodTruckService.java (for PageRequest usage) ==="
sed -n '1,240p' src/main/java/konkuk/chacall/domain/member/application/foodtruck/SavedFoodTruckService.java || true
echo
echo "=== Search for MAX/DEFAULT constants ==="
rg -n --hidden --no-ignore 'MAX_PAGE_SIZE|DEFAULT_PAGE_SIZE|DEFAULT_SIZE|MAX_SIZE|MAX_PAGE' || trueLength of output: 5007
상한값 미적용 — CursorPagingRequest에 최대 페이지 크기 제한(또는 서비스 레벨 클램프) 적용 필요
검증 결과: CursorPagingRequest는 @min(1) 및 DEFAULT_SIZE(20)를 가지나 상한(@max 또는 MAX_SIZE)이 없음. HasPaging.pagingOrDefault는 기본값 제공으로 정상 동작. size가 그대로 PageRequest.of 또는 하위 서비스로 전달되어 과도한 요청 시 DB/네트워크 부하 가능.
수정 대상(정확한 위치):
- src/main/java/konkuk/chacall/global/common/dto/CursorPagingRequest.java — @max 추가 또는 생성자에서 size = Math.min(size, MAX_PAGE_SIZE) 같은 프로그래매틱 클램프 도입.
- src/main/java/konkuk/chacall/domain/member/application/foodtruck/SavedFoodTruckService.java — PageRequest.of(0, cursorPagingRequest.size()) 를 PageRequest.of(0, Math.min(cursorPagingRequest.size(), MAX_PAGE_SIZE)) 등으로 방어 코딩.
- src/main/java/konkuk/chacall/domain/member/application/MemberService.java 및 src/main/java/konkuk/chacall/domain/owner/application/OwnerService.java — 하위 서비스로 전달되는 size에 대해 상한 적용 또는 하위 서비스에서 상한을 보장하도록 변경.
권장 방식: MAX_PAGE_SIZE(예: 50~100) 상수 정의 → CursorPagingRequest에 @max(…) 또는 생성자 클램프 적용 + 호출부에도 방어 코딩 및 단위 테스트 추가.
🤖 Prompt for AI Agents
In src/main/java/konkuk/chacall/domain/member/application/MemberService.java
around lines 59-66 and related flow, the passed paging size has no enforced
upper bound which can cause excessive DB/network load; define a MAX_PAGE_SIZE
constant (e.g. 50–100) in a common paging class, add either @Max(MAX_PAGE_SIZE)
or programmatic clamping (size = Math.min(size, MAX_PAGE_SIZE)) in
src/main/java/konkuk/chacall/global/common/dto/CursorPagingRequest.java, and
apply defensive clamps where sizes are used (e.g. change PageRequest.of(0,
cursorPagingRequest.size()) calls in
src/main/java/konkuk/chacall/domain/member/application/foodtruck/SavedFoodTruckService.java
and ensure MemberService.java and
src/main/java/konkuk/chacall/domain/owner/application/OwnerService.java either
pass the clamped size or re-clamp before delegating); add unit tests verifying
the clamp/enforcement and update any API validation docs accordingly.
| @@ -0,0 +1,35 @@ | |||
| package konkuk.chacall.domain.member.presentation.dto.request; | |||
There was a problem hiding this comment.
🛠️ Refactor suggestion
패키지 위치/이름 불일치
Response DTO가 request 패키지에 위치합니다. 패키지/경로를 response로 정정해 주세요(리팩터 후 import 영향 점검 필요).
-package konkuk.chacall.domain.member.presentation.dto.request;
+package konkuk.chacall.domain.member.presentation.dto.response;📝 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.
| package konkuk.chacall.domain.member.presentation.dto.request; | |
| package konkuk.chacall.domain.member.presentation.dto.response; |
There was a problem hiding this comment.
@ksg1227 네, 맞습니다! Response DTO가 request 패키지에 있는 것은 확실히 잘못된 위치네요.
MemberReservationHistoryResponse 클래스를 response 패키지로 이동시키시면 됩니다. 이동 후에는 이 클래스를 import하는 다른 파일들의 import 문도 자동으로 업데이트되는지 확인해보시기 바랍니다.
If you found this review helpful, would you consider giving us a shout-out on X?
Thank you for using CodeRabbit!
There was a problem hiding this comment.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
ksg1227
left a comment
There was a problem hiding this comment.
이번 기능에서는 흠 잡을 부분이 전혀 없었습니다 아주 굿👍🏻
언급해주신 내용에 대해서는, 저도 그냥 기존에 있던 쿼리를 그대로 가져다가 사용해도 괜찮을 것 같습니다. 어차피 member 까지 join 한다고 해서 성능에 큰 차이가 있을 것 같지도 않고, 재사용하는 것 나쁘지 않은 것 같아요! 수고하셨습니당
| Optional<Reservation> findByIdWithDetails(@Param("reservationId") Long reservationId); | ||
|
|
||
|
|
||
| @EntityGraph(attributePaths = {"foodTruck"}) |
There was a problem hiding this comment.
오 푸드트럭은 fetchJoin 으로 가져오면 좋겠다 생각했는데 딱 적용해주셨군요 아주 좋습니다
| reservation.getReservationInfo().parsingReservationDeposit(), | ||
| reservation.getReservationInfo().parsingIsUserElectricity(), |
There was a problem hiding this comment.
ReservationInfo 내에서 처리하는 것 좋습니다! 훨씬 낫네요 👍🏻 제꺼까지 고쳐주셔서 감사합니다 ㅎㅎ
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
src/main/java/konkuk/chacall/domain/member/application/MemberService.java (1)
56-63: 커서 페이지 사이즈 상한 클램프 필요 (이전 코멘트와 동일 사안)
request.pagingOrDefault()로 얻은 size에 상한이 없습니다. 과도한 size는 부하 유발합니다. 최소 서비스 경계에서라도 클램프 적용해 주세요.- CursorPagingRequest cursorPagingRequest = request.pagingOrDefault(); - - return memberReservationService.getMemberReservations(member, request, cursorPagingRequest.cursor(), cursorPagingRequest.size()); + CursorPagingRequest cursorPagingRequest = request.pagingOrDefault(); + int clampedSize = Math.min(cursorPagingRequest.size(), 50); // TODO: 공용 MAX_PAGE_SIZE로 치환 + return memberReservationService.getMemberReservations(member, request, cursorPagingRequest.cursor(), clampedSize);다음 스크립트로 공용 상한이 이미 정의되어 있는지 확인해 주세요.
#!/bin/bash rg -n --type=java 'MAX_PAGE_SIZE|@Max\(|clamp|withMaxSize' -C2 rg -n --type=java 'record\s+CursorPagingRequest\b|class\s+CursorPagingRequest\b' -C3
🧹 Nitpick comments (7)
src/main/java/konkuk/chacall/domain/member/application/MemberService.java (2)
5-5: 와일드카드 import 지양DTO import를 와일드카드로 열면 변경에 취약해집니다. 사용 중인 타입만 명시적으로 import해 주세요.
-import konkuk.chacall.domain.member.presentation.dto.request.*; -import konkuk.chacall.domain.member.presentation.dto.response.*; +import konkuk.chacall.domain.member.presentation.dto.request.GetReservationHistoryRequest; +import konkuk.chacall.domain.member.presentation.dto.request.RegisterRatingRequest; +import konkuk.chacall.domain.member.presentation.dto.request.UpdateFoodTruckSaveStatusRequest; +import konkuk.chacall.domain.member.presentation.dto.response.MemberReservationDetailResponse; +import konkuk.chacall.domain.member.presentation.dto.response.MemberReservationHistoryResponse; +import konkuk.chacall.domain.member.presentation.dto.response.ReservationForRatingResponse; +import konkuk.chacall.domain.member.presentation.dto.response.SavedFoodTruckResponse; +import konkuk.chacall.domain.member.presentation.dto.response.SavedFoodTruckStatusResponse;Also applies to: 7-8
65-70: 소유권 검증과 불필요 JOIN 제거 확인 요청상세 조회는
reservationId가 해당member의 소유인지 검증되어야 합니다(404/403 중 하나로 응답 일관화). 또한 PR 설명대로 현재 쿼리가 member까지 FETCH JOIN 한다면, 본 API에서는 불필요하므로 제거/분리 고려가 필요합니다.src/main/java/konkuk/chacall/domain/member/presentation/dto/response/MemberReservationHistoryResponse.java (2)
18-20: “최대 2개” 제약 보장 위치 명확화표기만 있고 코드 레벨 제약이 보이지 않습니다.
ReservationInfo#getFormattedDateTimeInfos()가 2개로 클램프하는지 확인하고, 아니면 여기서도limit(2)로 방어해 주세요.
23-33: 사진 URL null 처리/대체값 전략 필요
foodTruck.getFoodTruckPhotoList().getMainPhotoUrl()가 null일 수 있습니다. 스키마 nullable 지정 또는 기본 이미지로 대체하는 방어 로직이 필요합니다.- foodTruck.getFoodTruckPhotoList().getMainPhotoUrl(), + // TODO: 도메인/VO에서 기본값 보장되면 그대로 사용 + foodTruck.getFoodTruckPhotoList().getMainPhotoUrl(), // null 가능 시 스키마에 nullable=true 반영 또는 기본 URL 적용src/main/java/konkuk/chacall/domain/member/presentation/dto/response/MemberReservationDetailResponse.java (3)
9-39: DTO 필드 타입 재고: 금액/전기여부는 타입으로, 표현은 DTO에서 포맷
- deposit을 String(“50000원”)으로 들고 오면 통화 계산/정렬/합계에 제약이 큽니다. KRW 정수(Long) 또는 Money VO로 노출하고, 표시용 문자열은 DTO 변환 단계에서 포맷하세요.
- electricityInfo도 String(“가능/불가”) 대신 boolean/Enum을 권장합니다.
예시(방향성):
- 도메인:
long getReservationDepositAmountKrw(),boolean isElectricityAvailable()- DTO: NumberFormat/MessageSource를 통해
"50,000원", 현지화된"가능/불가"로 포맷
9-39: 상세 응답에 reservationId 포함 고려상세 화면에서도 추후 액션(공유/신고/재요청 등)에 식별자가 필요할 수 있습니다.
reservationId필드 추가를 검토해 주세요.
41-55: 도메인 파싱 메서드 명/책임 정교화
parsingReservationDeposit(),parsingIsUserElectricity()는 네이밍과 책임이 “포맷팅”에 가깝습니다.
- 도메인은 값(타입/규칙)까지 책임, 문자열 표현은 DTO/프리젠테이션 책임으로 분리해 주세요.
- 특히
parsingIsUserElectricity()는 오탈자 가능성이 있습니다(Use vs User). 의미가 “전기 사용 여부”라면isElectricityAvailable()같은 불리언 메서드가 적절합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/main/java/konkuk/chacall/domain/member/application/MemberService.java(3 hunks)src/main/java/konkuk/chacall/domain/member/application/reservation/MemberReservationService.java(1 hunks)src/main/java/konkuk/chacall/domain/member/presentation/MemberController.java(6 hunks)src/main/java/konkuk/chacall/domain/member/presentation/dto/response/MemberReservationDetailResponse.java(1 hunks)src/main/java/konkuk/chacall/domain/member/presentation/dto/response/MemberReservationHistoryResponse.java(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/main/java/konkuk/chacall/domain/member/application/reservation/MemberReservationService.java
- src/main/java/konkuk/chacall/domain/member/presentation/MemberController.java
🔇 Additional comments (1)
src/main/java/konkuk/chacall/domain/member/application/MemberService.java (1)
21-21: 서비스 의존성 주입 추가 LGTMMemberReservationService 주입 위치/가시성 적절합니다.
#️⃣연관된 이슈
closes #18
📝작업 내용
예약 목록 (무한 스크롤)
예약 상세 정보 조회
예약 상세 정보 조회를 구현하면서 상균님이 이미
사장님 예약 상세정보 조회 api에서 구현해둔 쿼리를 사용하였는데요. 그 페이지에선 Member의 정보가 필요하기 때문에 member 테이블을 FETCH JOIN 하였는데 현재 제가 구현한 api에서는 Member를 get해오지 않기 때문에 굳이 필요하지는 않는 상황입니다. 따라서 불필요한 JOIN이기는 한데 쿼리 선언을 하나 늘리는 것보다 기존 쿼리를 그대로 사용하는게 더 낫지 않나 라고 생각해서 일단 그대로 사용한 상황입니다. 이 부분에 대해서 상균님은 어떻게 생각하시는지 궁금합니다!!스크린샷
💬리뷰 요구사항
dto에서 파싱되는 부분(전기 사용 여부, 계약금 문자열 파싱)을 도메인 내부에서 이루어지도록 해서 중복 코드를 줄이고자 했습니다! (추후에 문자열 요구사항이 변경되더라도 도메인에서만 수정하면 되기 때문에 유지보수에 더 수월할 것이라고 생각했습니다~) 확인해주시면 감사하겠습니다.
Summary by CodeRabbit
신기능
문서