03_시퀀스다이어그램_2nd - loveAlakazam/hh-08-concert GitHub Wiki

서론

전부 다 변경하고 싶지만, 시간관계상 일부 시퀀스 다이어그램만 수정을 해보기로 했다.

열심히 설계에 고민하다가 옆구리 근육통에 시달리게된 팀원 준규님(@CUCU7103)의 시퀀스다이어그램을 참고해서 보완을해봤다. 준규님의 시퀀스 다이어그램을 보니까 API의 내부 플로우가 어떻게되는지 파악하기가 참좋았고, 지난주에 과제를 해결하기위해서 많은 고민을 하신거 같다. 젭에서 준규님과 이야기를 나누면서 개선방향을 잡았는데, 개선된 일부 시퀀스다이어그램에 대해 소개해보려고한다.

목차


토큰 검증

대기열 토큰과 대기순서 조회 API를 제외한 나머지 API에서는 토큰이 유효한지 토큰의 상태가 활성화(ACTIVE) 상태인지를 확인해야한다. 그러므로 API를 콜하기전에 인터셉터에서 토큰검증을 반드시 거쳐야한다.

1차 시퀀스다이어그램에서는 "유효하다고 가정"이라는 표현이 API 내부로직의 토큰검증 단계를 스킵할 수 있겠다는 오해의 소지를 가질 수 있겠다는 생각이 들었고, 오해의 소지를 불러 일으키지 않도록 표현하는 것도 중요한거 같다.

고려사항을 2가지로 나타냈다.

  • 현재 토큰의 유효기간이 유효한지?
  • 현재 토큰이 활성화(ACTIVE) 상태인지?
sequenceDiagram
    title 토큰 유효성 검증 공통 로직
    autonumber

    actor client as 사용자
    participant tokenValidator as 토큰 인터셉터
    participant tokenService as 토큰 서비스
    participant tokenRepository as 토큰 래포지토리

    client->>+tokenValidator: 토큰 유효성 검증 요청
    tokenValidator->>+tokenService: 토큰의 유효성 검증 요청 <br> 토큰 상태가 ACTIVE 이고 토큰이 유효한지 확인
    tokenService->>tokenService: 만료된 토큰 스케줄러 처리
    tokenService->>+tokenRepository: 토큰 상태 검증
    tokenRepository->>-tokenService: 토큰 상태 응답
    alt 토큰 유효기간이 유효한 경우
        alt 토큰 상태가 활성상태(ACTIVE) 일 때
            tokenService->>tokenValidator: 토큰 유효성 검증 응답
            tokenValidator->>client: 유효한 토큰임을 검증 완료
         else 토큰 상태가 활성상태(ACTIVE)가 아닌 경우
		        tokenService->>tokenValidator: 유효하지 않은 토큰 예외 발생
		        tokenValidator->>client: 예외 메시지 전달 <br> 401 Unauthorized
        end
    else 토큰 유효기간이 만료된 경우
        tokenService->>-tokenValidator: 토큰 유효기간 만료 예외 발생
        tokenValidator->>-client: 예외 메시지 전달 <br> 401 Unauthorized
    end

예약 가능한 날짜목록 조회 API

  • 토큰 검증 요청
  • 예약 가능한 날짜목록 조회 API 호출
  • 예약 가능한 날짜에 대한 스케줄 처리
  • 예약가능한 날짜 목록조회
  • 요청에 대한 응답처리
sequenceDiagram
    title: 예약 가능한 날짜 목록 조회 API
    autonumber

    actor client as 사용자
    participant tokenValidator as 토큰 인터셉터
    participant controller as 콘서트 컨트롤러
    participant service as 콘서트 서비스
    participant repository as 콘서트 날짜 래포지토리

    %% 토큰 유효성 검증
    Note over client, tokenValidator: 토큰 검증은 토큰 인터셉터 에서 처리

    %% API 요청
    client->>+controller: 콘서트 예약 가능한 날짜 목록 조회 요청 <br> [GET] /concerts/{concert_id}/dates

    %% 콘서트 예약 가능한 날짜 목록 조회
    controller->>+service: 예약 가능한 날짜 조회
    service->>service: 예약가능한 날짜 스케줄러 처리
    service->>+repository: 예약 가능한 날짜 목록 조회 요청
    repository->>-service: 응답 데이터 반환
    service->>-controller: 예약 가능한 날짜 반환
    controller->>-client: 예약 가능한 날짜 목록 반환 <br> 200 OK

예약가능한 날짜에 대한 스케줄링이 필요함을 실제 서비스 cgv 영화예매를 참고해서 반영해봤다.

  1. 좌석매진 ticket-soldout-example
  • 예약 가능한 날짜는 현재를 기준으로 지나간 과거날짜는 예약목록에서 제외되어야한다.

  • 현재~미래 날짜만 가능하다. 만일 목록조회 결과가 10개이상이라면 페이지네이션을 적용한다.

  1. (현재날짜 기준으로) 예약날짜가 지나감. ticket-terminated-example
  • 해당 날짜에서 좌석이 만석인 경우에는 "예약불가" 상태로 나타내야한다.

  • 좌석이 만석인지 체크하는 스케줄러는 30분 주기로 확인한다.

  • 만일 콘서트 예약이 인기가 많아진다면 해당 스케줄러의 주기를 줄여 나가면될거같다.

위의 아이디어를 바탕으로 예약좌석뿐만 아니라 날짜도 스케줄검증이 필요하다는 걸 깨달았다. 그래서 날짜 예약의 경우 2가지 스케줄러가 존재한다.

예약날짜 스케줄러 1 - 매일 0시에 현재날짜 기준으로 과거날짜는 "예약불가" 상태로 변경하는 스케줄러

  • 0시에 현재날짜를 기준으로 과거인날짜들은 상태를 '예약불가능'으로 하여 모두 예약가능한 날짜 목록에 제외한다.
sequenceDiagram
    title: 매일 0시에 현재시각을 기준으로 지난 날짜는 '예약불가' 상태로 변경하는 스케줄러
    autonumber

    participant scheduler as 예약날짜의 예약 가능여부 변경 스케줄러
    participant service as 콘서트 서비스
    participant repository as 콘서트 날짜 래포지토리

    loop 매일 0시에 스케줄러 처리
        scheduler->>+service: 현재날짜를 기준으로 과거날짜는 예약가능한 날짜목록에서 제외하도록 요청
        service->>+repository: 콘서트 날짜 테이블에서 과거날짜는 예약불가능으로 변경 <br> 예약상태: "예약가능" -> "예약 불가능"
        repository->>repository: 예약 불가능 상태 변경처리
        repository->>-service: 상태 변경 처리 완료
        service->>-scheduler: 스케줄러 처리 종료
    end

예약날짜 스케줄러 2 - 좌석이 만석인 예약날짜는 "예약불가" 상태로 변경하는 스케줄러

sequenceDiagram
    title: 10분 주기로 예약좌석이 만석인 날짜는 예약가능여부를 '예약불가' 상태로 변경하는 스케줄러
    autonumber

    participant scheduler as 예약날짜의 예약 가능여부 변경 스케줄러
    participant service as 콘서트 서비스
    participant repository as 콘서트 날짜 래포지토리
    participant seatRepository as 콘서트 좌석 래포지토리

    loop 10분 주기로 스케줄러 실행
        scheduler->>+service: 좌석이 만석인 예약날짜는 예약가능여부를 '예약불가' 상태로 변경 요청
        service->>+seatRepository: 현시각 기준으로 만석인 날짜 조회
        seatRepository->>-service: 만석인 날짜 데이터 응답
        service->>+repository: 만석인 날짜는 예약불가능 상태로 변경 <br> 예약상태: "예약가능" -> "예약 불가능"
        repository->>repository: 예약 불가능 상태 변경처리
        repository->>-service: 상태 변경 처리 완료
        service->>-scheduler: 스케줄러 처리 종료
    end

예약 가능한 좌석목록 조회 API

  • 토큰 검증 요청
  • 예약 가능한 좌석 목록 조회 API 호출
  • 예약가능한 좌석 스케줄러 처리
  • 날짜정보에 해당되는 예약 가능한 좌석정보 목록을 조회한다.
    • 콘서트 좌석은 1~50 번으로 구성되어있으며, 좌석마다 가격이 다르다 (e.g. 뮤지컬공연 티켓팅의 좌석별로 가격이 다름을 참고했다.)
    • 좌석의 예약가능 여부는 is_available 값에 따라 결정된다.
  • 요청에 대한 응답처리
sequenceDiagram
    title: 예약 가능한 좌석 목록 조회 API
    autonumber

    actor client as 사용자
    participant tokenValidator as 토큰 인터셉터
    participant controller as 콘서트 컨트롤러
    participant service as 콘서트 서비스
    participant repository as 콘서트 좌석 래포지토리

    %% 토큰 유효성 검증
    Note over client, tokenValidator: 토큰검증은 토큰 인터셉터에서 처리

    %% API 요청
    client->>+controller: 예약가능한 좌석목록 조회 요청 <br> [GET] /concerts/{concert_id}/seats?date={date}

    %% 예약이 가능한 좌석 정보 조회
    controller->>+service: 예약 가능한 좌석 정보목록 조회
    service->>service: 예약가능한 좌석 스케줄러 처리
    service->>+repository: 예약 가능한 좌석 목록 조회 요청
    repository->>-service: 응답 데이터 반환
    alt 예약 가능한 좌석 데이터가 존재할 때
        service->>controller: 예약 가능한 좌석 정보 응답
        controller->>client: 예약 가능한 좌석 정보 응답 <br> 200 OK
    else 예약 가능한 좌석 데이터가 존재하지 않을 때
        service->>-controller: 예약 가능한 좌석 데이터가 존재하지 않음 예외 발생
        controller->>-client: 잘못된 응답 <br> 404 Not Found
    end

좌석 예약 요청 API

  • 토큰 검증 요청
  • 좌석 예약 요청 API 호출
  • 예약가능한 좌석 스케줄러 처리
  • 예약 좌석 상태 조회
  • 예약 좌석이 상태가 예약 가능하다면 5분간 임시배정 상태로 변경
    • 좌석 상태(is_available): true -> false
    • 예약 정보
      • 신규예약시: 예약상태는 PENDING_PAYMENT 상태로 예약정보 생성
      • 기존 예약 취소 이력있는 경우: 예약상태는 CANCELED -> PENDING_PAYMENT 로 변경
  • 예약 좌석 상태가 예약 불가능하다면 응답에러 반환
sequenceDiagram
    title 좌석 예약 요청 API
    autonumber

    actor client as 사용자
    participant tokenValidator as 토큰 인터셉터
    participant controller as 에약 컨트롤러
    participant service as 예약 서비스
    participant concertRepository as 콘서트 좌석 래포지토리
    participant repository as 예약 래포지토리



    %% 토큰 유효성 검증
    Note over client, tokenValidator: 토큰검증은 토큰 인터셉터에서 처리
    client->>+controller: 좌석 예약 요청 <br> [POST] /reservations

    %% 좌석 예약
    controller->>+service: 좌석 예약 요청
    service->>+concertRepository: 예약좌석 상태 정보 조회 요청
    concertRepository->>concertRepository: 예약가능한 좌석 스케줄러 처리
    concertRepository->>service: 예약 좌석의 상태 정보 응답 데이터 반환

    alt 해당 좌석의 상태가 "예약 가능" 인 경우
        service->>concertRepository: 좌석 상태를 "예약 불가능" 으로 변경 요청
        concertRepository->>-service: 좌석 상태 변경

        service->>+repository: 예약 정보 조회 요청
        repository->>service: 예약 정보 응답 (신규 좌석 예약은 예약정보 없음)
        opt 신규 좌석 예약일 경우
	        service->>repository: 예약 정보 생성 요청
	        repository->>service: 예약 정보 반환
        end
        service->>repository: 예약 상태를 결제 대기중(PENDING_PAYMENT) 으로 변경 요청
        repository->>-service: 예약 상태 변경

        service->>controller: 사용자에게 5분 내에 결제해야 확정된 자리 입니다 메시지 전달
        controller->>client: 해당 좌석 예약 성공 <br> 201 Created

    else 해당 좌석의 상태가 "예약 불가능" 인 경우
        service->>-controller: 이미 예약된 좌석이므로 좌석 예약 불가 예외 발생
        controller->>-client: 예약 실패 예외 메시지 응답 <br> 409 Conflict
    end

결제 요청 API

  • 토큰 검증 요청
  • 좌석 예약 요청 API 호출
  • 예약 가능한 좌석 스케줄러 처리
  • 예약 좌석 정보 요청
  • 예약 정보 요청 (임시예약 으로 되어있는 상태인지 확인)<-> 응답
  • 포인트 조회 요청 <-> 응답
  • 포인트 사용 요청 <-> 응답
  • 결제요청 조회 <-> 응답
sequenceDiagram
  title: 결제 요청 API
  autonumber

  actor client as 사용자
  participant tokenValidator as 토큰 인터셉터
  participant controller as 결제 컨트롤러

  participant paymentService as 결제 서비스

  participant reserveRepository as 예약 래포지토리
  participant concertRepository as 콘서트 래포지토리
  participant pointRepository as 포인트 래포지토리
  participant repository as 결제 래포지토리



  %% 토큰 유효성 검증
  Note over client, tokenValidator: 토큰 검증은 토큰 인터셉터에서 처리
  client->>+controller: 결제 요청 API <br> [POST] /payments
  controller->>+paymentService: 결제 요청

  %% 예약 좌석이 임시예약 상태인지 확인
  paymentService-->>+reserveRepository: 예약 좌석 상태 조회
  reserveRepository->>-paymentService: 예약 좌석 상태 정보 응답

  %% 예약 좌석 정보 조회
  paymentService->>+concertRepository: 콘서트 좌석 정보 조회
  concertRepository->>-paymentService: 콘서트 좌석 정보 응답

  alt 예약좌석이 '임시예약' 상태일 경우 <br> 좌석상태: "예약 불가능", 예약상태: "결제 대기중(PENDING_PAYMENT)"
	  %% 포인트 조회요청
	  paymentService->>+pointRepository: 포인트조회 요청
	  pointRepository->>-paymentService: 포인트 반환

	  %% 결제금액(좌석금액)
	  alt 결제금액보다 포인트가 많은 경우
		  %% 포인트 차감
		  paymentService-->>+pointRepository: 결제금액만큼 포인트 차감
		  pointRepository-->>pointRepository: 포인트 차감 및 포인트 히스토리 적재
		  pointRepository-->>-paymentService: 포인트 차감후 잔액 반환

		  %% 예약확정으로 변경
		  paymentService->>+reserveRepository: 결제완료후 예약좌석의 상태를 변경 <br> 예약상태를 결제 대기중(PENDING_PAYMENT) 에서 확정(CONFIRMED)으로 변경
		  reserveRepository->>-paymentService: 상태 변경 완료

		  %% 결재내역 생성
		  paymentService->>+repository: 결재내역 생성
		  repository->>-paymentService: 결제내역 반환

		  paymentService->>controller: 예약확정 및 결제 성공
		  controller->>client: 예약확정 및 결제 성공 <br> 2O1 Created

	  else 결제금액보다 포인트가 적은 경우
		  paymentService->>controller: '잔액이 부족합니다' 예외 반환
		  controller->>paymentService: 결제 실패 예외 메시지 응답 <br> 400 Bad Request
	  end

	else 예약 좌석이 '예약확정(CONFIRMED)' 상태일 경우
		paymentService->>controller: '이미 예약된 좌석입니다' 예외 반환
		controller->>client: 결제실패 예외 메시지 응답 <br> 409 Conflict

	else 그외의 상태라면 ('예약취소(CANCELED)', 예약없음)
		paymentService->>-controller: '예약 상태에 결제를 진행할 수 없습니다' 예외 반환
		controller->>-client: 잘못된 접근 예외 메시지 응답 <br> 400 Bad Request
	end