Skip to content

Conversation

@sjk4618
Copy link
Member

@sjk4618 sjk4618 commented Dec 12, 2025

🔥Pull requests

⛳️ 작업한 브랜치

👷 작업한 내용

  • 도어용 게스트 티켓 도어 확인 및 유효성 검증 api

🚨 참고 사항

@coderabbitai
Copy link

coderabbitai bot commented Dec 12, 2025

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • 게스트 도어 티켓 검증 API 및 스태프 확인 API 추가
    • 게스트 도어 관련 경로(api/guests/**) 인증 제외 적용
  • Other Changes

    • QR 코드에 사용되는 진입 URL이 "/entry/guest"로 변경됨
    • 티켓 검증 응답이 이벤트명과 티켓명만 반환하도록 간소화됨
    • 스태프 확인 요청의 필드 유효성 메시지(한국어) 추가
    • 일정 응답에 eventId(인코딩된 값)가 포함되도록 변경됨

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

Walkthrough

게스트 티켓 도어 확인·유효성 검증 API와 관련 도메인, 컴포넌트, 예외, DTO, 컨트롤러를 추가하고 QR 코드 경로 및 시큐리티 화이트리스트를 갱신했습니다. 또한 일부 예외 상속과 기존 엔티티/레포지토리에 접근자 및 조회 메서드를 추가했습니다.

Changes

Cohort / File(s) 변경 요약
엔티티 및 리포지토리
src/main/java/com/permitseoul/permitserver/domain/admin/guestticket/core/domain/entity/GuestTicketEntity.java, src/main/java/com/permitseoul/permitserver/domain/admin/guestticket/core/repository/GuestTicketRepository.java
GuestTicketEntity에 클래스 레벨 @Getter 추가(모든 필드에 getter 생성); GuestTicketRepositoryOptional<GuestTicketEntity> findByGuestTicketCode(String guestTicketCode) 메서드 추가
게스트 예외 계층
src/main/java/com/permitseoul/permitserver/domain/guest/GuestBaseException.java, src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestApiException.java, src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestNotFoundException.java, src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestTicketIllegalException.java
GuestBaseException 추가( PermitGlobalException 확장), GuestApiException(추상)·GuestNotFoundException·GuestTicketIllegalException 추가
게스트 API (컨트롤러·예외핸들러·DTO)
src/main/java/com/permitseoul/permitserver/domain/guest/api/controller/GuestController.java, src/main/java/com/permitseoul/permitserver/domain/guest/api/GuestExceptionHandler.java, src/main/java/com/permitseoul/permitserver/domain/guest/api/dto/req/GuestTicketConfirmRequest.java, src/main/java/com/permitseoul/permitserver/domain/guest/api/dto/res/GuestTicketValidateResponse.java
게스트 티켓 유효성 검증(GET) 및 스태프 확인(POST) 엔드포인트 추가, 예외 핸들러 추가, 요청 레코드(GuestTicketConfirmRequest) 및 응답 레코드(GuestTicketValidateResponse) 변경/추가
게스트 서비스·컴포넌트·도메인 모델
src/main/java/com/permitseoul/permitserver/domain/guest/api/service/GuestService.java, src/main/java/com/permitseoul/permitserver/domain/guest/core/component/GuestRetriever.java, src/main/java/com/permitseoul/permitserver/domain/guest/core/component/GuestUpdater.java, src/main/java/com/permitseoul/permitserver/domain/guest/core/domain/GuestTicket.java
GuestServicevalidateGuestTicketconfirmGuestTicketByStaff 구현(예외 매핑 포함), GuestRetriever/GuestUpdater 컴포넌트 추가, 불변 도메인 GuestTicket 추가 및 fromEntity 매핑
유틸리티·예외·보안 설정 변경
src/main/java/com/permitseoul/permitserver/domain/admin/util/QrCodeUtil.java, src/main/java/com/permitseoul/permitserver/domain/eventimage/EventImageBaseException.java, src/main/java/com/permitseoul/permitserver/global/config/SecurityConfig.java
QR 코드 URL 경로 상수 "/entry/" → "/entry/guest"로 변경; EventImageBaseExceptionPermitGlobalException 상속으로 변경; SecurityConfig 화이트리스트에 "api/guests/**" 항목 추가
어드민 티켓·타임테이블 관련 변경
src/main/java/com/permitseoul/permitserver/domain/admin/timetable/base/api/dto/res/TimetableInfoResponse.java, src/main/java/com/permitseoul/permitserver/domain/admin/timetable/base/api/service/AdminTimetableService.java
TimetableInfoResponseeventId 필드 추가 및 팩토리 시그니처 변경; AdminTimetableService에서 SecureUrlUtil을 사용해 eventId 인코딩을 포함하도록 호출 수정

Sequence Diagram

sequenceDiagram
    participant Client
    participant Controller as GuestController
    participant Service as GuestService
    participant GuestRetriever
    participant EventRetriever
    participant Repo as GuestTicketRepository/EventRepository
    participant Entity as GuestTicketEntity
    participant Updater as GuestUpdater

    rect rgb(200,220,255)
    note over Client,Controller: 유효성 검증 흐름
    Client->>Controller: GET /api/guests/tickets/door/validation/{ticketCode}
    Controller->>Service: validateGuestTicket(ticketCode)
    Service->>GuestRetriever: findGuestTicketByTicketCode(ticketCode)
    GuestRetriever->>Repo: findByGuestTicketCode(ticketCode)
    Repo-->>GuestRetriever: GuestTicketEntity
    GuestRetriever-->>Service: GuestTicket(domain)
    Service->>Service: validateGuestTicketStatus(status)
    Service->>EventRetriever: findEventByEventId(eventId)
    EventRetriever->>Repo: findEventById(eventId)
    Repo-->>EventRetriever: Event
    EventRetriever-->>Service: Event
    Service-->>Controller: GuestTicketValidateResponse
    Controller-->>Client: 200 OK + BaseResponse
    end

    rect rgb(220,200,255)
    note over Client,Controller: 스태프 확인(사용 처리) 흐름
    Client->>Controller: POST /api/guests/tickets/door/staff/confirm
    Controller->>Service: confirmGuestTicketByStaff(ticketCode, checkCode)
    Service->>GuestRetriever: findGuestTicketEntityByTicketCode(ticketCode)
    GuestRetriever->>Repo: findByGuestTicketCode(ticketCode)
    Repo-->>GuestRetriever: GuestTicketEntity
    GuestRetriever-->>Service: GuestTicketEntity
    Service->>Service: validateGuestTicketStatus(status)
    Service->>EventRetriever: findEventByEventId(eventId)
    EventRetriever->>Repo: findEventById(eventId)
    Repo-->>EventRetriever: Event
    EventRetriever-->>Service: Event
    Service->>Service: validateGuestTicketByCheckCode(...)
    Service->>Updater: updateGuestTicketStatus(entity, USED)
    Updater->>Entity: updateStatus(USED)
    Updater-->>Service: void
    Service-->>Controller: void
    Controller-->>Client: 200 OK + BaseResponse
    end

    rect rgb(255,240,200)
    note over Service: 에러 흐름 예시
    Service->>Service: 티켓/이벤트 미발견 → GuestNotFoundException
    Service->>Service: 이미 사용된 티켓 → GuestTicketIllegalException
    Service->>Service: 체크코드 불일치 → GuestTicketIllegalException
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • 주의할 파일/영역:
    • src/.../guest/api/service/GuestService.java — 예외 매핑, 트랜잭션 경계, 상태 검증 로직
    • src/.../guest/core/component/GuestRetriever.java — repository 조회 및 예외 일관성
    • src/.../admin/util/QrCodeUtil.java — QR 경로 변경이 QR 생성·해석 흐름에 미치는 영향
    • src/.../eventimage/EventImageBaseException.java — PermitGlobalException 상속 변경으로 인한 예외 체인 영향
    • SecurityConfig 화이트리스트 추가로 인한 의도된 공개 경로 검증

Possibly related PRs

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning 대부분의 변경사항은 게스트 도어 확인 기능과 관련이 있지만, TimetableInfoResponse 및 AdminTimetableService 변경사항은 명시된 이슈 #197의 범위 밖입니다. TimetableInfoResponse와 AdminTimetableService의 변경사항을 별도 PR로 분리하거나, 해당 변경사항이 게스트 티켓 기능과의 연관성을 설명해주세요.
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% 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
Title check ✅ Passed 제목은 게스트 티켓 도어 확인 및 유효성 검증 API 구현이라는 핵심 변경사항을 명확하게 요약하고 있으며, 관련 이슈 번호 #197을 포함하고 있습니다.
Description check ✅ Passed 설명은 게스트 티켓 도어 확인 및 유효성 검증 API라는 변경사항과 관련이 있으며, 해결하는 이슈(#197)를 명시하고 있습니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경사항은 게스트 티켓의 도어 확인 및 유효성 검증 API 구현이라는 이슈 #197의 목표를 충족합니다. 새로운 GuestController, GuestService, 예외 처리, 리포지토리 쿼리 메서드 등이 추가되었습니다.
✨ 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/#197

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

🧹 Nitpick comments (6)
src/main/java/com/permitseoul/permitserver/domain/admin/guestticket/core/domain/entity/GuestTicketEntity.java (1)

10-10: 클래스 레벨 @Getter 추가 승인, 중복 어노테이션 제거 권장

클래스 레벨 @Getter 추가로 인해 16번과 27번 라인의 필드 레벨 @Getter 어노테이션이 중복됩니다. 코드 정리를 위해 해당 필드 레벨 어노테이션 제거를 권장합니다.

     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
-    @Getter
     @Column(name = "guest_ticket_id")
     private Long guestTicketId;

     @Column(name = "event_id", nullable = false)
     private long eventId;

     @Column(name = "guest_id", nullable = false)
     private long guestId;

     @Column(name = "guest_ticket_code", nullable = false)
-    @Getter
     private String guestTicketCode;
src/main/java/com/permitseoul/permitserver/domain/guest/core/component/GuestUpdater.java (1)

7-12: AdminGuestTicketUpdater와 중복 코드 존재

AdminGuestTicketUpdater와 동일한 구현입니다. 도메인 분리 목적이라면 현재 구조가 적절하나, 두 도메인이 동일한 GuestTicketEntity를 공유하므로 공통 컴포넌트로 통합하는 것을 고려해볼 수 있습니다.

src/main/java/com/permitseoul/permitserver/domain/guest/api/service/GuestService.java (2)

15-17: 사용하지 않는 import 제거 필요

NotFoundTicketException, TicketNotFoundException, TicketTypeNotfoundException이 import되어 있지만 코드에서 사용되지 않습니다.

다음 diff를 적용하여 사용하지 않는 import를 제거하세요:

-import com.permitseoul.permitserver.domain.ticket.api.exception.NotFoundTicketException;
-import com.permitseoul.permitserver.domain.ticket.core.exception.TicketNotFoundException;
-import com.permitseoul.permitserver.domain.tickettype.core.exception.TicketTypeNotfoundException;

32-44: 읽기 전용 트랜잭션 어노테이션 추가 권장

데이터베이스에서 조회만 수행하는 메서드이므로 @Transactional(readOnly = true)를 추가하는 것이 좋습니다. 이는 성능 최적화와 의도를 명확하게 표현하는 데 도움이 됩니다.

다음 diff를 적용하세요:

+@Transactional(readOnly = true)
 public GuestTicketValidateResponse validateGuestTicket(final String ticketCode) {
src/main/java/com/permitseoul/permitserver/domain/guest/api/controller/GuestController.java (2)

21-26: 경로 변수 검증 추가 권장

ticketCode 경로 변수에 대한 검증이 없습니다. 빈 문자열이나 유효하지 않은 형식의 입력을 방지하기 위해 @NotBlank 또는 다른 적절한 검증 어노테이션을 추가하는 것을 고려하세요.

다음 diff를 적용하세요:

+import jakarta.validation.constraints.NotBlank;
+
 @GetMapping("/tickets/door/validation/{ticketCode}")
 public ResponseEntity<BaseResponse<?>> validateGuestTicket(
-        @PathVariable final String ticketCode
+        @PathVariable @NotBlank(message = "티켓 코드는 필수입니다") final String ticketCode
 ) {

28-28: 주석 명확성 검토

주석에 "스텝"이라고 표기되어 있는데, "스태프"(staff)를 의미하는 것인지 확인이 필요합니다. 메서드 이름은 confirmGuestTicketByStaffAtDoor이므로 일관성을 위해 주석도 "스태프"로 수정하는 것이 좋습니다.

-//도어용 게스트 티켓 스텝 확인 api
+//도어용 게스트 티켓 스태프 확인 api
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 68b8d7b and fed0747.

📒 Files selected for processing (17)
  • src/main/java/com/permitseoul/permitserver/domain/admin/guestticket/core/domain/entity/GuestTicketEntity.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/admin/guestticket/core/repository/GuestTicketRepository.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/admin/util/QrCodeUtil.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/eventimage/EventImageBaseException.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/GuestBaseException.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/api/GuestExceptionHandler.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/api/controller/GuestController.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/api/dto/req/GuestTicketConfirmRequest.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/api/dto/res/GuestTicketValidateResponse.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestApiException.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestNotFoundException.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestTicketIllegalException.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/api/service/GuestService.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/core/component/GuestRetriever.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/core/component/GuestUpdater.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/core/domain/GuestTicket.java (1 hunks)
  • src/main/java/com/permitseoul/permitserver/global/config/SecurityConfig.java (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: sjk4618
Repo: PERMIT-SEOUL/permit-server PR: 48
File: src/main/java/com/permitseoul/permitserver/domain/guest/core/domain/entity/GuestEntity.java:31-37
Timestamp: 2025-07-15T09:37:32.765Z
Learning: sjk4618 prefers to implement factory methods or public constructors for entities when they are actually needed, rather than creating them proactively.
🧬 Code graph analysis (10)
src/main/java/com/permitseoul/permitserver/domain/eventimage/EventImageBaseException.java (1)
src/main/java/com/permitseoul/permitserver/global/exception/PermitGlobalException.java (1)
  • PermitGlobalException (3-4)
src/main/java/com/permitseoul/permitserver/domain/guest/api/GuestExceptionHandler.java (1)
src/main/java/com/permitseoul/permitserver/global/response/ApiResponseUtil.java (1)
  • ApiResponseUtil (7-29)
src/main/java/com/permitseoul/permitserver/domain/guest/api/service/GuestService.java (7)
src/main/java/com/permitseoul/permitserver/domain/admin/guestticket/core/exception/GuestTicketNotFoundException.java (1)
  • GuestTicketNotFoundException (3-4)
src/main/java/com/permitseoul/permitserver/domain/event/core/exception/EventNotfoundException.java (1)
  • EventNotfoundException (3-4)
src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestNotFoundException.java (1)
  • GuestNotFoundException (5-9)
src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestTicketIllegalException.java (1)
  • GuestTicketIllegalException (5-9)
src/main/java/com/permitseoul/permitserver/domain/ticket/api/exception/NotFoundTicketException.java (1)
  • NotFoundTicketException (5-9)
src/main/java/com/permitseoul/permitserver/domain/ticket/core/exception/TicketNotFoundException.java (1)
  • TicketNotFoundException (3-4)
src/main/java/com/permitseoul/permitserver/domain/tickettype/core/exception/TicketTypeNotfoundException.java (1)
  • TicketTypeNotfoundException (3-4)
src/main/java/com/permitseoul/permitserver/domain/guest/api/controller/GuestController.java (1)
src/main/java/com/permitseoul/permitserver/global/response/ApiResponseUtil.java (1)
  • ApiResponseUtil (7-29)
src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestApiException.java (1)
src/main/java/com/permitseoul/permitserver/domain/guest/GuestBaseException.java (1)
  • GuestBaseException (5-6)
src/main/java/com/permitseoul/permitserver/domain/guest/GuestBaseException.java (1)
src/main/java/com/permitseoul/permitserver/global/exception/PermitGlobalException.java (1)
  • PermitGlobalException (3-4)
src/main/java/com/permitseoul/permitserver/domain/guest/core/component/GuestUpdater.java (2)
src/main/java/com/permitseoul/permitserver/domain/guest/core/component/GuestRetriever.java (1)
  • Component (10-22)
src/main/java/com/permitseoul/permitserver/domain/admin/guestticket/core/component/AdminGuestTicketUpdater.java (1)
  • Component (7-13)
src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestTicketIllegalException.java (1)
src/main/java/com/permitseoul/permitserver/domain/ticket/api/exception/IllegalTicketException.java (1)
  • IllegalTicketException (5-9)
src/main/java/com/permitseoul/permitserver/domain/admin/guestticket/core/domain/entity/GuestTicketEntity.java (1)
src/main/java/com/permitseoul/permitserver/domain/admin/guestticket/api/exception/AdminGuestTicketApiException.java (1)
  • Getter (8-12)
src/main/java/com/permitseoul/permitserver/domain/guest/core/component/GuestRetriever.java (2)
src/main/java/com/permitseoul/permitserver/domain/admin/guestticket/core/exception/GuestTicketNotFoundException.java (1)
  • GuestTicketNotFoundException (3-4)
src/main/java/com/permitseoul/permitserver/domain/guest/core/component/GuestUpdater.java (1)
  • Component (7-13)
🔇 Additional comments (16)
src/main/java/com/permitseoul/permitserver/domain/eventimage/EventImageBaseException.java (1)

3-5: LGTM! 글로벌 예외 계층 구조와 일관성 있게 정렬되었습니다.

PermitGlobalException을 상속하도록 변경하여 프로젝트의 예외 처리 패턴과 일관성을 유지하고 있습니다.

src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestNotFoundException.java (1)

5-9: LGTM! 표준 예외 패턴을 따르고 있습니다.

GuestApiException을 확장하고 ErrorCode를 받는 생성자를 제공하는 구조가 프로젝트의 다른 도메인 예외(예: IllegalTicketException)와 일관성 있게 구현되었습니다.

src/main/java/com/permitseoul/permitserver/domain/guest/GuestBaseException.java (1)

5-6: LGTM! 게스트 도메인 예외 계층의 기반을 확립했습니다.

PermitGlobalException을 확장하여 프로젝트의 글로벌 예외 계층 구조와 일관성을 유지하며, GuestApiException의 상위 클래스로 적절히 기능합니다.

src/main/java/com/permitseoul/permitserver/domain/admin/guestticket/core/repository/GuestTicketRepository.java (1)

13-13: LGTM! 티켓 코드로 게스트 티켓을 조회하는 메서드가 올바르게 추가되었습니다.

Optional을 반환하여 null 안전성을 보장하며, Spring Data JPA의 파생 쿼리 명명 규칙을 따르고 있습니다.

src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestTicketIllegalException.java (1)

5-9: LGTM! 기존 패턴과 일관성 있는 예외 클래스입니다.

IllegalTicketException과 동일한 구조를 따르고 있어 프로젝트의 예외 처리 패턴과 일관성을 유지합니다.

src/main/java/com/permitseoul/permitserver/domain/guest/api/exception/GuestApiException.java (1)

8-12: LGTM! 잘 설계된 API 예외 기반 클래스입니다.

Lombok을 활용하여 보일러플레이트를 최소화하고, ErrorCode 필드를 통해 구조화된 에러 정보를 전달할 수 있도록 설계되었습니다. GuestBaseException을 확장하여 예외 계층 구조가 명확합니다.

src/main/java/com/permitseoul/permitserver/domain/guest/api/dto/req/GuestTicketConfirmRequest.java (1)

5-12: LGTM! 불변 DTO로서 적절하게 구현되었습니다.

Java record를 사용하여 불변성을 보장하고, @NotBlank 검증 어노테이션으로 필수 필드를 강제하며, 한국어 검증 메시지가 명확하게 작성되었습니다.

src/main/java/com/permitseoul/permitserver/domain/guest/api/GuestExceptionHandler.java (1)

10-16: LGTM!

@RestControllerAdvicebasePackages 범위 설정과 GuestApiException 처리 로직이 적절합니다. ApiResponseUtil.failure()를 통한 표준화된 응답 반환 방식이 기존 코드베이스와 일관성을 유지합니다.

src/main/java/com/permitseoul/permitserver/domain/guest/api/dto/res/GuestTicketValidateResponse.java (1)

8-20: LGTM!

레코드 구조와 @JsonFormat 설정이 적절합니다. of() 팩토리 메서드에서 날짜 필드를 null로 반환하는 것이 게스트 티켓의 의도된 동작인지 확인해 주세요.

src/main/java/com/permitseoul/permitserver/domain/guest/core/component/GuestRetriever.java (2)

4-4: admin 도메인 예외 사용에 대한 확인 필요

GuestTicketNotFoundExceptionadmin.guestticket.core.exception 패키지에서 import됩니다. guest 도메인에서 admin 도메인의 예외를 직접 참조하는 것이 의도된 설계인지 확인이 필요합니다. guest 도메인 전용 예외 사용을 고려해보세요.


15-21: LGTM!

엔티티와 도메인 모델을 각각 반환하는 두 메서드 구조가 적절합니다. orElseThrow를 통한 예외 처리가 일관되게 적용되어 있습니다.

src/main/java/com/permitseoul/permitserver/domain/guest/api/service/GuestService.java (2)

34-34: 도메인 객체 사용의 일관성 검토 필요

validateGuestTicket 메서드는 GuestTicket 도메인 객체를 사용하고(Line 34), confirmGuestTicketByStaff 메서드는 GuestTicketEntity를 사용합니다(Line 49). 업데이트 작업을 위해 엔티티가 필요한 것은 이해되지만, 일관성을 위해 두 메서드 모두 도메인 객체를 사용하고 필요할 때만 엔티티로 변환하는 방식을 고려해보세요.

현재 구현이 의도적인 설계인지 확인이 필요합니다. GuestRetriever에서 findGuestTicketByTicketCodefindGuestTicketEntityByTicketCode 두 메서드를 모두 제공하는 이유를 검토하세요.

Also applies to: 49-49


39-43: 계층별 예외 처리 패턴이 프로젝트 전반에서 일관되게 적용되고 있습니다.

코어 계층의 예외를 API 계층의 예외로 변환하는 패턴이 ReservationService, PaymentService, EventService 등 다른 서비스들에서도 동일하게 적용되고 있습니다. GuestService의 예외 처리 방식은 프로젝트의 표준 전략과 일치합니다.

src/main/java/com/permitseoul/permitserver/domain/guest/core/domain/GuestTicket.java (2)

20-29: 팩토리 메서드 구현 적절함

엔티티에서 도메인 객체로의 변환을 위한 정적 팩토리 메서드가 잘 구현되어 있습니다. 학습 내역에 따르면, 사용자는 필요할 때 팩토리 메서드를 구현하는 것을 선호하며, 이 구현은 해당 선호도와 일치합니다.


13-15: 필드 타입 차이는 설계 의도가 명확합니다

GuestTicketEntity를 확인한 결과, 타입 차이는 의도적이고 적절합니다:

  • guestTicketId@Id @GeneratedValue로 선언되어 있어 자동 생성되므로 Long (nullable)이 정확합니다
  • eventIdguestId@Column(nullable = false)로 명시되어 있어 long (primitive)이 적절합니다

현재 도메인 모델이 엔티티 설계를 정확하게 반영하고 있으므로 변경이 필요하지 않습니다.

src/main/java/com/permitseoul/permitserver/domain/guest/api/controller/GuestController.java (1)

29-35: POST 엔드포인트 구현 적절함

@Valid 어노테이션을 사용하여 요청 본문 검증이 올바르게 구현되어 있고, 서비스 메서드 호출 및 응답 반환이 적절합니다.

private static final int QR_SIZE = 256;
private static final String PNG = "PNG";
private static final String URL_PATH = "/entry/";
private static final String URL_PATH = "/entry/guest";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -name "QrCodeUtil.java" -type f -exec wc -l {} \;

Repository: PERMIT-SEOUL/permit-server

Length of output: 151


🏁 Script executed:

find . -name "QrCodeUtil.java" -type f -exec cat -n {} \;

Repository: PERMIT-SEOUL/permit-server

Length of output: 2509


🏁 Script executed:

# More specific search for /entry/ paths in controllers
rg -n --type=java '"/entry' -B 5 -A 5

Repository: PERMIT-SEOUL/permit-server

Length of output: 1349


🏁 Script executed:

# Search for any @GetMapping or @PostMapping with path variables
rg -n --type=java '@(Get|Post|Put|Patch|Delete)Mapping' -B 2 -A 5 | grep -E '(Mapping|entry|guest|ticketCode|@)' | head -100

Repository: PERMIT-SEOUL/permit-server

Length of output: 15668


🏁 Script executed:

# Search for any route or endpoint that contains "/entry"
rg -n --type=java 'RequestMapping|RestController|Controller' ./src/main/java/com/permitseoul/permitserver/domain/guest/ -B 1 -A 5

Repository: PERMIT-SEOUL/permit-server

Length of output: 2622


🏁 Script executed:

# Search for any TODO or FIXME comments related to entry or guest
rg -n 'TODO|FIXME' --type=java | grep -i 'entry\|guest' | head -20

Repository: PERMIT-SEOUL/permit-server

Length of output: 52


🏁 Script executed:

# Check git log for recent changes to QrCodeUtil
git log --oneline -20 -- src/main/java/com/permitseoul/permitserver/domain/admin/util/QrCodeUtil.java 2>/dev/null || echo "Git history not available"

Repository: PERMIT-SEOUL/permit-server

Length of output: 116


URL 경로에 구분자가 누락되어 QR 코드가 잘못된 URL을 생성합니다.

Line 31에서 baseUrl + URL_PATH + ticketCode로 URL을 구성하므로, 현재 변경사항은 다음과 같은 잘못된 URL을 생성합니다:

  • 결과: https://example.com/entry/guestTICKET123 (guest와 티켓코드 사이에 / 없음)
  • 예상: https://example.com/entry/guest/TICKET123

이로 인해 QR 코드를 스캔했을 때 라우팅 실패나 404 에러가 발생합니다. 경로 구분자를 추가하세요:

-    private static final String URL_PATH = "/entry/guest";
+    private static final String URL_PATH = "/entry/guest/";
📝 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
private static final String URL_PATH = "/entry/guest";
private static final String URL_PATH = "/entry/guest/";
🤖 Prompt for AI Agents
In src/main/java/com/permitseoul/permitserver/domain/admin/util/QrCodeUtil.java
around line 26, the constant URL_PATH is missing a trailing slash which causes
URLs like https://example.com/entry/guestTICKET123; change the constant to
include the path separator (e.g. "/entry/guest/") so concatenation baseUrl +
URL_PATH + ticketCode yields /guest/{ticketCode}; also defensively handle
possible double slashes by trimming a trailing slash from baseUrl before
concatenation or by using a proper URL join helper.

package com.permitseoul.permitserver.domain.guest.api.dto.res;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.permitseoul.permitserver.domain.ticket.api.dto.res.DoorValidateUserTicket;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

사용하지 않는 import 제거 필요

DoorValidateUserTicket import가 사용되지 않습니다. 제거해 주세요.

 import com.fasterxml.jackson.annotation.JsonFormat;
-import com.permitseoul.permitserver.domain.ticket.api.dto.res.DoorValidateUserTicket;

 import java.time.LocalDateTime;
📝 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
import com.permitseoul.permitserver.domain.ticket.api.dto.res.DoorValidateUserTicket;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
🤖 Prompt for AI Agents
src/main/java/com/permitseoul/permitserver/domain/guest/api/dto/res/GuestTicketValidateResponse.java
lines 4-4: the import of
com.permitseoul.permitserver.domain.ticket.api.dto.res.DoorValidateUserTicket is
unused; remove this import statement from the file and run a build/IDE
organize-imports to ensure no other unused imports remain.

"/api/tickets/door/validation/*",
"/api/notion/**"
"/api/notion/**",
"api/guests/**"
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

치명적: 경로 패턴에 선행 슬래시(/)가 누락되었습니다.

Line 43의 "api/guests/**" 패턴에 선행 슬래시가 없어 Spring Security의 requestMatchers가 올바르게 매칭하지 못합니다. 이로 인해 게스트 API 엔드포인트가 화이트리스트에 추가되지 않아 인증이 필요하게 되며, 이 PR의 핵심 기능이 작동하지 않습니다.

다음 diff를 적용하여 수정하세요:

-            "api/guests/**"
+            "/api/guests/**"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"api/guests/**"
"/api/guests/**"
🤖 Prompt for AI Agents
In src/main/java/com/permitseoul/permitserver/global/config/SecurityConfig.java
around line 43, the path pattern "api/guests/**" is missing a leading slash so
Spring Security requestMatchers won't match; update the pattern to include the
leading slash ("/api/guests/**") so the guest API endpoints are correctly
whitelisted by the security configuration.

@sjk4618 sjk4618 self-assigned this Dec 14, 2025
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

♻️ Duplicate comments (1)
src/main/java/com/permitseoul/permitserver/domain/guest/api/dto/res/GuestTicketValidateResponse.java (1)

3-7: 미사용 import 정리 필요 (DoorValidateUserTicket는 이전 코멘트와 동일 이슈)
현재 JsonFormat, DoorValidateUserTicket, LocalDateTime가 이 파일에서 사용되지 않습니다. IDE organize imports(또는 빌드 도구의 import 정리)로 제거해 주세요.

🧹 Nitpick comments (1)
src/main/java/com/permitseoul/permitserver/domain/guest/api/dto/res/GuestTicketValidateResponse.java (1)

8-14: "Guest Ticket" 하드코딩 문자열은 상수로 승격 권장
응답 스펙이 고정이더라도, 명칭 변경/i18n 대비를 위해 상수로 빼두는 편이 안전합니다(필요하면 eventName null 가드도 함께).

 public record GuestTicketValidateResponse(
         String eventName,
         String ticketName
 ) {
+    private static final String GUEST_TICKET_NAME = "Guest Ticket";
+
     public static GuestTicketValidateResponse of(final String eventName) {
-        return new GuestTicketValidateResponse(eventName, "Guest Ticket");
+        return new GuestTicketValidateResponse(eventName, GUEST_TICKET_NAME);
     }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fed0747 and 56bc3c9.

📒 Files selected for processing (3)
  • src/main/java/com/permitseoul/permitserver/domain/admin/timetable/base/api/dto/res/TimetableInfoResponse.java (3 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/admin/timetable/base/api/service/AdminTimetableService.java (3 hunks)
  • src/main/java/com/permitseoul/permitserver/domain/guest/api/dto/res/GuestTicketValidateResponse.java (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: sjk4618
Repo: PERMIT-SEOUL/permit-server PR: 48
File: src/main/java/com/permitseoul/permitserver/domain/guest/core/domain/entity/GuestEntity.java:31-37
Timestamp: 2025-07-15T09:37:32.765Z
Learning: sjk4618 prefers to implement factory methods or public constructors for entities when they are actually needed, rather than creating them proactively.
🔇 Additional comments (2)
src/main/java/com/permitseoul/permitserver/domain/admin/timetable/base/api/dto/res/TimetableInfoResponse.java (1)

4-4: 응답 DTO에 eventId 필드 추가를 확인했습니다.

인코딩된 eventId가 응답의 첫 번째 필드로 추가되었습니다. 구현은 올바르게 되어 있으나, 레코드 클래스의 필드 순서가 변경되면 직렬화된 JSON 응답의 필드 순서도 변경될 수 있습니다.

API 응답 형식이 변경되므로, 프론트엔드 팀이나 API 소비자에게 이 변경사항을 공지했는지 확인하세요.

Also applies to: 14-15, 24-24

src/main/java/com/permitseoul/permitserver/domain/admin/timetable/base/api/service/AdminTimetableService.java (1)

23-23: 타입 호환성은 Java의 자동 박싱으로 처리됩니다.

eventIdlong 타입(기본 타입)이고 SecureUrlUtil.encode(final Long id)Long 타입(래퍼 클래스)을 받습니다. 그러나 Java의 자동 박싱 기능으로 인해 long이 자동으로 Long으로 변환되므로 타입 호환성 문제는 없습니다.

}

return TimetableInfoResponse.of(
secureUrlUtil.encode(eventId),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for getTimetableInfo method definition and usages
rg -n --type java 'getTimetableInfo' -B 2 -A 10

Repository: PERMIT-SEOUL/permit-server

Length of output: 4130


🏁 Script executed:

#!/bin/bash
# Find TimetableInfoResponse class definition
fd -t f 'TimetableInfoResponse.java'

Repository: PERMIT-SEOUL/permit-server

Length of output: 179


🏁 Script executed:

#!/bin/bash
# Look at the AdminTimetableService file around line 99 to understand context
sed -n '85,115p' src/main/java/com/permitseoul/permitserver/domain/admin/timetable/base/api/service/AdminTimetableService.java

Repository: PERMIT-SEOUL/permit-server

Length of output: 1467


🏁 Script executed:

#!/bin/bash
# Examine TimetableInfoResponse class
cat src/main/java/com/permitseoul/permitserver/domain/admin/timetable/base/api/dto/res/TimetableInfoResponse.java

Repository: PERMIT-SEOUL/permit-server

Length of output: 1598


🏁 Script executed:

#!/bin/bash
# Check git history to see if eventId field was recently added
cd src/main/java/com/permitseoul/permitserver/domain/admin/timetable/base/api/dto/res && \
git log --oneline -20 -- TimetableInfoResponse.java 2>/dev/null || echo "Git history not available"

Repository: PERMIT-SEOUL/permit-server

Length of output: 117


API 응답 구조 변경 사항을 검토하세요.

TimetableInfoResponseeventId 필드가 새로 추가되었으며, 이로 인해 기존 API 응답 구조가 변경되었습니다. 이 변경사항은 API 응답 스키마를 변경하므로, 클라이언트(프론트엔드, 외부 시스템 등)의 JSON 직렬화/역직렬화 로직에 영향을 미칠 수 있습니다. 버전 관리나 하위 호환성 유지 방안을 검토하세요.

@sjk4618 sjk4618 merged commit 5fe4484 into dev Dec 14, 2025
2 checks passed
@sjk4618 sjk4618 deleted the feat/#197 branch December 14, 2025 08:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 게스트 티켓 도어 확인 및 유효성 검증 api

2 participants