Inventory не-отельных доменов — Quote-семантики, lifecycle и интеграционные паттерны
Версия: 1.0 Дата: 30.04.2026 Статус: Готов к обсуждению
Назначение документа
Документ закладывает каноничные модели inventory для не-отельных segment-типов, входящих в композицию Tour Builder и в собственный продуктовый каталог платформы. Получено как требование внешнего архитектурного ревью 30.04.2026: «не детализирована модель Inventory для не-отельных сегментов».
Документ не описывает конкретные интеграции с GDS (Amadeus, Sabre, Galileo) или провайдерами страховок — это операционный слой следующих стадий. Документ фиксирует каноничные семантические правила segment-типов, которые должны быть зашиты в платформенную модель с нулевого дня, чтобы при подключении первых не-отельных supplier'ов не пришлось переделывать ядро.
Главный принцип
Каждый не-отельный segment-тип имеет свою собственную Quote-семантику, отличающуюся от accommodation. Платформа не унифицирует Quote-логику до общего знаменателя — это привело бы либо к запутанности, либо к потере специфики каждого домена.
Каноничная модель: единый интерфейс Quote на уровне Tour Builder композиции, но семантически отличающиеся реализации для каждого segment-типа, с явно зафиксированными свойствами:
- продолжительность жизни Quote;
- кто является pricing authority (платформа, supplier, третья сторона);
- какие revalidation-правила применяются;
- какие refund/cancellation rules применяются;
- какие compliance-требования специфичны.
Каноничные segment-типы
Платформа поддерживает следующие первичные segment-типы (помимо accommodation, описанного в reference/domain-model.md):
- Air transport (flights) — авиаперелёты.
- Ground transport (transfers) — автомобильные/автобусные/железнодорожные переезды.
- Insurance — страховые продукты (туристическая страховка, отмена путешествия, медицинская страховка).
- Activities and experiences — экскурсии, билеты в музеи, активный отдых.
- Ancillary services — дополнительные услуги (трансфер из аэропорта, аренда оборудования, room upgrade).
Перечень не закрытый — новые segment-типы могут быть добавлены в будущем (cruises, rail packages, car rentals long-term). Каждый новый segment-тип проходит через каноничный процесс onboarding'а, описанный в разделе «Процесс добавления нового segment-типа» ниже.
1. Air Transport (flights)
Принципиальные отличия от accommodation
- Quote живёт секунды, не минуты. В авиации цена и доступность могут измениться между запросом и подтверждением даже в пределах одной сессии.
- Pricing engine — внешний. Платформа не определяет цену авиабилета. Цена приходит от GDS (Amadeus, Sabre, Galileo, Travelport) или от direct connect с авиакомпанией. Платформа не имеет права применять собственные правила pricing'а к flight Quote.
- Refund-семантика жёстко регулируется IATA fare rules, не контрактом supplier'а. Платформа транслирует эти правила, не определяет их.
- Quote-revalidation обязательна в момент чек-аута. Без revalidation Quote не считается валидным для booking commit.
Каноничная модель FlightQuote
FlightQuote (расширение базового Quote из domain-model.md):
base_quote_fields: id, supplier_quote_id, expires_at, ...
segments[]:
origin_airport: IATA code
destination_airport: IATA code
carrier: IATA airline code
flight_number
departure_time, arrival_time
cabin_class: economy/premium/business/first
fare_basis_code (IATA fare class)
fare_rules:
refundability: refundable / non_refundable / partial_refund_with_fee
change_policy
baggage_allowance
seat_selection_rules
total_price:
base_fare
taxes_and_fees (с детализацией)
currency
validity_window:
quote_expires_at (короткий — обычно 5-30 минут)
last_revalidation_required_before
pricing_authority: gds_id / direct_carrier_id
Lifecycle и revalidation
Этапы:
- Search — поиск через GDS, возвращает ranked-список FlightQuote с короткими expiry.
- Quote-snapshot — выбранный FlightQuote сохраняется в платформе с явным
expires_at(обычно 5-30 минут от GDS). - Pre-checkout revalidation — обязательная revalidation за 60 секунд до booking commit. Подтверждает что цена и доступность всё ещё валидны.
- Booking commit — после успешной revalidation, в течение нескольких секунд от revalidation. Получаем PNR (Passenger Name Record).
- Ticketing — отдельный этап, может быть синхронным (instant ticketing) или асинхронным (ticketing within 24h). Платформа должна поддерживать оба паттерна.
Правило revalidation: если между booking commit и ticketing Quote изменился (изменилась цена, отменён рейс) — Saga компенсирует через flight refund / repricing с partner notification.
Refund при отмене
- Refund-rules определяются IATA fare class, не нашим контрактом с supplier'ом.
- Платформа транслирует правила в стандартизованный формат (см. reference/partner-finance-and-clearing.md, раздел
Settlement Split). - Cancellation fee оплачивается из refund-amount; partner получает чистую сумму после fee.
- Refund timing регулируется IATA: full refund на refundable fare — до 7 дней; non-refundable — отказ refund либо только taxes_and_fees back.
Compliance специфика
- GDPR: passenger personal data передаются в GDS — нужен явный consent.
- APIS / SSR (Advance Passenger Information / Special Service Requests) — обязательные данные для трансграничных перелётов.
- PCI-DSS уровень 1 — полная карточная PII при ticketing (для авиабилетов).
2. Ground Transport (transfers)
Принципиальные отличия от accommodation
- Quote живёт минуты-часы, не секунды (как авиа) и не дни (как отели). Зависит от типа transfer'а: scheduled bus — часы; private car — минуты при peak demand.
- Pricing engine — комбинированный: некоторые supplier'ы дают фиксированный прайс (autobus компании с регулярными маршрутами), другие — dynamic pricing (private car services, ride-hailing intercity).
- Geographic constraints критичны: pickup и dropoff локации связаны geo-моделью, которая должна совпадать с другими segment'ами тура (transfer from airport X to hotel Y must reach Y within booking window).
- Capacity: transfer'ы часто имеют жёсткие ограничения (autobus: 50 мест; private car: 1-4 пассажира). Booking commit должен резервировать конкретные seats.
Каноничная модель TransferQuote
TransferQuote (расширение базового Quote):
base_quote_fields: id, supplier_quote_id, expires_at, ...
type: scheduled_bus / private_car / shared_van / rail / ride_hailing
pickup:
location (geo coordinates + named place: airport code, hotel id, custom address)
pickup_time
pickup_window (от-до для scheduled, exact для private)
dropoff:
location, expected_arrival_time
capacity:
seats_total, seats_reserved
vehicle_class: economy / standard / premium
pricing:
base_price
surge_multiplier (для dynamic pricing)
per_seat (для scheduled) / per_vehicle (для private)
cancellation_policy:
free_cancellation_until: ISO datetime
cancellation_fee_after: amount
Lifecycle
- Search — фильтрация по pickup/dropoff локациям, времени, capacity.
- Quote-snapshot — TransferQuote с
expires_at(минуты-часы). - Booking commit — резервация конкретных seats. Для scheduled — не требует revalidation (фиксированное расписание). Для private/dynamic — обязательная revalidation перед commit.
- Confirmation — обычно синхронное.
Refund при отмене
- Cancellation fees — определяются supplier'ом, фиксируются в TransferQuote на момент booking.
- Free cancellation до X часов до pickup — типично 24-48 часов.
- После cutoff — fee 50-100% от стоимости.
3. Insurance
Принципиальные отличия от accommodation
- Quote — это offer полиса, не доступности услуги. Quote живёт дольше всего (часы-дни), потому что условия полиса не меняются динамически.
- Pricing engine — actuarial model страховой компании. Платформа не имеет права влиять на цену, кроме transparent commission disclosure.
- Coverage rules жёстко определены полисом — платформа транслирует их клиенту перед purchase.
- Refund logic совершенно специфична — после commencement of coverage refund полностью отсутствует или сильно ограничен (это инвертированная семантика по сравнению с accommodation).
Каноничная модель InsuranceQuote
InsuranceQuote:
base_quote_fields: ...
policy_type: travel / medical / cancellation / baggage / multi_risk
coverage:
territories[]: list of country codes
period_start, period_end
coverage_limits: structured by risk class
deductibles
exclusions[]
insured_persons[]:
age_band
pre_existing_conditions_disclosure
premium:
amount, currency
tax_treatment (insurance premium tax differs by jurisdiction)
underwriter_id
policy_terms_url (link to actual policy document)
cooling_off_period_days: typically 14 (EU), 0 (некоторые юрисдикции)
Lifecycle
- Search — выбор policy_type, territories, period; ranked offers от разных insurers.
- Quote-snapshot — InsuranceQuote с
expires_atобычно 24-72 часа. - Disclosure step — клиент должен явно подтвердить ознакомление с policy terms перед purchase. Это — обязательный compliance step.
- Purchase — платформа issues policy через insurer; клиент получает policy document.
- Cooling-off period — клиент имеет право отменить полис в течение 14 дней (EU) с полным refund.
- Commencement of coverage — обычно совпадает с началом trip; после этой даты cooling-off закрывается.
Refund при отмене
- До commencement of coverage + в пределах cooling-off period — full refund.
- После commencement — обычно нет refund. Если есть — только pro-rata за неиспользованную часть.
- Если страховой случай уже произошёл — refund запрещён.
Compliance специфика
- EU Insurance Distribution Directive (IDD): распространение страховых продуктов требует регистрации платформы как insurance intermediary или работы через registered intermediary.
- Disclosure обязателен перед purchase: коммиссия платформы, IPID (Insurance Product Information Document).
- GDPR special category data: medical disclosures — sensitive personal data.
4. Activities and Experiences
Принципиальные отличия от accommodation
- Quote — обычно фиксированный прайс, не dynamic. Цена меняется реже всего.
- Capacity критична: tour spots ограничены, билеты в музей — конкретное количество на сеанс.
- Time slots — большинство activities привязаны к конкретному времени старта (10:00, 14:00, etc.), не к suite дате.
- Cancellation policies сильно варьируют: от free cancellation до non-refundable за hour до старта.
Каноничная модель ActivityQuote
ActivityQuote:
base_quote_fields: ...
activity_type: tour / museum / event / class / outdoor
venue:
location (geo + named)
venue_id
schedule:
activity_date
time_slot_start
duration_minutes
capacity:
spots_available, spots_reserved
participants:
age_categories[] (adult, child, senior с разной ценой)
inclusions[]: что входит в activity
exclusions[]: что не входит
pricing:
per_participant
cancellation_policy:
free_cancellation_until
fee_tiers[]
language: provided language(s) for guided activities
Lifecycle
Похож на transfer'ы (booking конкретного time slot с capacity), но без real-time pricing dynamics.
5. Ancillary Services
Принципиальные отличия от accommodation
- Привязаны к существующему booking (room upgrade — к hotel booking; airport transfer — к flight). Не самостоятельны.
- Lifecycle подчинён parent booking: при отмене parent booking ancillary автоматически отменяется (если supplier supports auto-cancel) или требует separate cancellation.
- Pricing часто bundle-aware: цена ancillary может зависеть от parent booking (early check-in cost depends on hotel rate).
Каноничная модель AncillaryQuote
AncillaryQuote:
base_quote_fields: ...
parent_booking_ref: (links to parent booking item)
parent_segment_type: accommodation / flight / activity / transfer
service_type: room_upgrade / late_checkout / airport_transfer / equipment_rental / room_service / spa
pricing:
standalone_price
bundle_discount (if any when bought with parent)
cancellation_policy:
aligned_with_parent: bool (если true — следует за parent)
independent_policy (если aligned_with_parent = false)
Lifecycle
- Discovery — добавление к существующему booking (cross-sell в чек-ауте) или после booking confirmation (upsell).
- Booking commit — atomic с parent booking (если в чек-ауте) или отдельный (для post-booking upsell).
- Cancellation — следует за parent если
aligned_with_parent, иначе независимо.
Связь с Tour Builder
Tour Builder композирует смешанные segment'ы в единый тур (например: 1 flight + 7 nights accommodation + 2 activities + 3 transfers + 1 insurance). Каноничные правила композиции:
Композиция Quote
- Каждый segment имеет свой Quote с своей semantic (см. правила выше).
- Tour-level Quote = aggregation segment-level Quote с дополнительными tour-wide правилами:
- tour-level cancellation policy (часто строже чем у отдельных segment'ов);
- tour-level commission и markup партнёра;
- tour-level disclaimer (Package Travel Directive notification);
- Tour-level expires_at = минимум segment-level expires_at. Если хотя бы один segment Quote устарел — весь Tour Quote устарел.
Revalidation тура
- Cascading revalidation: при revalidation тура запрашивается revalidation каждого segment'а в порядке стабильности (от наиболее volatile flight к наиболее стабильной insurance).
- При drift хотя бы одного segment'а — применяется логика tour-builder-operational-model.md, раздел про каскадный drift и auto-replace.
Drift handling по segment'ам
- Flight drift — наиболее частый и влияющий. Может потребовать re-routing всего тура.
- Accommodation drift — обычно price drift, реже availability drift. Может быть auto-replace на similar.
- Transfer drift — обычно time drift (изменилось расписание). Auto-adjust возможен.
- Insurance drift — редчайший. Если случается — обычно policy_terms change, требует disclosure step заново.
- Activity drift — capacity drift (sold out). Auto-replace на similar slot.
Процесс добавления нового segment-типа
При добавлении нового segment-типа (например, cruise или rail_pass_long_term) каноничный процесс:
- Семантическое моделирование: определить Quote-семантику (lifetime, pricing authority, revalidation rules, refund rules).
- Compliance-gap analysis: какие compliance-требования специфичны (например, maritime regulations для cruise).
- Расширение domain-model.md: добавить новый класс в группу композиционных сущностей.
- Создание раздела в этом документе.
- Обновление tour-builder композиции: добавление в cascading revalidation.
- Onboarding первого supplier'а — проверка модели на реальной интеграции.
Каноничный процесс не сокращается — каждый новый segment-тип проходит все 6 шагов до production.
Stage-aware подход
- Stage 1 (старт): только accommodation. Не-отельные segment'ы ingest'ятся, но не продаются через платформу.
- Stage 2: добавляется один не-отельный segment как pilot — обычно transfers (наиболее простой по semantic). Tour Builder поддерживает accommodation + transfer композиции.
- Stage 3: добавляются flights и insurance. Полная мульти-segment композиция.
- Stage 4+: activities, ancillaries, новые segment-типы.
Каноничные модели всех segment-типов проектируются с нулевого дня (этот документ), даже если их реальная продажа активируется только на следующих стадиях. Это исключает «мучительный re-engineering» о котором предупреждал внешний ревьюер.
Открытые вопросы и развилки
- Cruise как самостоятельный segment-тип или гибрид accommodation+activity? Cruise семантически содержит и accommodation (cabin), и activities (excursions). Решение между «cruise = новый segment-тип» и «cruise = composite» влияет на UX search.
- Rail passes (Eurail, JR Pass) — это inventory или отдельный financial product? Pass даёт доступ к unlimited-N journeys, что не укладывается в standard segment Quote.
- Bundle pricing: при покупке flight + accommodation вместе — единый bundle price или два отдельных Quote с явной дисконтной структурой? Влияет на пересчёт при drift.
- Тур как inventory item у партнёра: партнёр продаёт preset тур как «product» — он каноничный composite или новый item-type в каталоге?
Связанная документация
- Доменная модель — каноничная модель платформы, 7 групп сущностей.
- Tour Builder Domain — composition primitives.
- Tour Builder Operational Model — drift handling, revalidation cascade.
- Offer, pricing, booking semantics — общая Quote-семантика.
- Partner Finance and Clearing — settlement split при refund.
- Booking State Machine — состояния и transitions.
- Compliance and Legal — IATA, IDD, EU Package Travel Directive, GDPR.
- Development Roadmap — stage-aware activation segment-типов.