Phase 2: 아마데우스 예약 API 심층 분석
1. API 엔드포인트 개요
1.1 예약 관련 엔드포인트
| 엔드포인트 | 메서드 | 기능 | 위치 |
|---|---|---|---|
/internals/AMADEUS/bookings | POST | 예약 생성 | AmadeusBookingController.kt:25-38 |
/internals/AMADEUS/bookings/{pnr} | GET | 예약 조회 | AmadeusBookingController.kt:107-116 |
/internals/AMADEUS/bookings/{pnr} | PUT | APIS 정보 변경 | AmadeusBookingController.kt:40-56 |
/internals/AMADEUS/bookings/{pnr}/cancel | PUT | 예약 취소 | AmadeusBookingController.kt:58-75 |
/internals/AMADEUS/bookings/{pnr}/confirm | GET | 예약 확정 | AmadeusBookingController.kt:124-127 |
/internals/AMADEUS/bookings/{pnr}/repricing | GET | 재운임 계산 | AmadeusBookingController.kt:129-138 |
/internals/AMADEUS/bookings/{pnr}/divide | POST | 예약 분리 | AmadeusBookingController.kt:140-149 |
2. 예약 생성 (Create Booking)
2.1 전체 예약 플로우
flowchart TD A[예약 요청 수신] --> B[운임 정보 조회<br/>flightSearchService.getFareItinerary] B --> C{Stateful Session<br/>시작} C --> D[좌석 마킹<br/>markSeat] D --> E[예약 정보 저장<br/>saveReservationInfo] E --> F[운임 조회<br/>getPnrFares] F --> G[PNR 저장 및 경고 확인<br/>savePnrWithShowWarnings] G --> H{경고 메시지<br/>확인} H -->|최소 연결시간 오류| I[예외 발생<br/>MINIMUM_CONNECTION_TIME] H -->|일반 경고| J[재저장 시도] H -->|경고 없음| K[PNR 확정] J --> K K --> L[PNR 정보 조회<br/>getPnrInfoAndCheckInfantSoldOut] L --> M{Carrier Time<br/>Limit 확인} M -->|null| N[3초 대기 후<br/>재조회] M -->|존재| O[시간 계산] N --> O O --> P{스케줄 상태<br/>검증} P -->|HK/KK 아님| Q[SOLD_OUT<br/>예외] P -->|정상| R[세션 종료<br/>signOut] R --> S[예약 완료<br/>Booking 반환] 다크/라이트 모드 호환 색상 style C fill:#A8D5BA,stroke:#333,stroke-width:2px,color:#000 style H fill:#F4E4B1,stroke:#333,stroke-width:2px,color:#000 style I fill:#F39C9C,stroke:#333,stroke-width:2px,color:#000 style Q fill:#F39C9C,stroke:#333,stroke-width:2px,color:#000 style ERR fill:#E8B4B8,stroke:#333,stroke-width:2px,color:#000 style S fill:#95D5A6,stroke:#333,stroke-width:2px,color:#000
2.2 Stateful 세션 관리 패턴
위치: AmadeusBookingService.kt:65-178
stateDiagram-v2 [*] --> Start: 세션 시작 Start --> InSeries: 좌석 마킹 완료 InSeries --> InSeries: 연속 작업 InSeries --> End: 모든 작업 완료 End --> [*]: 세션 종료 InSeries --> Error: 예외 발생 Error --> Rollback: 세션 롤백 Rollback --> [*]: PNR 취소
2.3 핵심 처리 단계
Step 1: 좌석 마킹
위치: AmadeusBookingService.kt:67-73
start {
amadeusClient.markSeat(
fareItinerary = fareItinerary,
seatCount = passengers.count { it.type != PassengerType.INFANT },
statefulBuilder = this
)
}- 목적: 좌석 예약 및 가용성 확인
- 조건: 유아(INFANT)는 좌석 카운트에서 제외
Step 2: 예약 정보 저장
위치: AmadeusBookingService.kt:75-92
val pnrPassengers = inSeries {
amadeusClient.saveReservationInfo(
fareItinerary = fareItinerary,
reservationUser = reservationUser,
passengers = passengers,
corporateId = fareItinerary.passengerFares.first().option.corporateId,
statefulBuilder = this
)
}- 포함 정보: 승객, 연락처, 기업 ID
- 반환값: PNR과 승객 정보
Step 3: 최소 연결시간 체크
위치: AmadeusBookingService.kt:100-104
warnings.forEach {
if (it.contains("CHECK MINIMUM CONNECTION TIME") ||
it.contains("CHECK ARRIVAL/DEPARTURE")) {
throw InternationalAdapterException(
ErrorMessage.MINIMUM_CONNECTION_TIME,
it
)
}
}- 조건: 경고 메시지에 최소 연결시간 관련 문구 포함
- 처리: 즉시 예외 발생, 예약 중단
Step 4: Carrier Time Limit 처리
위치: AmadeusBookingService.kt:128-139
val calculatedCarrierTimeLimit =
if ((savedPnrInfo.carrierTimeLimit ?: savedPnrInfo.ssrCarrierTimeLimit) == null) {
withBlocking {
logger.info("[AMADEUS] carrierTimeLimit is null")
delay(3000) // 3초 대기
amadeusClient.getPnrInfo(pnr = pnr, statefulBuilder = this@stateful)
}
} else {
savedPnrInfo
}.let {
calculateCarrierTimeLimit(it)
}- 문제: 발권 시한이 즉시 설정되지 않는 경우
- 해결: 3초 대기 후 재조회
3. 예외 처리 및 롤백
3.1 예외 처리 플로우
flowchart TD A[예외 발생] --> B{세션 상태<br/>확인} B -->|InSeries| C[세션 종료<br/>signOut] B -->|기타| D[세션 유지] C --> E{예외 타입<br/>판단} D --> E E --> F{isUnexposedFareItinerary} F -->|SOLD_OUT| G[운임 정보 제거<br/>캐시에서 삭제] F -->|INFANT_SOLD_OUT| G F -->|MINIMUM_CONNECTION_TIME| G F -->|기타| H[일반 처리] G --> I[unexposed 저장] H --> J{PNR 존재} I --> J J -->|있음| K[PNR 취소<br/>비동기] J -->|없음| L[예외 재발생] K --> L 다크/라이트 모드 호환 색상 style B fill:#F4E4B1,stroke:#333,stroke-width:2px,color:#000 style F fill:#F4E4B1,stroke:#333,stroke-width:2px,color:#000 style K fill:#F4E4B1,stroke:#333,stroke-width:2px,color:#000 style P fill:#95D5A6,stroke:#333,stroke-width:2px,color:#000
4.2 티켓 문서 처리
위치: AmadeusBookingService.kt:210-245
val (emdTickets, eTickets) = tickets.partition { it.type == TicketType.EMD }- EMD: Electronic Miscellaneous Document (부가 서비스)
- E-Ticket: 전자 항공권
- 처리 차이: EMD는 별도 검증 (officeId 확인)
5. 예약 변경 (Modify)
5.1 APIS 정보 변경
엔드포인트: PUT /internals/AMADEUS/bookings/{pnr}
위치: AmadeusBookingController.kt:40-56
flowchart LR A[APIS 변경 요청] --> B[승객 정보 변환<br/>Passenger.of] B --> C[passengerService.changeApis] C --> D[변경된 승객 정보] D --> E[응답 반환] 다크/라이트 모드 호환 색상 style B fill:#F4E4B1,stroke:#333,stroke-width:2px,color:#000 style C fill:#9FB4CE,stroke:#333,stroke-width:2px,color:#000 style D fill:#9FB4CE,stroke:#333,stroke-width:2px,color:#000 style E fill:#9FB4CE,stroke:#333,stroke-width:2px,color:#000
8.2 비동기 처리
- 캐시 제거:
AmadeusBookingService.kt:193-196 - Unexposed 저장:
AmadeusBookingService.kt:187-191 - PNR 취소:
cancelService.pnrCancelAsync
9. 트러블슈팅
9.1 일반적인 문제
| 문제 | 증상 | 원인 | 해결 방법 |
|---|---|---|---|
| Carrier Time Limit null | 발권 시한 미설정 | GDS 응답 지연 | 3초 대기 후 재조회 |
| 최소 연결시간 오류 | 예약 실패 | 환승 시간 부족 | 다른 스케줄 선택 |
| 스케줄 미확정 | SOLD_OUT 예외 | 좌석 부족 | 다른 항공편 검색 |
| 유아 좌석 부족 | INFANT_SOLD_OUT | 유아 제한 초과 | 항공사 문의 필요 |
9.2 세션 관리 주의사항
- InSeries 상태에서 예외 발생 시 반드시 세션 종료
- PNR 생성 후 실패 시 비동기 취소 처리
- 트랜잭션 무결성 보장을 위한 stateful 패턴 사용
10. 주요 코드 위치 참조
| 기능 | 파일 | 라인 |
|---|---|---|
| 예약 생성 | AmadeusBookingService.kt | 53-178 |
| 예약 조회 | AmadeusBookingService.kt | 199-252 |
| 예약 확정 | AmadeusBookingService.kt | 254-268 |
| 재운임 계산 | AmadeusBookingService.kt | 270-277 |
| 예약 분리 | AmadeusBookingService.kt | 279-289 |
| PNR 체크 | AmadeusBookingService.kt | 291-295 |
| 예외 처리 | AmadeusBookingService.kt | 167-177 |
| 경고 필터링 | AmadeusBookingService.kt | 110-122 |
다음 Phase
Phase 3: 발권 API 심층 분석으로 진행