T’way Air(코드명 TWAY)는 국내 LCC(저비용항공사)로, GDS/NDC를 거치지 않고 항공사 자체 REST 엔드포인트에 직접 XML로 호출하는 모듈이다. 인증은 GDS 세션 토큰이 아니라 매 요청마다 HTTP Basic 헤더에 SEED 암호화된 비밀번호를 실어 보내는 stateless 방식이며, 결제·카드·PNR 같은 민감정보도 TwaySEED.jar의 SeedUtil.encoding()으로 암호화한다. Amadeus 같은 stateful PNR 세션이 없으므로 모듈 자체는 단순하지만, 요청/응답 DTO 수가 200개가 넘어(78 request + 127 response) 매핑 코드가 가장 큰 비중을 차지한다.
1. 공급사 특징 — 왜 이렇게 연동하는가
1-1. LCC / FSC / GDS / NDC 분류 → LCC + 직접 REST
T’way Air(티웨이항공)는 대한민국 국적 **LCC(Low-Cost Carrier)**다. GDS(Amadeus/Sabre/Galileo)나 NDC(Korean Air/Lufthansa) 채널을 경유하지 않고, 항공사가 자체 운영하는 예약 시스템(Navitaire 계열 SkySpeed/New Skies 류의 LCC PSS)의 REST API에 직접 붙는다. 코드로 확인되는 근거:
모든 외부 호출이 infrastructure/TwayClient.kt에서 "${endpoint}/shop/..." 또는 "${endpoint}/book/..." 같은 REST 경로로 나간다 (TwayClient.kt:56, 89, 153, 183, 221, 271, 305, 325 …).
요청 본문은 SOAP 봉투가 아니라 순수 XML이다. TwayClient의 헤더가 Content-Type: application/xml 하나뿐이다.
// TwayClient.kt:45-47private val headerMap = mapOf( HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_XML_VALUE)
GDS와의 결정적 차이
Amadeus/Sabre/Galileo는 SOAP 세션을 열고 PNR 상태를 서버가 들고 있는 stateful 구조다. T’way는 세션 개념이 없고, 매 호출이 독립적인 stateless REST 호출이다. 따라서 TwayClient에는 로그인/세션토큰/시그너처 같은 상태가 없으며, 인증 정보를 요청마다 새로 만들어 헤더에 붙인다(아래 1-3).
1-2. 비즈니스·시장 맥락 — 직항만 판매, 노선 화이트리스트
LCC 특성이 코드에 그대로 드러난다.
직항만 판매한다.TwayClient.toItineraries()에서 경유 편명(segmentReferenceInfo가 2개 이상)을 명시적으로 걸러낸다.
// TwayClient.kt:1043-1044val segmentReferenceInfo = pricingInfo.segmentReferenceInfos.first() // segmentReferenceInfo가 2개 이상인 것은 경유 편명이다. TW는 직항만 팔아야 한다.pricingInfo.tripRefIndex == tripInfo.tripIndex && pricingInfo.segmentReferenceInfos.size == 1 && ...
취항 노선을 사전에 화이트리스트로 관리한다. 검색 전에 RetrieveRoute로 전 노선을 받아 Redis에 캐싱하고(TwayRouteService.getAllRoutes()), 요청 노선이 화이트리스트에 없으면 공급사 호출 없이 빈 결과로 단락(short-circuit) 한다.
T’way 연동의 가장 중요한 특징이자 신입이 놓치기 쉬운 지점. T’way는 외부 라이브러리 libs/TwaySEED.jar(클래스 com.twayair.security.seed.SeedUtil)를 통해 비밀번호·카드정보·PNR 등 민감 데이터를 SEED(국산 128bit 블록암호)로 암호화해서 보낸다. 이 jar는 gradle에 로컬 파일 의존성으로 박혀 있다.
어댑터에는 support/util/SeedEncryptor.kt와 @SeedEncrypt 애너테이션도 따로 존재하지만, 이것은 Korean Air의 NicePay 결제(KoreanairPaymentClient)용이며 T’way와는 무관하다. T’way가 쓰는 SEED는 오직 com.twayair.security.seed.SeedUtil(외부 jar)이다. 두 SEED 구현을 혼동하지 말 것 → 자세한 함정은 tway-pitfalls.
interfaces/controller — 외부에 뭘 노출하는지(=무엇을 할 수 있는지) 먼저 본다.
application — 컨트롤러가 호출하는 서비스의 오케스트레이션 흐름.
infrastructure/TwayClient — 실제 HTTP 호출과 SEED 인증.
infrastructure/request·response — 200여 개 DTO는 통째로 외우지 말고, 필요한 오퍼레이션 1개의 *RQmsg/*RSmsg 쌍만 따라가면 된다. (*msg가 루트 봉투, *RQ/*RS가 본문)
왜 infrastructure가 이렇게 거대한가?
T’way XML 스키마는 오퍼레이션마다 별도 루트 메시지(AirAvailabilityRQmsg, CreateBookingRQmsg, ModifyBookingRSmsg …)를 쓰고, 그 안에 좌석/수하물/운임/세금/탑승객 등 중첩 구조를 전부 별도 Kotlin 클래스로 1:1 매핑해 두었다. 로직은 단순하지만 DTO 매핑 부피가 큰 것이 LCC/REST 모듈의 전형이다. 비즈니스 로직을 찾을 때 request/response 패키지를 다 뒤지지 말고 TwayClient와 application만 봐야 한다.
3. 핵심 파일 표
파일 (상대경로)
역할
별점
infrastructure/TwayClient.kt
모든 외부 API 호출의 단일 진입점. SEED 인증, XML 직렬화, 에러 판정(checkError), @Retryable 취소 재시도, 응답→도메인 매핑(toBooking/toItineraries 등)이 전부 여기 모여 있다 (1,089 LOC)
FareItinerary를 Gzip 압축 + JSON으로 Redis에 저장하는 전용 RedisTemplate
★
support/model/Booking.kt 등
어댑터 공통 도메인으로 변환하기 위한 T’way 내부 모델
★
4. 공개 인터페이스 — 컨트롤러 엔드포인트 & 서비스
모든 컨트롤러는 interfaces/controller/internals 패키지의 @RestController이며, 베이스 경로는 /internals/TWAY/...다. 중앙 디스패처 없이 컨트롤러 자체가 Triple 예약 시스템의 내부 API로 노출된다(→ system-architecture, request-flow).
6개 컨트롤러가 6개 오퍼레이션 카테고리(Search/Booking/Ticketing/FareRule/Ancillary/AgencyCredit)에 거의 대응하지만, 재발행(reissue) 처럼 한 사용자 액션이 Search·Ticketing 두 컨트롤러에 걸쳐 있고, 취소(cancel) 는 Booking 컨트롤러에 들어 있다. 카테고리 표를 그대로 컨트롤러로 믿지 말고 위 표를 기준으로 보라.
위 표에서 보듯 application 계층의 거의 모든 서비스가 단일 TwayClient로 외부 호출을 위임한다. 즉 T’way 연동의 진짜 본체는 TwayClient.kt 1,089줄이다. 오퍼레이션별 상세 흐름은 tway-operations, XML/SEED 프로토콜 디테일은 tway-protocol를 참고.
5. 중요도 별점
모듈 중요도: ★★ (보통~중요)
근거
운영 비중(↑): 국내 출발 국제선에서 T’way는 실판매 LCC라 트래픽이 적지 않다. 검색 컨트롤러에만 서킷브레이커가 별도로 걸려 있는 것은 장애 격리가 중요한 활성 모듈임을 시사한다(TwaySearchController.kt:27@CircuitBreaker(name="twaySearch")).
연동 복잡도(↓): GDS 같은 stateful 세션이 없어 호출 패턴이 단순하다. 모든 로직이 TwayClient 한 파일에 집중되어 추적이 쉽다.
고유 위험요소(↑): SEED 외부 jar 의존(TwaySEED.jar), 결제 비밀번호/카드정보 암호화, 재발행 Redis 폴링 비동기, 취소 @Retryable, 미노출운임 저장 등 운영 사고로 직결되는 디테일이 많다. 코드 규모(약 1만 LOC)는 크지만 대부분 DTO라 학습 난이도 자체는 GDS보다 낮다.
→ 종합하면 “이해 난도는 중간, 운영 민감도는 높음”. 신입이 두 번째~세 번째로 학습하기 좋은 LCC 표본이다(가장 단순한 Jeju Air보다 한 단계 풍부).