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 영화예매를 참고해서 반영해봤다.
- 좌석매진
예약 가능한 날짜는 현재를 기준으로 지나간 과거날짜는 예약목록에서 제외되어야한다.
현재~미래 날짜만 가능하다. 만일 목록조회 결과가 10개이상이라면 페이지네이션을 적용한다.
- (현재날짜 기준으로) 예약날짜가 지나감.
해당 날짜에서 좌석이 만석인 경우에는 "예약불가" 상태로 나타내야한다.
좌석이 만석인지 체크하는 스케줄러는 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