FlightSearchV2ProxyController DFS (기능명세서)
1. API 개요 및 목적
1.1 컨트롤러 정보
| 항목 | 값 |
|---|---|
| 클래스명 | FlightSearchV2ProxyController |
| 패키지 | com.triple.air.intl.search.interfaces.controller.internal.proxy.v2 |
| 소스 위치 | air-intl-search/src/main/kotlin/.../proxy/v2/FlightSearchV2ProxyController.kt |
| Base Path | /internals/proxy/flights/search/v2 |
1.2 목적
V2 프록시 검색 컨트롤러는 국제선 항공권 검색을 위한 내부 API를 제공합니다. V1과 달리 다음과 같은 특징을 가집니다:
- MixFlightResponseType 파라미터를 통한 명시적인 SPLIT/COMBINED 모드 구분
- COMBINED 모드 지원 (왕복 항공권과 MIX 항공권의 조합 결과 반환)
flightGroupCriteria기본값이SCHEDULE_WITH_FREE_BAGGAGE로 변경- V2 전용 응답 형식 (
InternalProxyFlightItemV2View)
1.3 필수 헤더 요구사항
소스:
FlightSearchV2ProxyController.kt:24-27
@RequestMapping(
"/internals/proxy/flights/search/v2",
headers = [Constants.TRIPLE_SALES_CHANNEL_HEADER, Constants.TRIPLE_SALES_FUNNEL_HEADER]
)| 헤더 | 상수명 | 값 | 필수 |
|---|---|---|---|
x-triple-sales-channel | TRIPLE_SALES_CHANNEL_HEADER | - | O |
x-triple-sales-funnel | TRIPLE_SALES_FUNNEL_HEADER | - | O |
소스:
Constants.kt:6-7
2. 엔드포인트별 상세 분석
2.1 편도 검색 (One-Way Trip)
| 항목 | 값 |
|---|---|
| HTTP Method | GET |
| URL Pattern | /{originType}:{origin}-{destinationType}:{destination}/{outboundDate} |
| 메서드명 | searchOneWayTrip |
| 소스 위치 | FlightSearchV2ProxyController.kt:34-69 |
| UseCase | StandardFlightSearchUseCase |
Path Variables
| 파라미터 | 타입 | 설명 |
|---|---|---|
originType | LocationType | 출발지 타입 (CITY/AIRPORT) |
origin | String | 출발지 IATA 코드 |
destinationType | LocationType | 도착지 타입 (CITY/AIRPORT) |
destination | String | 도착지 IATA 코드 |
outboundDate | LocalDate | 출발일 (ISO DATE 형식: yyyy-MM-dd) |
Query Parameters
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
cabins | Set<CabinType> | O | - | 좌석 등급 |
adult | Int | O | - | 성인 인원 |
child | Int | X | 0 | 소아 인원 |
infant | Int | X | 0 | 유아 인원 |
freeBaggageOnly | Boolean | X | false | 무료 수하물 포함 항공편만 |
useRecommendation | Boolean | X | true | 추천 점수 사용 여부 |
useCache | Boolean | X | true | 캐시 사용 여부 |
flightGroupCriteria | FlightGroupCriteria | X | SCHEDULE_WITH_FREE_BAGGAGE | 항공편 그룹핑 기준 |
2.2 왕복 검색 - 기본 모드 (Round Trip)
| 항목 | 값 |
|---|---|
| HTTP Method | GET |
| URL Pattern | /{originType}:{origin}-{destinationType}:{destination}/{outboundDate}/{inboundDate} |
| 메서드명 | searchRoundTrip |
| 소스 위치 | FlightSearchV2ProxyController.kt:71-113 |
| UseCase | StandardFlightSearchUseCase |
추가 Path Variables
| 파라미터 | 타입 | 설명 |
|---|---|---|
inboundDate | LocalDate | 귀국일 (ISO DATE 형식: yyyy-MM-dd) |
2.3 왕복 검색 - SPLIT 모드
| 항목 | 값 |
|---|---|
| HTTP Method | GET |
| URL Pattern | /{originType}:{origin}-{destinationType}:{destination}/{outboundDate}/{inboundDate} |
| 필수 파라미터 | mixResponseType=SPLIT |
| 메서드명 | searchSplitRoundTrip |
| 소스 위치 | FlightSearchV2ProxyController.kt:115-167 |
| UseCase | SplitFlightSearchUseCase |
추가 Query Parameters
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
mixResponseType | MixFlightResponseType | X | - | SPLIT 지정 |
searchTripDirectionType | SearchTripDirectionType | X | - | OUTBOUND/INBOUND |
detailKey | String | X | - | 앵커 항공편 상세 키 |
promotionPrincipleId | Long | X | - | 프로모션 원칙 ID |
추가 Headers
| 헤더 | 타입 | 필수 | 설명 |
|---|---|---|---|
cached-search-key | String | X | 캐시된 검색 키 (UUID) |
응답 Headers
| 헤더 | 설명 |
|---|---|
cached-search-key | 검색 결과 캐시 키 (후속 INBOUND 검색에 사용) |
2.4 왕복 검색 - COMBINED 모드
| 항목 | 값 |
|---|---|
| HTTP Method | GET |
| URL Pattern | /{originType}:{origin}-{destinationType}:{destination}/{outboundDate}/{inboundDate} |
| 필수 파라미터 | mixResponseType=COMBINED |
| 메서드명 | searchCombinedRoundTrip |
| 소스 위치 | FlightSearchV2ProxyController.kt:169-217 |
| UseCase | CombineFlightSearchUseCase |
추가 Query Parameters
| 파라미터 | 타입 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
mixResponseType | MixFlightResponseType | X | - | COMBINED 지정 |
useRecommendation | Boolean | X | false | 추천 점수 사용 (기본 false) |
debug | Boolean | X | false | 디버그 모드 |
2.5 다구간 검색 (Multi-City Trip)
2구간 검색
| 항목 | 값 |
|---|---|
| URL Pattern | /{originType1}:{origin1}-{destinationType1}:{destination1}/{date1}/{originType2}:{origin2}-{destinationType2}:{destination2}/{date2} |
| 메서드명 | searchMultiCityTrip (2구간) |
| 소스 위치 | FlightSearchV2ProxyController.kt:219-268 |
3구간 검색
| 항목 | 값 |
|---|---|
| URL Pattern | 2구간 패턴 + /{originType3}:{origin3}-{destinationType3}:{destination3}/{date3} |
| 메서드명 | searchMultiCityTrip (3구간) |
| 소스 위치 | FlightSearchV2ProxyController.kt:270-331 |
4구간 검색
| 항목 | 값 |
|---|---|
| URL Pattern | 3구간 패턴 + /{originType4}:{origin4}-{destinationType4}:{destination4}/{date4} |
| 메서드명 | searchMultiCityTrip (4구간) |
| 소스 위치 | FlightSearchV2ProxyController.kt:333-406 |
3. V1(FlightSearchProxyController)과의 차이점
V1 소스 위치:
air-intl-search/src/main/kotlin/.../proxy/FlightSearchProxyController.kt
3.1 URL 경로 차이
| 버전 | Base Path |
|---|---|
| V1 | /internals/proxy/flights (엔드포인트별 /search 포함) |
| V2 | /internals/proxy/flights/search/v2 |
3.2 MixFlightResponseType 지원
| 버전 | SPLIT | COMBINED |
|---|---|---|
| V1 | useMultiTicket=true 플래그로 처리 (소스:85행) | 미지원 |
| V2 | mixResponseType=SPLIT 명시적 파라미터 | mixResponseType=COMBINED 지원 |
3.3 flightGroupCriteria 기본값
| 버전 | 기본값 | 소스 위치 |
|---|---|---|
| V1 | SCHEDULE | FlightSearchProxyController.kt:49, 89, 163, 219, 287 |
| V2 | SCHEDULE_WITH_FREE_BAGGAGE | FlightSearchV2ProxyController.kt:51-52, 89-91, 138-140, 190-192, 244-246, 302-304, 372-374 |
3.4 응답 타입 차이
| 버전 | 응답 타입 | 특징 |
|---|---|---|
| V1 | InternalProxyFlightItemView | validatingCarrier, tripDirectionType 포함 |
| V2 | InternalProxyFlightItemV2View | hidden 필드, items 배열(FlightItemFragment) 포함 |
3.5 UseCase 차이
| 버전 | 사용 UseCase |
|---|---|
| V1 | StandardFlightSearchUseCase, SplitFlightSearchUseCase |
| V2 | StandardFlightSearchUseCase, SplitFlightSearchUseCase, CombineFlightSearchUseCase |
4. Request/Response 구조
4.1 공통 Request 도메인 모델
LocationType
소스:
support/enums/LocationType.kt:3-6
enum class LocationType(val shorter: String) {
CITY(shorter = "c"),
AIRPORT(shorter = "a");
}CabinType
소스:
support/enums/CabinType.kt:3-10
enum class CabinType(val value: String) {
ECONOMY(value = "Y"), // 이코노미
PREMIUM_ECONOMY(value = "W"), // 프리미엄 이코노미
BUSINESS(value = "C"), // 비지니스
FIRST(value = "F") // 일등석
}FlightGroupCriteria
소스:
support/enums/FlightGroupCriteria.kt:6-11
enum class FlightGroupCriteria {
NONE, // 그룹핑 없음
SCHEDULE, // 스케줄 기준 (ITX운임과 일반운임 경합)
SCHEDULE_WITH_CLASS, // 스케줄 + 예약 클래스
SCHEDULE_WITH_FREE_BAGGAGE, // 스케줄 + 무료 수하물
}SCHEDULE_WITH_FREE_BAGGAGE 그룹핑 로직 (소스: 34-46행):
- 스케줄 키:
{marketingCarrier}{flightNumber}{departureAt.dayOfWeek} - 수하물 2PC 이상인 경우 별도 그룹:
{volume}PC - 수하물 있으면
Y, 없으면 빈 문자열
MixFlightResponseType
소스:
support/enums/MixFlightResponseType.kt:3-8
enum class MixFlightResponseType {
SPLIT, // MIX 항공권 Outbound, Inbound 각각 반환
COMBINED; // MIX 항공권 outbound X inbound 조합으로 반환
}SearchTripDirectionType
소스:
support/enums/SearchTripDirectionType.kt:3-6
enum class SearchTripDirectionType {
OUTBOUND,
INBOUND,
}4.2 내부 모델
SearchInfo
소스:
support/model/SearchInfo.kt:15-106
data class SearchInfo(
val adult: Int,
val child: Int,
val infant: Int,
val freeBaggageOnly: Boolean,
val cabins: Set<CabinType>,
val originDestinationLocationInfos: List<OriginDestinationLocationInfo>,
val multiTicket: MultiTicket? = null,
val useCache: Boolean,
)검증 로직 (validate 메서드, 소스: 46-52행):
- 예약 가능 날짜 범위 확인
- 검색 날짜 순서 확인 (출발일 ⇐ 귀국일)
- 탑승객 수 유효성 검사
- 여정 유효성 검사 (출도착 동일 불가, 국내선 불가, 제한 국가 불가)
- MIX 검색 유효성 검사
MultiTicket
소스:
support/model/SearchInfo.kt:108-113
data class MultiTicket(
val searchTripDirectionType: SearchTripDirectionType?,
val detailKey: String?,
val promotionPrincipleId: Long?,
val cachedListKey: UUID?,
)4.3 Response 구조
InternalProxyFlightItemV2View
소스:
interfaces/response/ProxyCombinedFlightSearchView.kt:15-63
data class InternalProxyFlightItemV2View(
val listKey: UUID,
val score: BigDecimal?,
val tags: List<TagType>?,
val schedules: List<InternalProxyScheduleView>,
val fares: List<InternalProxyFlightFareV2View>,
val tripType: TripType,
val hidden: Boolean = false,
)InternalProxyFlightFareV2View
소스:
interfaces/response/ProxyCombinedFlightSearchView.kt:66-108
data class InternalProxyFlightFareV2View(
val avail: Int,
val passengerFares: List<InternalProxyFlightPassengerFareView>,
val adultAirPrice: Long,
val adultTaxPrice: Long,
val adultTotalPrice: Long,
val tags: List<String>,
val identityType: IdentityType,
val items: List<InternalProxyFlightItemFragmentView>,
)InternalProxyFlightItemFragmentView
소스:
interfaces/response/ProxyCombinedFlightSearchView.kt:111-131
data class InternalProxyFlightItemFragmentView(
val id: String,
val key: String,
val validatingCarrier: String,
val promotionPrincipleId: Long?,
val cardPromotionName: String? = null,
val representative: Boolean? = null,
)5. 비즈니스 로직 흐름 (UseCase 연동 분석)
5.1 기본 검색 흐름 (Standard)
sequenceDiagram participant C as Controller participant UC as StandardFlightSearchUseCase participant FS as FlightSearchService participant BDS as BookableDateService C->>C: searchFlights() 호출 C->>C: SearchInfo 생성 C->>UC: searchFlights() UC->>BDS: getBookableDateRange() UC->>UC: searchInfo.validate() UC->>FS: searchFlights() FS-->>UC: List<FlightItem> UC->>UC: groupBy(flightGroupCriteria.getKey) UC->>UC: pickOptimalFlight(fareDecisionStrategy) opt useRecommendation UC->>FS: applyRecommendationScores() end UC-->>C: List<FlightItem> C->>C: map to InternalProxyFlightItemV2View C-->>C: ResponseEntity
소스:
StandardFlightSearchUseCase.kt:26-82
5.2 SPLIT 검색 흐름
sequenceDiagram participant C as Controller participant UC as SplitFlightSearchUseCase participant FS as FlightSearchService participant Cache as CacheKeyGenerator C->>C: searchSplitFlights() 호출 C->>C: SearchInfo 생성 (MultiTicket 포함) C->>Cache: getFlightSearchCacheKey() (if cachedListKey is null) C->>UC: searchFlights(listKey, searchInfo, flightGroupCriteria) alt cachedListKey 존재 UC->>FS: getFlightItems(cachedListKey) else UC->>FS: searchFlights(useMultiTicket=true) end UC->>UC: splitMultiTicketSearchFlights() UC->>UC: groupBy & pickOptimalFlight UC-->>C: List<FlightItem> C->>C: map to InternalProxyFlightItemV2View C->>C: ResponseEntity with cached-search-key header
소스:
SplitFlightSearchUseCase.kt:24-56,FlightSearchV2ProxyController.kt:446-492
SPLIT 검색 내부 로직
소스:
SplitFlightSearchUseCase.kt:58-114
- MIX/왕복 분리:
flightItems.partition { it.isMix } - MIX Outbound/Inbound 분리:
mixFlightItems.partition { it.tripDirectionType == OUTBOUND } - searchTripDirectionType에 따른 분기:
INBOUND: anchorFlightItem 기준으로 Inbound 필터링OUTBOUND: Outbound 항공편만 반환null: 전체 검색 (Outbound + Inbound)
5.3 COMBINED 검색 흐름
sequenceDiagram participant C as Controller participant UC as CombineFlightSearchUseCase participant FS as FlightSearchService C->>C: searchCombinedFlights() 호출 C->>UC: searchFlights() UC->>FS: searchFlights(useMultiTicket=true) UC->>UC: combineMultiTicketSearchFlights() UC->>UC: compact() - 동일 스케줄 그룹핑 UC->>UC: groupBy(flightGroupCriteria.getKey) UC->>UC: pickOptimalFlight(fareDecisionStrategy) opt useRecommendation UC->>FS: applyRecommendationScores() end UC-->>C: List<CombinedFlightItem> C->>C: map to InternalProxyFlightItemV2View C-->>C: ResponseEntity
소스:
CombineFlightSearchUseCase.kt:28-65
COMBINED 결합 로직
소스:
CombineFlightSearchUseCase.kt:67-115
- MIX/왕복 분리:
flightItems.partition { it.tripDirectionType != null } - 왕복 항공권 래핑:
CombinedFlightItem.ofRoundTrip() - MIX 결합: Outbound X Inbound 모든 조합 생성
- 연결 시간 검증:
isValidConnectionTime()(3시간 이상) - 운임 정책 필터링:
filterByOutboundAndPolicy()
- 연결 시간 검증:
- 결과 병합: 왕복 + MIX 결합 항공권
6. MixFlightResponseType별 처리
6.1 SPLIT 모드
| 특징 | 설명 |
|---|---|
| 용도 | 가는편/오는편 별도 선택 UI |
| 결과 형태 | Outbound, Inbound 목록 각각 반환 |
| 캐시 키 | cached-search-key 헤더로 반환 |
| 후속 검색 | Outbound 선택 후 Inbound 검색 시 detailKey, cachedListKey 필요 |
6.2 COMBINED 모드
| 특징 | 설명 |
|---|---|
| 용도 | 왕복/MIX 통합 검색 결과 |
| 결과 형태 | 왕복 + (Outbound X Inbound) 조합 |
| FareDecisionStrategy | LOWEST_FARE_BY_IDENTITY_AND_CARD_TYPE 고정 (소스: 522행) |
| debug 모드 | hidden 항목 포함, 로그 출력 |
7. flightGroupCriteria 기본값 차이
7.1 V1 기본값: SCHEDULE
소스:
FlightSearchProxyController.kt:49
@RequestParam(required = false, defaultValue = "SCHEDULE") flightGroupCriteria: FlightGroupCriteria,그룹핑 키 생성 (소스: FlightGroupCriteria.kt:17-23):
flightItem.schedules.forEach { schedule ->
schedule.segments.forEach {
append("${it.marketingCarrier}${it.flightNumber}${it.departureAt.dayOfWeek.value}")
}
}7.2 V2 기본값: SCHEDULE_WITH_FREE_BAGGAGE
소스:
FlightSearchV2ProxyController.kt:51-52
@RequestParam(
required = false,
defaultValue = "SCHEDULE_WITH_FREE_BAGGAGE"
) flightGroupCriteria: FlightGroupCriteria,그룹핑 키 생성 (소스: FlightGroupCriteria.kt:34-46):
flightItem.schedules.forEach { schedule ->
schedule.segments.forEach {
append("${it.marketingCarrier}${it.flightNumber}${it.departureAt.dayOfWeek.value}")
}
// PC 단위 수하물은 2개 이상부터 별도 그룹핑
if (schedule.freeBaggage?.unit == BaggageUnit.QUANTITY && schedule.freeBaggage.volume > 1) {
append("${schedule.freeBaggage.volume}PC")
} else {
append(if ((schedule.freeBaggage?.volume ?: 0) > 0) "Y" else "")
}
}차이점 요약:
- V2는 동일 스케줄이라도 수하물 유무/수량에 따라 별도 그룹으로 분리
- 무료 수하물 2PC 이상은
{volume}PC로 구분 - 무료 수하물 1PC 이하는
Y또는 빈 문자열
8. 에러 처리 및 예외 상황
8.1 SearchInfo 검증 예외
소스:
support/model/SearchInfo.kt:46-98
| 예외 조건 | MessageKey | 설명 |
|---|---|---|
| 날짜 순서 오류 | INVALID_DATES | 출발일 > 귀국일 |
| 출도착 동일 | INVALID_ITINERARY | 출발지가 도착지에 포함 |
| 국내선 | INVALID_ITINERARY | 출도착 모두 국내 공항 |
| 제한 국가 | INVALID_ITINERARY_RESTRICTED_COUNTRY | SY, IR, UA, CU |
| INBOUND 검색 파라미터 누락 | INVALID_PARAMETER | detailKey 또는 cachedListKey 없음 |
| OUTBOUND에 detailKey 포함 | INVALID_PARAMETER | INBOUND가 아닌데 detailKey 존재 |
8.2 예약 가능 날짜 범위
소스:
SearchInfo.kt:54-56
private fun checkBookableDate(bookableDateRange: LongRange) {
originDestinationLocationInfos
.forEach { bookableDateRange.validateBookable(date = it.date) }
}8.3 탑승객 수 검증
소스:
SearchInfo.kt:49
checkSearchablePassengers(adult = this.adult, child = this.child, infant = this.infant)9. 관련 도메인 모델 분석
9.1 TripType
소스:
support/enums/TripType.kt:3-7
enum class TripType {
ONE_WAY, // 편도
ROUND_TRIP, // 왕복
MULTI_CITY; // 다구간
}판정 로직 (소스: 20-34행):
- 여정 1개:
ONE_WAY - 여정 2개 + 출발지귀국도착지 + 목적지귀국출발지:
ROUND_TRIP - 그 외:
MULTI_CITY
9.2 FareDecisionStrategy
소스:
support/enums/FareDecisionStrategy.kt:3-6
enum class FareDecisionStrategy {
LOWEST_ADULT_FARE, // 성인 최저가 기준
LOWEST_FARE_BY_IDENTITY_AND_CARD_TYPE; // 신분유형 & 카드 프로모션별 최저가
}COMBINED 모드에서는 LOWEST_FARE_BY_IDENTITY_AND_CARD_TYPE 고정 사용 (소스: FlightSearchV2ProxyController.kt:522)
9.3 CombinedFlightItem
소스:
support/model/CombinedFlightItem.kt:14-71
data class CombinedFlightItem(
val listKey: UUID,
override val schedules: List<Schedule>,
val fares: List<CombinedFlightFare>,
var score: BigDecimal?,
var tags: List<RecommendationTag>?,
val isMix: Boolean,
val hidden: Boolean = false, // V2 전용
val groupKey: String = ""
)9.4 CombinedFlightFare
소스:
support/model/CombinedFlightItem.kt:73-144
data class CombinedFlightFare(
val funnel: Funnel,
val avail: Int,
val passengerFares: List<PassengerFare>,
val tags: List<String> = emptyList(),
val items: List<FlightItemFragment>, // MIX인 경우 2개, 왕복인 경우 1개
)9.5 FlightItemFragment
소스:
support/model/CombinedFlightItem.kt:146-181
data class FlightItemFragment(
val id: String,
val lookUpKey: String = "",
val detailKey: String,
val scheduleKey: String,
val supplier: String,
val prepayment: Boolean?,
val validatingCarrier: String,
val cardPromotionName: String? = null,
val cardPromotionId: Long? = null,
val promotionPrincipleId: Long? = null,
val representative: Boolean? = null,
val naverCardType: String? = null,
val freeBaggageInfo: List<FreeBaggage>,
)10. 의존성 주입
소스:
FlightSearchV2ProxyController.kt:28-33
class FlightSearchV2ProxyController(
private val standardFlightSearchUseCase: StandardFlightSearchUseCase,
private val splitFlightSearchUseCase: SplitFlightSearchUseCase,
private val combineFlightSearchUseCase: CombineFlightSearchUseCase,
private val locationService: LocationService,
)| 의존성 | 역할 |
|---|---|
StandardFlightSearchUseCase | 기본 검색 (편도, 왕복, 다구간) |
SplitFlightSearchUseCase | SPLIT 모드 검색 |
CombineFlightSearchUseCase | COMBINED 모드 검색 |
LocationService | IATA 코드 → LocationInfo 변환 |
11. 요청 예시
11.1 편도 검색
GET /internals/proxy/flights/search/v2/CITY:SEL-CITY:TYO/2024-03-15?cabins=ECONOMY&adult=2
x-triple-sales-channel: TRIPLE
x-triple-sales-funnel: TRIPLE11.2 왕복 검색 (기본)
GET /internals/proxy/flights/search/v2/CITY:SEL-CITY:TYO/2024-03-15/2024-03-20?cabins=ECONOMY&adult=2
x-triple-sales-channel: TRIPLE
x-triple-sales-funnel: TRIPLE11.3 왕복 검색 (SPLIT - Outbound)
GET /internals/proxy/flights/search/v2/CITY:SEL-CITY:TYO/2024-03-15/2024-03-20?cabins=ECONOMY&adult=2&mixResponseType=SPLIT&searchTripDirectionType=OUTBOUND
x-triple-sales-channel: TRIPLE
x-triple-sales-funnel: TRIPLE11.4 왕복 검색 (SPLIT - Inbound)
GET /internals/proxy/flights/search/v2/CITY:SEL-CITY:TYO/2024-03-15/2024-03-20?cabins=ECONOMY&adult=2&mixResponseType=SPLIT&searchTripDirectionType=INBOUND&detailKey=xxx&promotionPrincipleId=123
x-triple-sales-channel: TRIPLE
x-triple-sales-funnel: TRIPLE
cached-search-key: uuid-from-outbound-search11.5 왕복 검색 (COMBINED)
GET /internals/proxy/flights/search/v2/CITY:SEL-CITY:TYO/2024-03-15/2024-03-20?cabins=ECONOMY&adult=2&mixResponseType=COMBINED
x-triple-sales-channel: TRIPLE
x-triple-sales-funnel: TRIPLE12. 참조 문서
- FlightSearchProxyController - V1 프록시 검색 컨트롤러
- StandardFlightSearchUseCase - 표준 검색 UseCase
- SplitFlightSearchUseCase - SPLIT 검색 UseCase
- CombineFlightSearchUseCase - COMBINED 검색 UseCase
- FlightGroupCriteria - 항공편 그룹핑 기준 Enum
- MixFlightResponseType - MIX 응답 타입 Enum