Travel Search → Offer → Reprice → Booking Reference Architecture
Travel metasearch ve booking sistemlerinde search, canonical offer, reprice, payment ve booking akışını uçtan uca reference architecture olarak tasarlayın.
Travel booking mimarisindeki kritik sınır search sonucu ile book edilebilir offer'ın aynı şey olmadığını kabul etmektir. Search, kullanıcıya seçenek üretir; reprice/availability check ise seçilen offer'ın halen geçerli olup olmadığını doğrular; booking ise provider tarafında yeni bir transaction yaratır.
Bu sayfa, hotel ve flight gibi farklı travel vertical'larında kullanılabilecek canonical bir omurga tanımlar.
Reference architecture
Travel search to booking reference architecture
1. Search context'i canonical yapın
Supplier request DTO'sunu domain modeliniz yapmayın. Önce ortak bir SearchContext üretin:
{
"searchId": "srch_123",
"vertical": "hotel",
"market": "TR",
"currency": "TRY",
"checkIn": "2026-10-10",
"checkOut": "2026-10-12",
"occupancies": [
{ "adults": 2, "childrenAges": [] }
]
}Adapter katmanı bu context'i provider-specific request'e çevirir. Böylece provider değiştirmek domain contract'ını bozmaz.
2. Search response ile canonical offer'ı ayırın
Her supplier farklı fiyat, tax, cancellation ve availability semantics'i taşır. Normalize edilmiş offer en az şu identity'leri korumalıdır:
- internal offer ID,
- supplier ID,
- supplier offer/rate ID,
- property/product reference,
- total price + currency,
- tax/fee breakdown,
- cancellation/refund policy,
- payment timing,
- room/fare/product attributes,
- availability/freshness timestamp,
- raw provider context veya opaque booking token.
Özellikle opaque token'ları kaybetmeyin. Search sırasında gelen bir booking token reprice veya booking call için zorunlu olabilir.
3. Offer immutable snapshot gibi davranmalı
UI'daki fiyatı daha sonra mutable bir row üzerinden güncellemek yerine seçilen offer'ın snapshot'ını tutun.
SearchOffer
-> SelectedOfferSnapshot
-> RepricedOffer
-> BookingIntent
-> ProviderBookingBöylece "kullanıcı hangi fiyatı gördü?", "reprice ne değiştirdi?" ve "hangi amount book edildi?" soruları cevaplanabilir.
4. Reprice ayrı bir domain adımıdır
Search sonucu doğrudan booking'e gitmemelidir. Reprice veya availability check şu değişiklikleri yakalamalıdır:
- fiyat değişti,
- tax/fee değişti,
- room/fare artık unavailable,
- cancellation policy değişti,
- payment model değişti,
- supplier token expire oldu,
- passenger/occupancy doğrulaması başarısız.
Reprice sonucu yeni bir OfferVersion üretmek, eski offer'ı overwrite etmekten daha güvenlidir.
5. Booking intent provider booking değildir
Kullanıcı "satın al" dediğinde önce internal bir BookingIntent oluşturun.
BookingIntent şunları bağlar:
- selected/repriced offer,
- traveler/passenger data,
- payment strategy,
- idempotency key,
- correlation ID,
- consent/terms version,
- client/session context.
Bu kayıt provider call başlamadan önce persist edilirse timeout durumunda recovery kolaylaşır.
6. Payment sequencing explicit olmalı
Tek bir doğru sıra yoktur. Provider ve commercial model'e göre:
authorize -> book -> capture
book -> authorize/capture
pay at property
virtual card / settlement lateruygulanabilir.
Bu nedenle PaymentState ve BookingState ayrı tutulmalıdır. "Payment success" booking confirmation değildir.
7. Booking create sonucu üçlüdür
Provider booking call için yalnız SUCCESS/FAILED kullanmayın:
CONFIRMEDFAILEDUNKNOWN
Network timeout veya connection reset sonrası provider'ın booking oluşturup oluşturmadığı bilinmiyorsa durum UNKNOWN'dur. Otomatik create retry duplicate booking üretebilir.
8. UNKNOWN recovery
Unknown booking outcome recovery
Recovery kaynakları:
- provider booking lookup,
- client reference / idempotency key lookup,
- webhook/event,
- scheduled reconciliation,
- manual operations queue.
9. Canonical domain boundaries
Önerilen temel entity'ler:
| Entity | Sorumluluk |
|---|---|
| SearchContext | Kullanıcının canonical arama intent'i |
| SupplierExecution | Her provider çağrısının latency/outcome kaydı |
| CanonicalOffer | Normalize edilmiş search offer |
| OfferVersion | Search/reprice sonrası immutable offer snapshot |
| BookingIntent | Kullanıcı booking isteği ve idempotency sınırı |
| PaymentAttempt | Payment lifecycle |
| BookingAttempt | Supplier booking çağrısı |
| Booking | Materialized canonical booking state |
| BookingEvent | Immutable lifecycle evidence |
| ReconciliationRecord | Unknown/divergent state recovery kaydı |
10. Correlation zinciri
Her aşama birbirine bağlanabilmeli:
searchId
-> offerId / offerVersion
-> bookingIntentId
-> paymentAttemptId
-> bookingAttemptId
-> providerReference
-> bookingIdProvider request/response logları PII veya PCI data nedeniyle ham olarak sınırsız tutulmamalıdır; redaction ve retention politikası uygulanmalıdır.
Failure modes
En önemli failure class'ları:
- stale search offer,
- reprice mismatch,
- duplicate provider booking,
- payment authorized fakat booking unknown,
- provider confirmed fakat local persistence başarısız,
- webhook gecikmesi veya kaybı,
- out-of-order lifecycle event,
- supplier partial outage,
- downstream timeout amplification,
- currency/tax normalization mismatch.
Observability
Minimum ölçümler:
- search success rate,
- supplier p50/p95/p99 latency,
- search → offer selection conversion,
- reprice success/mismatch rate,
- booking confirmation rate,
- booking UNKNOWN rate,
- duplicate-prevention hit count,
- reconciliation age,
- payment/booking divergence,
- end-to-end search → confirmed booking latency.
Trace üzerinde searchId, bookingIntentId ve providerReference aranabilir olmalıdır.
Production checklist
- canonical SearchContext,
- immutable OfferVersion,
- mandatory reprice/availability gate,
- BookingIntent persistence before provider write,
- explicit payment sequencing,
- CONFIRMED / FAILED / UNKNOWN booking outcomes,
- reconciliation path,
- operation-scoped idempotency,
- end-to-end correlation IDs,
- PII-safe logging and retention.
Design rule
Reference architecture'ın ana prensibi şudur:
Provider DTO'larını değil, lifecycle sınırlarını canonicalize edin.
Search, Offer, Reprice, Payment ve Booking birbirinden ayrı domain state'ler olarak modellendiğinde provider farklılıkları adapter katmanında kalır; retry, reconciliation ve troubleshooting ise ortak altyapı üzerinden yönetilebilir.
Mimarinizi birlikte review edelim.
Travel distribution ve metasearch mimarinizi ölçeklenebilirlik, hata senaryoları ve operasyon açısından değerlendirebiliriz.