Перейти к основному содержимому

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):

  1. Air transport (flights) — авиаперелёты.
  2. Ground transport (transfers) — автомобильные/автобусные/железнодорожные переезды.
  3. Insurance — страховые продукты (туристическая страховка, отмена путешествия, медицинская страховка).
  4. Activities and experiences — экскурсии, билеты в музеи, активный отдых.
  5. 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

Этапы:

  1. Search — поиск через GDS, возвращает ranked-список FlightQuote с короткими expiry.
  2. Quote-snapshot — выбранный FlightQuote сохраняется в платформе с явным expires_at (обычно 5-30 минут от GDS).
  3. Pre-checkout revalidation — обязательная revalidation за 60 секунд до booking commit. Подтверждает что цена и доступность всё ещё валидны.
  4. Booking commit — после успешной revalidation, в течение нескольких секунд от revalidation. Получаем PNR (Passenger Name Record).
  5. 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

  1. Search — фильтрация по pickup/dropoff локациям, времени, capacity.
  2. Quote-snapshot — TransferQuote с expires_at (минуты-часы).
  3. Booking commit — резервация конкретных seats. Для scheduled — не требует revalidation (фиксированное расписание). Для private/dynamic — обязательная revalidation перед commit.
  4. 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

  1. Search — выбор policy_type, territories, period; ranked offers от разных insurers.
  2. Quote-snapshot — InsuranceQuote с expires_at обычно 24-72 часа.
  3. Disclosure step — клиент должен явно подтвердить ознакомление с policy terms перед purchase. Это — обязательный compliance step.
  4. Purchase — платформа issues policy через insurer; клиент получает policy document.
  5. Cooling-off period — клиент имеет право отменить полис в течение 14 дней (EU) с полным refund.
  6. 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

  1. Discovery — добавление к существующему booking (cross-sell в чек-ауте) или после booking confirmation (upsell).
  2. Booking commit — atomic с parent booking (если в чек-ауте) или отдельный (для post-booking upsell).
  3. 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) каноничный процесс:

  1. Семантическое моделирование: определить Quote-семантику (lifetime, pricing authority, revalidation rules, refund rules).
  2. Compliance-gap analysis: какие compliance-требования специфичны (например, maritime regulations для cruise).
  3. Расширение domain-model.md: добавить новый класс в группу композиционных сущностей.
  4. Создание раздела в этом документе.
  5. Обновление tour-builder композиции: добавление в cascading revalidation.
  6. Onboarding первого supplier'а — проверка модели на реальной интеграции.

Каноничный процесс не сокращается — каждый новый segment-тип проходит все 6 шагов до production.

Stage-aware подход

В development/roadmap.md:

  • 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 в каталоге?

Связанная документация