Skip to content

[FEAT] 예약 상태 변경 및 조회 api 구현#30

Merged
buzz0331 merged 13 commits into
developfrom
feat/#29-reservation-state
Sep 23, 2025
Merged

[FEAT] 예약 상태 변경 및 조회 api 구현#30
buzz0331 merged 13 commits into
developfrom
feat/#29-reservation-state

Conversation

@buzz0331

@buzz0331 buzz0331 commented Sep 22, 2025

Copy link
Copy Markdown
Contributor

#️⃣연관된 이슈

closes #29

📝작업 내용

예약 상태 변경 api

  1. 변경 요청받은 예약 상태에 따라 파사드 클래스에서 유저 권한을 검증 후 알맞은 하위 클래스 호출
  2. Reservation 조회
  3. 해당 유저가 예약 상태를 변경할 권한을 가지고 있는지 검증
  4. ReservationStatus 순서가 올바른지 검증
  5. ReservationStatus 업데이트

4번 과정에서 순서를 보장할 때 초기에 if문으로 분기를 만들어 구현했는데, 추후에 요구사항 수정에 유연하지 못할 것 같아 EnumMap을 만들어 해당 Enum의 가능한 다음 Enum을 Set 자료구조로 주입하여 사용하였습니다.
스크린샷 2025-09-22 오후 4 46 25

예약 상태 조회 api
별다른 이슈가 없습니다.

스크린샷

스크린샷 2025-09-22 오후 4 51 09

💬리뷰 요구사항(선택)

  • 추가적으로 프론트 개발자 분들 요청에 따라 다시 userId를 필터에서 주입하도록 수정하였습니다.
  • 요구사항에 따라 예약 견적서 작성시 글자수 제한을 추가하였습니다.
  • 프론트 개발자 분께 여쭤본 결과 예약 견적서 수정시에는 id 반환이 필요하지 않다고 해서 반환을 제거하였습니다.

Summary by CodeRabbit

  • New Features
    • 예약 상태 조회/변경 API 추가(역할 기반 전환 검증, 상태 DTO 및 상태 전이 로직 반영).
  • Bug Fixes / Validation
    • 예약 생성/수정 입력 유효성 강화(문자 길이, 금액 자릿수 등).
  • Refactor
    • 예약 수정 API 응답을 본문 없는 형태로 단순화; 내부 상태 업데이트 흐름 분리.
  • Security
    • 화이트리스트 외 모든 요청에 인증 필수, 토큰 누락 시 즉시 인증 오류 반환.
  • Documentation
    • 예약 상태 관련 Swagger 문서 및 신규 오류 코드(상태/전환 관련) 추가.

@coderabbitai

coderabbitai Bot commented Sep 22, 2025

Copy link
Copy Markdown

Walkthrough

예약 상태 변경·조회 기능을 추가했다. ReservationStatus 전이 규칙과 Reservation의 접근/전이 검증을 도입하고, ReservationService는 상태 처리를 ReservationStatusService로 위임하도록 변경했으며 컨트롤러·DTO·에러코드·Swagger·보안 리졸버도 갱신됐다.

Changes

Cohort / File(s) Summary
상태 처리 서비스 및 컨트롤러
src/main/java/.../reservation/application/ReservationService.java, src/main/java/.../reservation/application/status/ReservationStatusService.java, src/main/java/.../reservation/presentation/ReservationController.java
Reservation 상태 변경/조회 API 추가. ReservationService에 상태 관련 메서드 추가/위임, updateReservation 반환형을 void로 변경, 컨트롤러에 PATCH/GET /reservations/{id}/status 엔드포인트 추가.
도메인: 상태 전이 및 접근 검증
src/main/java/.../reservation/domain/model/Reservation.java, src/main/java/.../reservation/domain/value/ReservationStatus.java
Reservation에 validateAccessibleBy/updateStatus 추가 및 접근 검증 강화. ReservationStatus에 전이 규칙(TRANSITIONS)과 전이 검증 메서드(canTransitTo/isInValidStatusTransitionFrom) 도입.
DTO 및 요청 검증 강화
src/main/java/.../reservation/presentation/dto/request/UpdateReservationStatusRequest.java, src/main/java/.../reservation/presentation/dto/response/ReservationStatusResponse.java, src/main/java/.../reservation/presentation/dto/request/CreateReservationRequest.java
상태 요청/응답 DTO 추가. CreateReservationRequest에 길이/숫자 validation 애노테이션 추가.
상태 전담 서비스 구현
src/main/java/.../reservation/application/info/ReservationInfoService.java
패키지 경로 조정 및 updateReservation 반환형을 Longvoid로 변경(연계 호출부 반영).
에러 코드 및 Swagger 확장
src/main/java/.../global/common/exception/code/ErrorCode.java, src/main/java/.../global/common/swagger/SwaggerResponseDescription.java
INVALID_RESERVATION_STATUS, INVALID_RESERVATION_STATUS_TRANSITION 에러 코드 추가 및 상태 관련 Swagger 응답 설명 상수 추가.
인증/보안 변경 및 리졸버
src/main/java/.../global/config/SecurityConfig.java, src/main/java/.../global/common/security/resolver/UserIdArgumentResolver.java
보안 정책을 화이트리스트 외 인증 필요로 변경. UserIdArgumentResolver가 토큰 미존재 시 더 이상 1L을 반환하지 않고 인증 예외를 던지도록 변경.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant C as 클라이언트
    participant RC as ReservationController
    participant RS as ReservationService
    participant RSS as ReservationStatusService
    participant Repo as ReservationRepository
    participant R as Reservation

    Note over C,RC: PATCH /reservations/{id}/status
    C->>RC: UpdateReservationStatusRequest(status)
    RC->>RS: updateReservationStatus(id, req, userId)
    RS->>RSS: 역할 기반 위임
    RSS->>Repo: findById(id)
    Repo-->>RSS: Reservation
    RSS->>R: 소유자/예약자 검증
    R-->>RSS: 검증 OK 또는 예외
    RSS->>R: updateStatus(newStatus)
    R-->>RSS: 상태 변경 또는 전이 예외
    RSS-->>RS: ReservationStatusResponse
    RS-->>RC: ReservationStatusResponse
    RC-->>C: 200 OK + body

    Note over C,RC: GET /reservations/{id}/status
    C->>RC: 요청
    RC->>RS: getReservationStatus(id, userId)
    RS->>RSS: getReservationStatus(id, user)
    RSS->>Repo: findById(id)
    Repo-->>RSS: Reservation
    RSS->>R: validateAccessibleBy(userId)
    R-->>RSS: 검증 OK 또는 예외
    RSS-->>RS: ReservationStatusResponse
    RS-->>RC: ReservationStatusResponse
    RC-->>C: 200 OK + body
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Possibly related PRs

Suggested reviewers

  • ksg1227

Poem

새벽 당근 들고 달려온 토끼,
상태 바꾸니 로그가 뿅뿅,
CONFIRMED든 CANCELLED든 깡총 처리,
전이 규칙 따라 안전히 뛰네,
배포 전 깃발 흔드는 토끼 🥕🐇

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning 대다수 변경은 이슈 범위에 부합하지만 SecurityConfig의 인증 정책 전환은 전역적인 인증 동작을 바꾸는 광범위한 영향이 있어 본 이슈의 범위를 벗어날 가능성이 있으며 raw_summary에 포함된 'src/calculator.py' 관련 변경 사항은 본 기능 구현과 무관한 잡음 또는 실수로 보입니다. SecurityConfig의 인증 정책 변경은 별도 PR로 분리하거나 PR 설명에 변경 의도와 영향 범위를 명확히 기재하고 관련 통합 테스트를 추가해 주세요; 또한 저장소 diff를 재검토하여 'src/calculator.py' 같은 의도치 않은 파일 변경이 포함되어 있다면 해당 변경을 제거하거나 별도 PR로 분리해 주세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed 제목 “[FEAT] 예약 상태 변경 및 조회 api 구현”은 변경의 핵심인 예약 상태 변경 및 조회 API 구현을 명확하고 간결하게 표현하여 PR의 주된 목적을 한눈에 파악하기에 적절합니다.
Linked Issues Check ✅ Passed PR은 연결 이슈 #29에서 요구한 항목들(예약 확정 요청, 예약 확정, 예약 취소 요청, 예약 취소, 예약 상태 조회)을 컨트롤러 엔드포인트 추가, ReservationStatusService 및 상태 전이 검증(ReservationStatus enum·Reservation.updateStatus), 관련 DTO와 에러코드 추가로 구현하여 코드·API 수준에서 요구사항을 충족합니다.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/#29-reservation-state

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.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 10

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/konkuk/chacall/domain/reservation/application/info/ReservationInfoService.java (1)

58-79: updateReservation에 @transactional 누락 — 변경사항이 영속되지 않을 수 있습니다

JPA 더티체킹으로 update가 반영되려면 트랜잭션이 필요합니다. 서비스 메서드에 @transactional을 추가하세요.

적용 제안:

+import org.springframework.transaction.annotation.Transactional
-    public void updateReservation(Long reservationId, UpdateReservationRequest request, User user) {
+    @Transactional
+    public void updateReservation(Long reservationId, UpdateReservationRequest request, User user) {
🧹 Nitpick comments (15)
src/main/java/konkuk/chacall/global/common/security/resolver/UserIdArgumentResolver.java (2)

34-39: 널 대체값(1L) 제거하고 401 예외로 전환한 것 적절합니다. 다만 캐스팅 안전성 보강 제안

현재 Object를 곧바로 (Long) 캐스팅하면 타입 불일치 시 ClassCastException이 납니다. 방어적으로 instanceof 체크를 추가하고, 타입 불일치도 401로 처리하는 편이 안전합니다.

적용 제안(diff 34-39):

-        Object userId = ((HttpServletRequest) webRequest.getNativeRequest()).getAttribute(JWT_ACCESS_TOKEN_KEY.getValue());
-        if (userId == null) {
-            throw new AuthException(AUTH_TOKEN_NOT_FOUND);
-        }
-        return (Long) userId;
+        Object userIdAttr = ((HttpServletRequest) webRequest.getNativeRequest()).getAttribute(JWT_ACCESS_TOKEN_KEY.getValue());
+        if (userIdAttr == null) {
+            throw new AuthException(AUTH_TOKEN_NOT_FOUND);
+        }
+        if (!(userIdAttr instanceof Long)) {
+            throw new AuthException(AUTH_UNAUTHORIZED);
+        }
+        return (Long) userIdAttr;

추가 import(파일 상단 import 구역):

+import static konkuk.chacall.global.common.exception.code.ErrorCode.AUTH_UNAUTHORIZED;

24-26: @userid 파라미터에 primitive long도 지원하세요

검증 결과: src/main/java 내 @userid 사용처는 모두 Long입니다. 즉각적인 문제는 없으나 primitive long 실수 사용을 방지하기 위해 변경을 권장합니다.

-        return parameter.hasParameterAnnotation(UserId.class)
-                && parameter.getParameterType().equals(Long.class);
+        return parameter.hasParameterAnnotation(UserId.class)
+                && (Long.class.equals(parameter.getParameterType()) || long.class.equals(parameter.getParameterType()));
src/main/java/konkuk/chacall/domain/reservation/application/info/ReservationInfoService.java (3)

24-42: createReservation도 트랜잭션 경계에 포함하세요

엔티티 생성/저장은 트랜잭션 내에서 수행하는 게 안전합니다.

적용 제안:

-    public Long createReservation(CreateReservationRequest request, User owner, User member) {
+    @Transactional
+    public Long createReservation(CreateReservationRequest request, User owner, User member) {

44-56: 조회 메서드 readOnly 최적화 권장

getReservation은 조회-only입니다. @transactional(readOnly = true)로 힌트를 주면 성능/불필요한 flush 방지에 도움이 됩니다.

적용 제안:

-    public ReservationResponse getReservation(Long reservationId, User user) {
+    @Transactional(readOnly = true)
+    public ReservationResponse getReservation(Long reservationId, User user) {

48-53: 중복 접근검증 로직은 헬퍼로 추출 가능

get/update 모두 동일한 접근 검증을 수행합니다. private 메서드로 추출하면 유지보수가 쉬워집니다.

예시:

private void validateAccess(Reservation reservation, User user) {
    if (user.getRole().equals(Role.OWNER)) {
        reservation.validateFoodTruckOwner(user.getUserId());
    } else {
        reservation.validateReservedBy(user.getUserId());
    }
}
src/main/java/konkuk/chacall/global/common/exception/code/ErrorCode.java (1)

60-61: 에러 상태코드 제안: 전이 불가는 409 CONFLICT가 더 적합

유효하지 않은 상태 전이는 리소스 현재 상태와의 충돌 의미가 강합니다. 400 대신 409 사용을 고려해주세요.

적용 제안:

-    INVALID_RESERVATION_STATUS_TRANSITION(HttpStatus.BAD_REQUEST, 90007, "유효하지 않은 예약 상태 전환입니다."),
+    INVALID_RESERVATION_STATUS_TRANSITION(HttpStatus.CONFLICT, 90007, "유효하지 않은 예약 상태 전환입니다."),
src/main/java/konkuk/chacall/domain/reservation/domain/model/Reservation.java (2)

49-55: 접근성 단일 검증 메서드 추가 좋습니다.

컨트롤러/서비스에서 중복 분기를 줄일 수 있습니다. 상태 조회/변경 흐름에도 적극 재사용 추천.


155-161: 상태 전이 검증 메서드 명/사용 혼동 가능성

isInValidStatusTransitionFrom(newStatus)는 의미가 애매합니다(“in valid” vs “invalid”). 가독성과 오용 방지를 위해 긍정형 API로 교체 권장.

권장(diff, ReservationStatus에 canTransitTo가 있다면):

-        if (this.reservationStatus.isInValidStatusTransitionFrom(newStatus)) {
+        if (!this.reservationStatus.canTransitTo(newStatus)) {
             throw new DomainRuleException(INVALID_RESERVATION_STATUS_TRANSITION);
         }
         this.reservationStatus = newStatus;

없다면 isInvalidTransitionTo 등으로 명확히 리네이밍해 주세요.

src/main/java/konkuk/chacall/domain/reservation/domain/value/ReservationStatus.java (2)

29-38: TRANSITIONS를 완전 불변 구조로 단순화하세요.

현재 Map.copyOf만 불변이고, 값(Set)은 EnumSet으로 여전히 변경 가능해서 내부 변경 여지가 있습니다. 한 줄 초기화와 Set.of/Map.of를 사용하면 Map/Set 모두 완전 불변이 됩니다.

적용 diff:

-    private static final Map<ReservationStatus, Set<ReservationStatus>> TRANSITIONS;
-    static {
-        Map<ReservationStatus, Set<ReservationStatus>> m = new EnumMap<>(ReservationStatus.class);
-        m.put(PENDING, EnumSet.of(CONFIRMED_REQUESTED));
-        m.put(CONFIRMED_REQUESTED, EnumSet.of(CONFIRMED));
-        m.put(CONFIRMED, EnumSet.of(CANCELLED_REQUESTED));
-        m.put(CANCELLED_REQUESTED, EnumSet.of(CANCELLED));
-        m.put(CANCELLED, EnumSet.noneOf(ReservationStatus.class));
-        TRANSITIONS = Map.copyOf(m);
-    }
+    private static final Map<ReservationStatus, Set<ReservationStatus>> TRANSITIONS =
+            Map.of(
+                    PENDING, Set.of(CONFIRMED_REQUESTED),
+                    CONFIRMED_REQUESTED, Set.of(CONFIRMED),
+                    CONFIRMED, Set.of(CANCELLED_REQUESTED),
+                    CANCELLED_REQUESTED, Set.of(CANCELLED),
+                    CANCELLED, Set.of()
+            );

45-47: 메서드 이름을 오해 없게 정리해 주세요.

isInValidStatusTransitionFrom는 철자/의미가 모호합니다. 유지하되, 보다 명확한 별칭을 추가하는 것을 권장합니다.

추가 메서드 제안(기존 메서드는 @deprecated로 유지):

     public boolean isInValidStatusTransitionFrom(ReservationStatus newStatus) {
         return !canTransitTo(newStatus);
     }
+
+    /** @deprecated 의미가 모호합니다. cannotTransitTo를 사용하세요. */
+    @Deprecated
+    public boolean isInvalidTransitionTo(ReservationStatus target) {
+        return !canTransitTo(target);
+    }
+
+    public boolean cannotTransitTo(ReservationStatus target) {
+        return !canTransitTo(target);
+    }
src/main/java/konkuk/chacall/domain/reservation/presentation/ReservationController.java (1)

79-80: 경로 표기 일관성(슬래시 누락 가능성)

@PatchMapping("{reservationId}/status")는 동작하더라도, 동일 파일의 @GetMapping("/{reservationId}/status")와 표기를 맞추는 편이 가독성과 오타 방지에 좋습니다.

-    @PatchMapping("{reservationId}/status")
+    @PatchMapping("/{reservationId}/status")
src/main/java/konkuk/chacall/domain/reservation/application/status/ReservationStatusService.java (4)

11-15: 트랜잭션 경계 명시(읽기 전용 기본 + 갱신 메서드에 쓰기 트랜잭션)

현재 클래스에 @transactional이 없어 상위 호출자 트랜잭션에 의존합니다. 안전성을 위해 클래스 기본을 readOnly로, 상태 변경 메서드에 @transactional을 부여하세요.

적용 diff:

 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;

-@Service
+@Service
+@Transactional(readOnly = true)
 @RequiredArgsConstructor
 public class ReservationStatusService {

각 업데이트 메서드에 쓰기 트랜잭션 추가:

-    public ReservationStatusResponse updateReservationStatusToConfirmedRequested(Long reservationId, UpdateReservationStatusRequest request, User member) {
+    @Transactional
+    public ReservationStatusResponse updateReservationStatusToConfirmedRequested(Long reservationId, UpdateReservationStatusRequest request, User member) {
...
-    public ReservationStatusResponse updateReservationStatusToConfirmed(Long reservationId, UpdateReservationStatusRequest request, User owner) {
+    @Transactional
+    public ReservationStatusResponse updateReservationStatusToConfirmed(Long reservationId, UpdateReservationStatusRequest request, User owner) {
...
-    public ReservationStatusResponse updateReservationStatusToCancelled(Long reservationId, UpdateReservationStatusRequest request, User user) {
+    @Transactional
+    public ReservationStatusResponse updateReservationStatusToCancelled(Long reservationId, UpdateReservationStatusRequest request, User user) {

45-46: 주석 오타: CONFIRMED → CANCELLED

// CANCELLED_REQUESTED, CONFIRMED ...는 문맥상 CANCELLED_REQUESTED, CANCELLED로 보입니다. 주석 수정 바랍니다.

-        // CANCELLED_REQUESTED, CONFIRMED 모두 예약자, 사장님 모두 가능
+        // CANCELLED_REQUESTED, CANCELLED 모두 예약자, 사장님 모두 가능

68-71: save 호출은 선택 사항입니다.

JPA에서 findById로 조회한 영속 엔티티의 필드 변경은 트랜잭션 커밋 시 플러시됩니다. reservationRepository.save(reservation)는 중복 호출이므로 제거해도 무방합니다(명시적 save가 팀 규칙이면 유지).

     private void updateReservationStatus(Reservation reservation, UpdateReservationStatusRequest request) {
         reservation.updateStatus(request.reservationStatus());
-        reservationRepository.save(reservation);
     }

19-39: 엔드포인트별 기대 상태값을 선제 검증하세요.

안전성을 위해 메서드별 허용 상태값을 명시적으로 체크하면 라우팅 실수나 잘못된 요청을 조기 차단할 수 있습니다(도메인 전이 규칙과 별개).

예시:

// confirmed-requested 전용
if (request.reservationStatus() != ReservationStatus.CONFIRMED_REQUESTED) {
    throw new BusinessException(ErrorCode.INVALID_RESERVATION_STATUS);
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cf5476e and 5cbe85e.

📒 Files selected for processing (13)
  • src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java (3 hunks)
  • src/main/java/konkuk/chacall/domain/reservation/application/info/ReservationInfoService.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/reservation/application/status/ReservationStatusService.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/reservation/domain/model/Reservation.java (3 hunks)
  • src/main/java/konkuk/chacall/domain/reservation/domain/value/ReservationStatus.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/reservation/presentation/ReservationController.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/CreateReservationRequest.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/UpdateReservationStatusRequest.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/response/ReservationStatusResponse.java (1 hunks)
  • src/main/java/konkuk/chacall/global/common/exception/code/ErrorCode.java (1 hunks)
  • src/main/java/konkuk/chacall/global/common/security/resolver/UserIdArgumentResolver.java (1 hunks)
  • src/main/java/konkuk/chacall/global/common/swagger/SwaggerResponseDescription.java (1 hunks)
  • src/main/java/konkuk/chacall/global/config/SecurityConfig.java (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
src/main/java/konkuk/chacall/global/common/security/resolver/UserIdArgumentResolver.java (3)
src/main/java/konkuk/chacall/global/common/security/util/JwtUtil.java (2)
  • getUserId (61-63)
  • Slf4j (17-71)
src/main/java/konkuk/chacall/global/common/security/filter/JwtAuthenticationFilter.java (1)
  • Override (32-55)
src/main/java/konkuk/chacall/global/common/exception/AuthException.java (1)
  • Getter (6-18)
src/main/java/konkuk/chacall/domain/reservation/application/info/ReservationInfoService.java (3)
src/main/java/konkuk/chacall/domain/reservation/domain/value/ReservationInfo.java (2)
  • updateReservationInfo (82-100)
  • Getter (15-101)
src/main/java/konkuk/chacall/domain/user/application/UserService.java (1)
  • Transactional (26-32)
src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/UpdateReservationRequest.java (1)
  • UpdateReservationRequest (8-47)
src/main/java/konkuk/chacall/domain/reservation/domain/value/ReservationStatus.java (4)
src/main/java/konkuk/chacall/domain/reservation/domain/model/Reservation.java (1)
  • Getter (17-162)
src/main/java/konkuk/chacall/domain/owner/presentation/dto/request/GetReservationHistoryRequest.java (1)
  • GetReservationHistoryRequest (10-21)
src/main/java/konkuk/chacall/domain/owner/application/reservation/OwnerReservationService.java (1)
  • RequiredArgsConstructor (25-88)
src/main/java/konkuk/chacall/domain/member/presentation/dto/request/GetReservationHistoryRequest.java (1)
  • GetReservationHistoryRequest (10-21)
src/main/java/konkuk/chacall/domain/reservation/domain/model/Reservation.java (1)
src/main/java/konkuk/chacall/domain/reservation/application/reservationinfo/ReservationInfoService.java (2)
  • updateReservation (58-81)
  • Service (17-82)
src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/UpdateReservationStatusRequest.java (2)
src/main/java/konkuk/chacall/domain/owner/presentation/dto/request/GetReservationHistoryRequest.java (1)
  • GetReservationHistoryRequest (10-21)
src/main/java/konkuk/chacall/domain/member/presentation/dto/request/GetReservationHistoryRequest.java (1)
  • GetReservationHistoryRequest (10-21)
src/main/java/konkuk/chacall/domain/reservation/application/status/ReservationStatusService.java (2)
src/main/java/konkuk/chacall/global/common/exception/EntityNotFoundException.java (1)
  • EntityNotFoundException (6-11)
src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java (1)
  • Service (19-74)
🪛 GitHub Actions: CI with Gradle
src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java

[error] 48-48: incompatible types: unexpected return value

🔇 Additional comments (9)
src/main/java/konkuk/chacall/domain/reservation/application/info/ReservationInfoService.java (1)

48-53: 권한 분기(OWNER vs 나머지) 정책 확인 필요

현재 OWNER가 아니면 모두 예약자 검증을 타게 됩니다. ADMIN 등 시스템 역할이 있다면 접근 차단될 수 있습니다. 의도된 정책인지 확인 바랍니다.

정책 질문:

  • ADMIN이 모든 예약 열람/수정 가능해야 한다면 별도 분기가 필요합니다.
  • Role 확장 시 기본 else 분기 동작 재검토가 필요합니다.

Also applies to: 62-67

src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/CreateReservationRequest.java (3)

27-33: 날짜 포맷만 검증하고 순서/유효일자 검증 부재

정규식만으로는 시작≤종료/유효한 달·일 여부를 막지 못합니다. 도메인/서비스 레벨에서 추가 검증 필요(예: 파싱 후 LocalDate 비교).

원하시면 도메인 검증 유틸을 추가하는 패치를 제안하겠습니다.


43-44: 메뉴 50자 제한은 타협 가능한가요?

다품목 입력 시 50자 제한이 UX를 저해할 수 있습니다. 프론트 합의한 한계치인지 확인 요청.


56-58: LGTM — 기타 요청 사항 200자 제한

현실적인 상한선으로 보입니다.

src/main/java/konkuk/chacall/domain/reservation/presentation/dto/response/ReservationStatusResponse.java (1)

6-10: 단순·명확한 DTO 추가 좋습니다.

enum 직렬화가 의도대로 이뤄지는지(Swagger example, Jackson 설정)만 확인해주세요. 필요 시 @NotNull 추가 고려.

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

148-161: 상태 변경/조회용 스웨거 에러 매핑 추가 적절합니다.

컨트롤러의 해당 엔드포인트가 이 enum 항목을 실제로 참조하는지만 재확인 부탁드립니다.

src/main/java/konkuk/chacall/domain/reservation/domain/value/ReservationStatus.java (2)

40-43: 전이 검증 로직은 명확하고 안전합니다.

null 가드와 불변 Map 조회 방식 모두 적절합니다.


32-36: 비즈니스 규칙 재확인 요청: PENDING → CANCELLED_REQUESTED 불허가 맞나요?

현재 전이는 단선(PENDING→CONFIRMED_REQUESTED→CONFIRMED→CANCELLED_REQUESTED→CANCELLED)만 허용합니다. ‘견적 대기(PENDING)’에서 바로 취소 요청을 보낼 수 없도록 한 의도인지 확인 부탁드립니다. UX/프론트 흐름과도 일치하는지 검증이 필요합니다.

src/main/java/konkuk/chacall/domain/reservation/application/status/ReservationStatusService.java (1)

52-59: 아이템포턴시 정책 확인 요청

이미 해당 상태인 경우(예: 중복 PATCH) 현재는 도메인 전이 규칙상 예외가 발생합니다. 동일 상태 재요청을 허용(무시)할지, 명시적으로 409/422를 줄지 정책 합의가 필요합니다.

Comment on lines +52 to +68
public ReservationStatusResponse updateReservationStatus(Long reservationId, UpdateReservationStatusRequest request, Long userId) {
switch(request.reservationStatus()) {
case CONFIRMED_REQUESTED -> {
User member = memberValidator.validateAndGetMember(userId);
return reservationStatusService.updateReservationStatusToConfirmedRequested(reservationId, request, member);
}
case CONFIRMED -> {
User owner = ownerValidator.validateAndGetOwner(userId);
return reservationStatusService.updateReservationStatusToConfirmed(reservationId, request, owner);
}
case CANCELLED, CANCELLED_REQUESTED -> {
User user = memberValidator.validateAndGetMember(userId);
return reservationStatusService.updateReservationStatusToCancelled(reservationId, request, user);
}
default -> throw new BusinessException(ErrorCode.INVALID_RESERVATION_STATUS);
}
}

@coderabbitai coderabbitai Bot Sep 22, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

❓ Verification inconclusive

권한 모델 재검토 필요: 취소(REQUESTED/최종) 케이스가 ‘회원’만 허용됩니다.

현재 CANCELLED, CANCELLED_REQUESTED 모두 memberValidator를 사용해 OWNER 취소를 막습니다. 사장도 예약 취소가 가능해야 한다면 권한 분기/검증을 조정해야 합니다(서비스 내 소유권 검증과 조합).

수정 방향 예시(의사코드):

  • CANCELLED_REQUESTED: 예약자(member)만 요청 가능
  • CANCELLED: 사장(OWNER) 또는 특정 조건의 예약자 승인 가능
    또는 공통: userId로 사용자를 조회한 뒤 Reservation.validateAccessibleBy로 접근성만 확인하고, 세부 권한은 ReservationStatusService에서 역할별로 처리.

권한 모델 재검토 필요 — OWNER 예약 취소 허용 여부 확인

현재 CANCELLED 및 CANCELLED_REQUESTED 케이스에서 memberValidator만 사용해 OWNER의 취소를 차단합니다. (src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java:52-68)

  • 권장 수정:
    • CANCELLED_REQUESTED: 예약자(member)만 요청 허용.
    • CANCELLED: OWNER(사장)도 취소 가능하도록 권한 분기/검증 추가(예: ownerValidator 사용 또는 userId로 사용자 조회 후 Reservation.validateAccessibleBy로 접근성만 확인하고 ReservationStatusService에서 역할별 로직 처리).
🤖 Prompt for AI Agents
In
src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java
around lines 52 to 68, the CANCELLED and CANCELLED_REQUESTED branches both use
memberValidator, which prevents owners from cancelling; change the branching so
CANCELLED_REQUESTED continues to require the member (memberValidator), while
CANCELLED allows owner cancellation by validating owner (ownerValidator) when
userId is an owner or by retrieving the user and using
Reservation.validateAccessibleBy to check access and then delegating
role-specific handling into ReservationStatusService; adjust the switch to call
ownerValidator.validateAndGetOwner for owner cancellation or to fetch the user
and pass that user to
reservationStatusService.updateReservationStatusToCancelled so the service can
apply role-based logic.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

User 클래스 내부를 보면 Member 검증은 MEMBER와 OWNER를 모두 허용해두고 있어. OWNER는 MEMBER와 OWNER 권한을 모두 가지는 식이야.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@buzz0331 감사합니다! 권한 모델에 대한 명확한 설명 잘 이해했습니다.

OWNER가 MEMBER 권한을 상속받는 구조라면 현재 구현이 올바르네요. memberValidator.validateAndGetMember()가 OWNER도 허용한다면 취소 기능에서 권한 문제가 없겠습니다.

제가 권한 분기 수정을 제안했던 것은 불필요한 제안이었네요. 현재 구현이 의도된 대로 잘 동작하고 있습니다.

  (\   /)
 ( ^.^ )
  o_(")(")
*lightbulb moment!*

✏️ Learnings added
Learnt from: buzz0331
PR: CHA-CALL/ChaCall-Server#30
File: src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java:52-68
Timestamp: 2025-09-22T08:13:37.848Z
Learning: ChaCall 프로젝트에서 OWNER 역할은 MEMBER 권한을 포함합니다. memberValidator.validateAndGetMember()는 MEMBER와 OWNER 모두를 허용하므로, OWNER가 예약 취소 등 MEMBER 기능을 사용할 수 있습니다.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment on lines +70 to +73
public ReservationStatusResponse getReservationStatus(Long reservationId, Long userId) {
User user = memberValidator.validateAndGetMember(userId);
return reservationStatusService.getReservationStatus(reservationId, user);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

상태 조회(getReservationStatus)에 ‘회원’ 전용 검증 사용

사장 접근이 막힐 수 있습니다. 접근 주체가 OWNER/MEMBER 모두 가능한 요구사항이면 공통 사용자 조회(예: UserService.getById) 후 도메인에서 접근성 검증으로 통일하세요.

🤖 Prompt for AI Agents
In
src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java
around lines 70 to 73, replace the member-only lookup with a generic user fetch:
call the common user retrieval (e.g., UserService.getById(userId) or equivalent)
instead of memberValidator.validateAndGetMember(userId), and pass the resulting
User into reservationStatusService.getReservationStatus(reservationId, user);
keep any role/access checks inside the domain/service layer so both OWNER and
MEMBER can be handled consistently.

Comment on lines +19 to 20
@Size(max = 20, message = "예약 주소는 공백 포함 최대 20자까지 입력 가능합니다.")
String address,

@coderabbitai coderabbitai Bot Sep 22, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

주소 길이 20자는 과도하게 짧습니다. 실주소 입력 실패 가능성이 큽니다.

도로명/지번+동/층 등을 포함하면 20자를 쉽게 초과합니다. 최소 100자 권장.

적용 예시(diff):

-        @Size(max = 20, message = "예약 주소는 공백 포함 최대 20자까지 입력 가능합니다.")
+        @Size(max = 100, message = "예약 주소는 공백 포함 최대 100자까지 입력 가능합니다.")
📝 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
@Size(max = 20, message = "예약 주소는 공백 포함 최대 20자까지 입력 가능합니다.")
String address,
@Size(max = 100, message = "예약 주소는 공백 포함 최대 100자까지 입력 가능합니다.")
String address,
🤖 Prompt for AI Agents
In
src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/CreateReservationRequest.java
around lines 19-20, the @Size(max = 20) on the address field is too short for
real addresses; update the annotation to a larger limit (e.g., @Size(max = 100))
and adjust the validation message to reflect the new limit (e.g., "예약 주소는 공백 포함
최대 100자까지 입력 가능합니다.") so real road/jibun names and unit/floor details are
accepted.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

address와 detailaddress가 따로 분리되어 있어서 address에는 시/구/동만 들어가고 detailaddress에 구체적인 건물과 층수가 들어갈 것 같은데 그래도 적은가?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

@buzz0331 좋은 지적이네요!

분석해보니 address 필드가 정말로 시/구/동 수준의 행정구역만 담는다면 20자가 대부분 충분합니다.

  • 일반적인 예시: "서울시 강남구 역삼동" (9자), "부산시 해운대구 우동" (8자)
  • 긴 예시도: "경기도 고양시 일산서구 주엽동" (13자) 정도

다만 edge case를 고려하면:

  • 일부 특수한 행정구역명이 더 길 수 있음
  • 사용자가 실수로 상세주소를 포함할 가능성
  • 향후 주소 체계 변경 가능성

현재 필드 분리 설계가 명확하다면 20자도 실용적으로 충분할 것 같습니다. 다만 안전성을 고려한다면 30-40자 정도로 여유를 두는 것도 좋은 선택이겠네요.

    /|   /|   
   ( :v:  :v: )
    |(_)(_)|
    /       \
   /  ^   ^  \
  (  curious  )
   \    _    /
    \  ___  /
     \_____/

🏁 Script executed:

#!/bin/bash
# Let's analyze some typical Korean address examples to see if 20 characters is sufficient for 시/구/동 level addresses

echo "=== 일반적인 한국 주소 예시 (시/구/동 레벨) ==="
echo "서울시 강남구 역삼동 (9자)"
echo "부산시 해운대구 우동 (8자)" 
echo "경기도 수원시 영통구 매탄동 (12자)"
echo "경기도 고양시 일산서구 주엽동 (13자)"
echo "인천시 남동구 구월동 (8자)"
echo "대전시 유성구 온천동 (8자)"

echo -e "\n=== 좀 더 긴 예시들 ==="
echo "경상북도 포항시 북구 흥해읍 (12자)"
echo "전라남도 목포시 용당동 (9자)"
echo "충청북도 청주시 상당구 우암동 (13자)"
echo "경기도 성남시 분당구 정자동 (12자)"

echo -e "\n=== 특별히 긴 주소명들 ==="
echo "경상남도 창원시 의창구 도계동 (13자)"
echo "전라북도 전주시 덕진구 인후동 (13자)"
echo "충청남도 천안시 동남구 신부동 (13자)"

echo -e "\n분석: 대부분 20자 이내로 충분해 보입니다."

Length of output: 365


맞습니다! 스크립트 분석 결과를 보니 20자가 충분하네요.

실제 데이터를 보면:

  • 대부분 8-13자 범위 (최장 "경기도 고양시 일산서구 주엽동" 13자)
  • 20자 제한으로 7자의 안전 여백 확보
  • 시/구/동 레벨에서는 전혀 문제없음

필드 분리 설계가 잘 되어있어서 제 초기 우려가 불필요했습니다. 현재 20자 제한 유지하는 게 맞겠네요.

detailAddress 필드가 별도로 있어서 구체적인 건물명/층수는 거기서 처리되니까 address는 행정구역만 깔끔하게 담는 현재 구조가 좋습니다.

    /|   /|   
   ( ^.^  ^.^ )
    |(_)(_)|
    /       \
   /  happy  \
  (  learned  )
   \   new   /
    \ thing /
     \_____/

✏️ Learnings added
Learnt from: buzz0331
PR: CHA-CALL/ChaCall-Server#30
File: src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/CreateReservationRequest.java:19-0
Timestamp: 2025-09-22T08:11:41.789Z
Learning: CreateReservationRequest의 address 필드는 시/구/동 수준의 행정구역만 담고, detailAddress 필드에 구체적인 건물명/층수 등이 분리되어 있음. 이 경우 address 필드의 20자 제한은 대부분의 한국 행정구역명에 충분함.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

Comment on lines +24 to 25
@Size(max = 20, message = "예약 상세 주소는 공백 포함 최대 20자까지 입력 가능합니다.")
String detailAddress,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

상세 주소도 20자는 부족합니다.

동·호수·상세 안내 문구 등을 고려해 100자 권장.

-        @Size(max = 20, message = "예약 상세 주소는 공백 포함 최대 20자까지 입력 가능합니다.")
+        @Size(max = 100, message = "예약 상세 주소는 공백 포함 최대 100자까지 입력 가능합니다.")
📝 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
@Size(max = 20, message = "예약 상세 주소는 공백 포함 최대 20자까지 입력 가능합니다.")
String detailAddress,
@Size(max = 100, message = "예약 상세 주소는 공백 포함 최대 100자까지 입력 가능합니다.")
String detailAddress,
🤖 Prompt for AI Agents
In
src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/CreateReservationRequest.java
around lines 24-25, the @Size(max = 20) on detailAddress is too small — increase
the max to 100 and update the validation message accordingly (e.g., "예약 상세 주소는
공백 포함 최대 100자까지 입력 가능합니다.") so the annotation reflects the new limit and
user-facing text matches it.

Comment on lines +96 to 103
public BaseResponse<ReservationStatusResponse> getReservationStatus(
@Parameter(description = "예약 ID", example = "1") @PathVariable final Long reservationId,
@Parameter(hidden = true) @UserId final Long userId
) {
return BaseResponse.ok(
reservationService.getReservationStatus(reservationId, userId)
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

권한 검증 경로 불일치: 사장님도 조회/취소 가능해야 함

설명에 따르면 ‘사장님, 일반 유저 모두’ 상태 조회/취소가 가능해야 합니다. 그러나 ReservationService.getReservationStatus(...)updateReservationStatus(...)에서 CANCELLED/REQUESTED 분기 시 memberValidator.validateAndGetMember(userId)를 사용하고 있어 사장님(OWNER)은 차단될 가능성이 큽니다.

개선 제안(서비스 레이어에서 롤-불문 사용자 조회로 통일):

  • 공통 유저 조회 헬퍼 추가(OWNER→없으면 MEMBER 순으로 검증) 또는 UserRepository 직접 조회 후 도메인에서 권한 검증.
  • getReservationStatus, CANCELLED/REQUESTED 분기도 동일 적용.

검증 스크립트:


🏁 Script executed:

#!/bin/bash
# CANCELLED 분기에서 memberValidator 강제 사용 여부 확인
rg -n -C3 'updateReservationStatus\s*\(' src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java
rg -n -C2 'getReservationStatus\s*\(' src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java

Length of output: 624


권한 검증 경로 불일치 — 서비스에서 OWNER도 허용하도록 롤-불문 조회로 통일 필요

ReservationService의 getReservationStatus/updateReservationStatus가 memberValidator.validateAndGetMember(userId)를 호출해 사장(OWNER) 접근이 차단됩니다.
수정 위치: src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java — updateReservationStatus (≈52–55), getReservationStatus (≈70–71)

권장 해결책(간단히):

  • 공통 유저 조회 헬퍼 추가: OWNER 우선 조회 → 없으면 MEMBER 조회(예: validateAndGetUserAllowOwnerOrMember(userId)), 또는
  • UserRepository.findById(userId)로 직접 조회한 뒤 도메인/서비스에서 권한 판정

CANCELLED/REQUESTED 분기에도 동일한 검증 경로 적용 필요.

Comment on lines 81 to +87
.authorizeHttpRequests(auth -> auth // 개발시동안 임시로 모든 경로 허용
.requestMatchers("/**").permitAll()
)
// .authorizeHttpRequests(auth -> auth
// .requestMatchers(WHITELIST).permitAll()
// .anyRequest().authenticated()
// )
.authorizeHttpRequests(auth -> auth
.requestMatchers(WHITELIST).permitAll()
.anyRequest().authenticated()
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

보안 설정 충돌: / permitAll이 남아 있어 전체 공개됩니다**

두 번의 authorizeHttpRequests 체인 중 첫 번째에서 /** permitAll을 선언해 두 번째 화이트리스트 기반 설정이 무력화됩니다. 반드시 제거하세요.

적용 제안:

-                .authorizeHttpRequests(auth -> auth   // 개발시동안 임시로 모든 경로 허용
-                        .requestMatchers("/**").permitAll()
-                )

추가 점검 스크립트(유사 permitAll 패턴 탐지):

#!/bin/bash
rg -nP --type=java 'requestMatchers\(\s*"/\*\*"\s*\)\.permitAll\(\)' src/main/java
🤖 Prompt for AI Agents
In src/main/java/konkuk/chacall/global/config/SecurityConfig.java around lines
81 to 87, remove the first authorizeHttpRequests block that calls
requestMatchers("/**").permitAll() so it no longer overrides the whitelist-based
rules; keep only the authorizeHttpRequests block that applies WHITELIST and
.anyRequest().authenticated(); after editing, run a quick search (e.g., ripgrep
pattern requestMatchers\(\s*"/\*\*"\s*\)\.permitAll\(\)) across src/main/java to
ensure no other global /** permitAll remains.

ksg1227
ksg1227 previously approved these changes Sep 22, 2025

@ksg1227 ksg1227 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

수고하셨습니다!

예약 상태 변경 쪽을 워낙 꼼꼼하게 구현해주셔서 흐름 상으로는 딱히 말씀드릴게 없네용 굿굿

Comment on lines +53 to +65
switch(request.reservationStatus()) {
case CONFIRMED_REQUESTED -> {
User member = memberValidator.validateAndGetMember(userId);
return reservationStatusService.updateReservationStatusToConfirmedRequested(reservationId, request, member);
}
case CONFIRMED -> {
User owner = ownerValidator.validateAndGetOwner(userId);
return reservationStatusService.updateReservationStatusToConfirmed(reservationId, request, owner);
}
case CANCELLED, CANCELLED_REQUESTED -> {
User user = memberValidator.validateAndGetMember(userId);
return reservationStatusService.updateReservationStatusToCancelled(reservationId, request, user);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

상태에 따라 멤버, 사장님 권한을 다르게 확인하는 군여 꼼꼼하네요 좋습니다


private void updateReservationStatus(Reservation reservation, UpdateReservationStatusRequest request) {
reservation.updateStatus(request.reservationStatus());
reservationRepository.save(reservation);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

p3: 별 것 아니긴 한데, save 를 명시적으로 해주지 않아도 변경감지를 통해서 update 쿼리가 자동으로 날라갈 것 같긴 합니당

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

맞네요. 업데이트할때 다 명시하지 않았으니 여기서도 제거하겠습니다.

Comment on lines +28 to +38
// PENDING -> CONFIRMED_REQUESTED -> CONFIRMED -> CANCELLED_REQUESTED -> CANCELLED
private static final Map<ReservationStatus, Set<ReservationStatus>> TRANSITIONS;
static {
Map<ReservationStatus, Set<ReservationStatus>> m = new EnumMap<>(ReservationStatus.class);
m.put(PENDING, EnumSet.of(CONFIRMED_REQUESTED));
m.put(CONFIRMED_REQUESTED, EnumSet.of(CONFIRMED));
m.put(CONFIRMED, EnumSet.of(CANCELLED_REQUESTED));
m.put(CANCELLED_REQUESTED, EnumSet.of(CANCELLED));
m.put(CANCELLED, EnumSet.noneOf(ReservationStatus.class));
TRANSITIONS = Map.copyOf(m);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

오호 Map 으로 다음상태를 관리하는 것 좋네요! 좀 더 꼼꼼하게 확인이 가능할 것 같습니다.

@Schema(description = "예약금 (0 이상)", example = "50000")
@NotNull(message = "예약금은 필수 입력 값입니다.")
@PositiveOrZero(message = "예약금은 0 이상이어야 합니다.")
@Digits(integer = 10, fraction = 0, message = "예약금은 공백 포함 최대 15자리까지 입력 가능합니다.")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

현재 최대 10자리 정수만 받도록 되어있는 것 같아서 확인 한 번 부탁드립니다!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

아 pm님이 15자리를 요구사항으로 하셨는데 integer가 어차피 10자리 정수까지 담을 수 있는 자료형이라 사이즈를 바꾸었습니다! 에러메시지 수정하겠습니다!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (2)
src/main/java/konkuk/chacall/domain/reservation/application/status/ReservationStatusService.java (1)

45-45: 주석 오타를 수정하세요.

CANCELLED_REQUESTED와 CONFIRMED 대신 CANCELLED_REQUESTED와 CANCELLED가 올바른 표현입니다.

-        // CANCELLED_REQUESTED, CONFIRMED 모두 예약자, 사장님 모두 가능
+        // CANCELLED_REQUESTED, CANCELLED 모두 예약자, 사장님 모두 가능
src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/UpdateReservationRequest.java (1)

16-16: 상세 주소 20자 제한은 과도할 수 있음

건물명/동·호수/층수까지 포함 시 20자 초과가 빈번합니다. 50자 이상 권장.

적용 예:

-        @Size(max = 20, message = "예약 상세 주소는 공백 포함 최대 20자까지 입력 가능합니다.")
+        @Size(max = 50, message = "예약 상세 주소는 공백 포함 최대 50자까지 입력 가능합니다.")
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d7b4bc1 and c03adf8.

📒 Files selected for processing (4)
  • src/main/java/konkuk/chacall/domain/reservation/application/status/ReservationStatusService.java (1 hunks)
  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/CreateReservationRequest.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/UpdateReservationRequest.java (2 hunks)
  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/UpdateReservationStatusRequest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/CreateReservationRequest.java
  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/UpdateReservationStatusRequest.java
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-22T08:11:41.812Z
Learnt from: buzz0331
PR: CHA-CALL/ChaCall-Server#30
File: src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/CreateReservationRequest.java:19-0
Timestamp: 2025-09-22T08:11:41.812Z
Learning: CreateReservationRequest의 address 필드는 시/구/동 수준의 행정구역만 담고, detailAddress 필드에 구체적인 건물명/층수 등이 분리되어 있음. 이 경우 address 필드의 20자 제한은 대부분의 한국 행정구역명에 충분함.

Applied to files:

  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/UpdateReservationRequest.java
🧬 Code graph analysis (1)
src/main/java/konkuk/chacall/domain/reservation/application/status/ReservationStatusService.java (2)
src/main/java/konkuk/chacall/global/common/exception/EntityNotFoundException.java (1)
  • EntityNotFoundException (6-11)
src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java (1)
  • Service (19-74)
🔇 Additional comments (9)
src/main/java/konkuk/chacall/domain/reservation/application/status/ReservationStatusService.java (6)

19-28: 메소드 로직이 올바르게 구현되었습니다!

예약자 권한 검증과 상태 업데이트 처리가 적절하게 구현되어 있습니다.


30-39: 사장님 권한 검증이 적절합니다!

푸드트럭 소유자만 예약을 확정할 수 있도록 올바르게 구현되었습니다.


41-50: 취소 처리의 권한 검증이 양쪽 모두 가능하도록 잘 구현되었습니다!

예약자와 사장님 모두 취소할 수 있도록 validateAccessibleBy를 사용한 것이 적절합니다.


52-59: 상태 조회 로직이 적절합니다!

접근 권한을 확인한 후 예약 상태를 반환하는 로직이 올바르게 구현되었습니다.


26-27: 명시적인 save 호출 제거가 적절합니다.

이전 리뷰 코멘트에서 언급된 대로 JPA 더티 체킹을 통해 자동으로 업데이트되므로 명시적인 save 호출을 제거한 것이 좋습니다.

Also applies to: 37-38, 48-49


19-50: 트랜잭션 관리 확인 — 문제 없음.
ReservationService.updateReservationStatus 메서드(src/main/java/konkuk/chacall/domain/reservation/application/ReservationService.java, 약 라인 51)에 @transactional이 선언되어 있어 내부의 reservationStatusService 호출 시 상태 변경은 트랜잭션 내에서 처리·커밋됩니다.

src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/UpdateReservationRequest.java (3)

11-11: 주소 20자 제한 적절 — 기존 정책과 정합

CreateReservationRequest 관련 학습 노트(행정구역만 포함, 20자 충분)와 일치합니다.


35-35: 메뉴 50자 제한 — 요구사항/FE·DB 스키마와 일치 여부 확인

여러 항목 나열 시 50자가 빠듯할 수 있습니다. CreateReservationRequest와 동일 값인지, DB 컬럼 길이와도 맞는지 확인 부탁드립니다.


49-49: 기타 요청 200자 — DB 컬럼과 프론트 제약 합치 여부 확인

DB 컬럼 길이 및 프론트 입력 제한과 동일한지 확인 부탁드립니다.

Comment on lines +41 to 42
@Digits(integer = 10, fraction = 0, message = "예약금은 공백 포함 최대 10자리까지 입력 가능합니다.")
Integer deposit,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

@digits(10)와 Integer 타입 불일치로 바인딩 오류 위험

10자리 값(최대 9,999,999,999)은 Integer 범위를 초과합니다. Spring 바인딩 단계에서 400(BindingException)로 떨어져 Bean Validation 메시지가 노출되지 않을 수 있습니다.

권장 수정안(A): Long 사용 + 메시지 문구 보정

-        @Digits(integer = 10, fraction = 0, message = "예약금은 공백 포함 최대 10자리까지 입력 가능합니다.")
-        Integer deposit,
+        @Digits(integer = 10, fraction = 0, message = "예약금은 최대 10자리 정수까지 입력 가능합니다.")
+        Long deposit,

대안(B): Integer 유지 시 9자리로 제한하거나, @Max(2_147_483_647)로 명확히 제한하세요.

검증 스크립트(코드베이스 내 deposit 타입 일관성 확인):


🏁 Script executed:

#!/bin/bash
# deposit 필드 선언부와 타입을 검색하여 DTO/엔티티 간 타입 일관성 확인
rg -n -C2 --type=java '\b(Integer|Long|BigDecimal)\s+deposit\b'

Length of output: 2738


@digits(10)와 Integer 불일치 — deposit을 Long으로 변경하거나 제약을 9자리/@max로 제한

검증 결과 deposit은 아래 파일들에서 모두 Integer로 선언되어 있으며 @digits(integer=10)을 쓰고 있어, 10자리 입력(최대 9,999,999,999)은 Integer 범위를 초과해 Spring 바인딩 단계에서 400(BindingException)이 발생하여 Bean Validation 메시지가 나오지 않을 위험이 있습니다.

  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/UpdateReservationRequest.java:42
  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/CreateReservationRequest.java:50
  • src/main/java/konkuk/chacall/domain/reservation/presentation/dto/response/ReservationResponse.java:30
  • src/main/java/konkuk/chacall/domain/reservation/domain/value/ReservationInfo.java:39

권장 수정(일관성 있게 적용):

-        @Digits(integer = 10, fraction = 0, message = "예약금은 공백 포함 최대 10자리까지 입력 가능합니다.")
-        Integer deposit,
+        @Digits(integer = 10, fraction = 0, message = "예약금은 최대 10자리 정수까지 입력 가능합니다.")
+        Long deposit,

대안: Integer를 유지하려면 @digits(integer = 9, fraction = 0)로 제한하거나 @max(2_147_483_647)를 추가해 범위를 명시적으로 제한하세요.

📝 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
@Digits(integer = 10, fraction = 0, message = "예약금은 공백 포함 최대 10자리까지 입력 가능합니다.")
Integer deposit,
@Digits(integer = 10, fraction = 0, message = "예약금은 최대 10자리 정수까지 입력 가능합니다.")
Long deposit,
🤖 Prompt for AI Agents
In
src/main/java/konkuk/chacall/domain/reservation/presentation/dto/request/UpdateReservationRequest.java
around lines 41-42, the deposit field is declared as Integer but uses
@Digits(integer = 10) which allows values outside Integer range and can cause
binding errors; either change the field type to Long and keep @Digits(integer =
10, fraction = 0) (and update imports/any usages) or keep Integer and restrict
validation to @Digits(integer = 9, fraction = 0) or add @Max(2147483647) to
ensure the allowed range fits Integer; apply the same choice consistently in the
other reservation DTOs and value objects mentioned in the review.

@buzz0331 buzz0331 merged commit 3cd481d into develop Sep 23, 2025
2 checks passed
@buzz0331 buzz0331 deleted the feat/#29-reservation-state branch September 23, 2025 15:31
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