Skip to content

[FEAT] 공연 : 공연 티켓 예매 Saga 정상 흐름 구현#29

Open
boogiewooki02 wants to merge 3 commits into
mainfrom
feat/ticket-reservation-saga
Open

[FEAT] 공연 : 공연 티켓 예매 Saga 정상 흐름 구현#29
boogiewooki02 wants to merge 3 commits into
mainfrom
feat/ticket-reservation-saga

Conversation

@boogiewooki02
Copy link
Copy Markdown
Collaborator

‼️ 관련 이슈

close #


🔎 개요

공연 티켓 예매 Saga 정상 흐름을 구현했습니다.
로그인한 사용자가 공연을 선택한 뒤 좌석 확인, 좌석 선점, 예매 생성, QR 티켓
발급, 예매 완료까지 한 번에 진행할 수 있습니다.


📝 작업 내용

  • 공연 조회 API 추가
    • GET /api/performances
    • GET /api/performances/{performanceId}
  • 공연 데이터 구조 및 인메모리 데이터소스 추가
  • 티켓 예매 데이터 구조 추가
  • 티켓 예매 상태값 정의
    • SEAT_HELD
    • RESERVATION_CREATED
    • QR_ISSUED
    • COMPLETED
    • CANCELLED
  • 티켓 예매 Saga API 추가
    • POST /api/ticket-reservations
    • GET /api/ticket-reservations/me
    • GET /api/ticket-reservations/{reservationId}
  • 정상 Saga 흐름 구현
    • 좌석 확인 → 좌석 선점 → 예매 생성 → QR 발급 → 예매 완료
  • 잔여 좌석 확인 및 매진 차단 로직 구현
  • 동일 사용자의 같은 공연 중복 예매 차단
  • QR 티켓 발급 로직 구현
    • /performances/tickets/{reservationId} 형태의 티켓 확인 URL 발급
  • 공연 목록 화면을 API 기반으로 변경
  • 공연 상세 화면 추가
  • 로그인 사용자 예매 버튼 및 예매 완료 패널 추가
  • 예매 완료 후 QR 티켓 표시
  • QR 티켓 확인 화면 추가
  • 사용자 화면에서는 내부 Saga 단계명을 노출하지 않도록 정리
    • Saga 로그는 API 응답과 테스트 검증에는 유지

👀 변경 사항

  • 공연 예매는 로그인한 사용자만 진행할 수 있습니다.
  • 공연 목록/상세 조회는 인증 없이 가능합니다.
  • 티켓 예매 생성 및 티켓 단건 조회는 인증이 필요합니다.
  • 티켓 단건 조회는 본인 예매만 확인할 수 있도록 백엔드에서 검증합니다.
  • 예매 완료 화면에는 QR 티켓과 예매 번호만 노출합니다.
  • SEAT_CHECKED, SEAT_HELD 등 내부 Saga 단계는 사용자 화면에 표시하지 않
    습니다.
  • 백엔드 API 응답에는 Saga 정상 흐름 검증을 위한 sagaLogs가 포함됩니다.

✅ 테스트

  • 백엔드 테스트 추가
    • PerformanceRepositoryTest
    • PerformanceServiceTest
    • TicketReservationControllerTest
    • TicketReservationServiceTest
  • 프론트엔드 테스트 추가
    • PerformanceCard.test.tsx
    • PerformanceReservationPanel.test.tsx

📸 스크린샷 (Optional)

스크린샷 2026-05-26 오후 5 36 20

@boogiewooki02 boogiewooki02 self-assigned this May 26, 2026
@boogiewooki02 boogiewooki02 added the enhancement New feature or request label May 26, 2026
Copy link
Copy Markdown
Owner

@dldusgh318 dldusgh318 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다~ 리뷰확인부탁드려요!

if (request == null || request.performanceId() == null) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "예매할 공연 정보가 필요합니다.");
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

좌석 초과 시의 예외 핸들링도 필요할 거 같습니다

LocalDateTime issuedAt = LocalDateTime.now();
reservation.issueQr(ticketQrCodeIssuer.issue(reservation), issuedAt);
ticketReservationRepository.update(reservation);
sagaLogs.add(log("QR_ISSUED", "QR 티켓을 발급했습니다.", issuedAt));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

qr 발급이 트랜잭션 내에서 이루어지고 있어, 두 가지 문제가 발생할 수 있을 거 같습니다!

  1. DB 트랜잭션이 길어져서 락 유지 시간 길어짐
  2. QR 발급 성공 이후, DB가 실패하면 외부상태와 DB 상태의 불일치

SAGA패턴을 이용해서 분리하는 게 좋을 거 같습니다!

}
}

private TicketReservationSagaLogResponse log(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

이거는 따로 record로 분리하는 게 좋을 거 같아요

null,
heldAt,
heldAt));
sagaLogs.add(log("SEAT_HELD", "좌석을 선점했습니다.", heldAt));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

여기서 추후 보상 처리 로직도 필요할 거 같습니당
예를 들어..
좌석 선점 해제
QR 폐기
예약 실패 상태 기록
재시도 가능 여부 저장

private final TicketQrCodeIssuer ticketQrCodeIssuer;

@Transactional
public TicketReservationResponse reserveTicket(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

현재 로직이 절차적 응집으로 보입니다. 전체적으로 응집도가 낮아보이는데, 추후 보상 처리 로직 등 다양한 로직이 붙으면 더 커질 거 같아, 미리 책임을 분리해두는 걸 추천합니다!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants