개인 시스템 프로젝트 → 실제 React 예약 클라이언트

Concert Booking

좌석 경합을 통과시키는 코드에서, 실패해도 다음 행동을 알 수 있는 예약 경험으로 확장했습니다.

Concert Booking React 클라이언트에서 VIP 1열 5번 좌석을 선택한 화면

동일 좌석을 한 번만 확정하는 동시성 실험으로 시작했지만 테스트만으로는 대기·충돌·만료를 겪는 사용자의 경험을 설명하기 어려웠습니다.

Setting
개인 시스템 프로젝트 → 실제 React 예약 클라이언트
Audience
예약 경합과 재시도를 직접 확인하려는 포트폴리오 방문자
Role
예약 백엔드 설계, 실패 경계 수정, 제품 클라이언트와 E2E 연결
  • 대기열 입장부터 좌석 선택, 예약, 만료 카운트다운, 데모 결제까지 한 흐름으로 연결했습니다.
  • Queue Token 응답을 잃어도 같은 토큰을 되찾고, SSE가 반복 실패하면 polling으로 전환하게 했습니다.
  • 좌석 경합의 패자는 최신 좌석표로 복구하고 만료·취소 뒤 좌석이 다시 반환되게 했습니다.
  1. 01

    공연을 고르고 로그인한 뒤 대기열에서 입장 순서를 기다립니다.

  2. 02

    READY 토큰으로 좌석을 선택하고, 충돌하면 최신 좌석표에서 다시 고릅니다.

  3. 03

    예약 만료 시간을 확인하며 데모 결제를 완료하거나 예약을 취소합니다.

사용자가 경험하는 예약 경계Queue는 입장 권한, Booking은 예약 의도, PostgreSQL은 좌석의 최종 상태를 맡습니다.enterreservebound tokencommitsame transactionretry publishBooking client대기·선택·복구Redis Queueuser + schedule tokenBooking serviceidempotency + lockPostgreSQLseat + reservationOutboxcommit 이후 사건Kafka / DLT발행·격리·replay
  1. 클라이언트가 일정별 Queue Token을 발급받습니다.
  2. 예약 의도는 Idempotency-Key로 재시도돼도 한 결과로 수렴합니다.
  3. PostgreSQL transaction이 좌석의 최종 승자를 정합니다.
  4. commit 이후 사건은 Outbox와 Kafka 복구 경로로 이동합니다.
Queue는 입장 권한, Booking은 예약 의도, PostgreSQL은 좌석의 최종 상태를 맡습니다.
사용자가 경험하는 예약 경계
사용자가 경험하는 예약 경계Queue는 입장 권한, Booking은 예약 의도, PostgreSQL은 좌석의 최종 상태를 맡습니다.enterreservebound tokencommitsame transactionretry publishBooking client대기·선택·복구Redis Queueuser + schedule tokenBooking serviceidempotency + lockPostgreSQLseat + reservationOutboxcommit 이후 사건Kafka / DLT발행·격리·replay
실제 클라이언트를 붙이자 Queue Token 재발급과 응답 유실처럼 통합 테스트만으로는 보이지 않던 제품 결함이 드러났습니다.
Lab

동일 좌석을 한 건으로 수렴시키기

DB lock과 unique constraint, Queue Token, Idempotency-Key가 서로 다른 중복 경계를 맡게 했습니다.

Product client

실패가 사용자에게 어떻게 보이는지 연결하기

대기·좌석 충돌·응답 유실·만료를 화면 상태와 다음 행동으로 번역했습니다.

Recovery

commit 이후 실패도 되돌아올 경로 남기기

Outbox와 DLT는 성공을 꾸미는 장치가 아니라 실패를 관찰하고 다시 처리하는 운영 경계로 사용했습니다.

React 클라이언트와 Docker demo, 브라우저 E2E까지 저장소에 포함하며 공개 서버는 아직 운영하지 않습니다.

  • 예약의 성공·충돌·만료·취소를 하나의 사용자 여정으로 재현합니다.
  • 동일 좌석과 동일 요청의 중복을 서로 다른 경계에서 흡수합니다.
  • 이벤트 발행·소비 실패를 상태로 남기고 replay할 수 있습니다.
  • 동일 좌석 경합 통합 테스트

    공개 저장소에서 확인
    근거 ↗
  • 예약 멱등성 통합 테스트

    공개 저장소에서 확인
    근거 ↗
  • Outbox 실패·재시도 상태 전이

    공개 저장소에서 확인
    근거 ↗
  • DLT replay 멱등 복구 테스트

    공개 저장소에서 확인
    근거 ↗
  • 예약 클라이언트와 실패 복구 경계를 연결한 제품 rebuild merge

    공개 저장소에서 확인
    근거 ↗
  • Queue Token 멱등 발급·재진입·만료 상태 테스트

    공개 저장소에서 확인
    근거 ↗
  • 예약 완주·좌석 패자 복구·응답 유실 브라우저 E2E

    공개 저장소에서 확인
    근거 ↗
  • 취소·만료 뒤 좌석 반환 브라우저 E2E

    공개 저장소에서 확인
    근거 ↗
  • SSE 재연결·polling fallback·401 종료 브라우저 E2E

    공개 저장소에서 확인
    근거 ↗
  • 결제는 실제 PG가 아닌 데모 확정 흐름입니다.
  • 공개 근거는 Testcontainers와 로컬 브라우저 E2E 범위이며 production 처리량을 뜻하지 않습니다.
JavaSpring BootPostgreSQLRedisKafka