Canonical Offer, Order ve Booking State Model
Travel sistemlerinde Offer, Order ve Booking kavramlarını ayıran canonical state modelini ve booking state machine tasarımını kurun.
Travel entegrasyonlarında en sık yapılan modelleme hatalarından biri, provider'daki tek bir status alanını doğrudan internal booking state yapmak. Canonical model bunun yerine Offer, Order/Intent ve Booking'i ayrı lifecycle'lar olarak ele almalıdır.
Kavramsal ayrım
| Kavram | Ne ifade eder? | Mutable mı? |
|---|---|---|
| Offer | Belirli koşullarda satın alınabilir travel ürünü snapshot'ı | Yeni version üretilir |
| Order / BookingIntent | Kullanıcının seçilen offer'ı satın alma isteği | Kontrollü state transitions |
| Booking | Supplier tarafında yaratılan rezervasyon sonucu | Lifecycle boyunca değişir |
Provider terminolojisi farklı olabilir. Bazı API'ler "order", bazıları "reservation", "booking", "itinerary" veya "PNR" kullanabilir. Canonical model provider kelimesini değil davranışı normalize eder.
Offer state
Önerilen state'ler:
Canonical offer state machine
Offer state booking state değildir. Expired offer, daha önce yaratılmış booking'i iptal etmez.
Canonical Order / BookingIntent state
CREATED
-> VALIDATING
-> READY
-> SUBMITTING
-> SUBMITTED
-> COMPLETED | FAILED | UNKNOWNBookingIntent kullanıcının niyetini ve idempotency sınırını temsil eder. Aynı intent için ikinci bir supplier create çağrısı ancak önceki attempt'in authoritative olarak başarısız olduğu kanıtlanırsa yapılmalıdır.
Booking state machine
Canonical booking state machine
UNKNOWN neden first-class state?
Timeout şu anlama gelmez:
request timed out == booking failedDoğru ifade:
request timed out == local system outcome'u bilmiyorProvider booking'i yaratmış ama response kaybolmuş olabilir. Bu yüzden UNKNOWN retry değil reconciliation tetiklemelidir.
FAILED için kanıt seviyesi
FAILED state yalnız authoritative evidence ile verilmelidir:
- provider explicit rejection,
- valid lookup ile booking'in oluşmadığının doğrulanması,
- deterministic validation failure before provider submission.
Transport error tek başına FAILED değildir.
Provider mapping tablosu kullanın
Provider-specific state mapping configuration veya adapter içinde explicit tutulmalıdır.
provider status -> canonical state -> confidence/evidenceÖrnek:
| Provider response | Canonical state | Evidence |
|---|---|---|
| confirmed + reference | CONFIRMED | API response |
| validation_error | FAILED | authoritative rejection |
| HTTP timeout | UNKNOWN | transport ambiguity |
| webhook cancelled | CANCELLED | async provider event |
String karşılaştırmalarını business layer'a yaymayın.
State ve event'i ayırın
Current state hızlı okumak için materialize edilebilir; fakat evidence ayrı event log'da kalmalıdır.
{
"bookingId": "bk_42",
"state": "CONFIRMED",
"version": 7,
"lastEvidence": {
"type": "PROVIDER_CONFIRMED",
"source": "webhook",
"providerReference": "ABC123"
}
}Current state mutable olabilir; event history immutable olmalıdır.
Transition guard'ları
Her transition için şu sorular cevaplanmalı:
- hangi source bu transition'ı yapabilir?
- hangi previous state'lerden izin verilir?
- aynı event tekrar gelirse ne olur?
- event eskiyse ne olur?
- provider reference yoksa transition yapılabilir mi?
- payment state bu transition için prerequisite mi?
Modification ayrı attempt'tir
Booking modification'ı booking row'unu overwrite eden CRUD update gibi düşünmeyin.
Booking
-> ModificationAttempt
-> provider modify
-> CONFIRMED / FAILED / UNKNOWN
-> reconciliationAynı model cancellation için de geçerlidir.
Concurrency
Aynı booking'e API response, webhook ve reconciliation aynı anda gelebilir. Optimistic concurrency/version kontrolü kullanın:
UPDATE booking
SET state = ?, version = version + 1
WHERE id = ? AND version = ?Update başarısızsa state tekrar okunup event yeniden evaluate edilmelidir.
Invariant'lar
Canonical modelde faydalı invariant'lar:
- CONFIRMED booking provider reference'sız olmamalı,
- CANCELLED ancak confirmed booking lifecycle'ından gelmeli,
- FAILED sonrası aynı intent otomatik yeniden submit edilmemeli; retry policy explicit olmalı,
- UNKNOWN booking terminal state değildir,
- payment CAPTURED olması booking CONFIRMED zorunluluğu yaratmaz,
- booking CONFIRMED olması payment CAPTURED zorunluluğu yaratmaz.
Failure modes
- provider status'un canonical state'e yanlış map edilmesi,
- UNKNOWN outcome'un erken FAILED yapılması,
- stale/out-of-order event'in daha yeni state'i geri alması,
- aynı BookingIntent için paralel create attempt,
- payment state ile booking state'in birbirine karıştırılması,
- modification/cancellation sırasında version race.
Observability
Takip edin:
- state transition count,
- invalid transition count,
- UNKNOWN count ve age,
- duplicate event count,
- out-of-order event count,
- reconciliation resolution rate,
- state başına median duration,
- modification/cancellation UNKNOWN oranı.
Production checklist
- Offer / BookingIntent / Booking state'lerini ayrı tutun,
- terminal ve non-terminal state'leri explicit tanımlayın,
- UNKNOWN için reconciliation yolu sağlayın,
- provider mapping tablosunu adapter sınırında tutun,
- optimistic concurrency/version kontrolü kullanın,
- immutable event history saklayın,
- invalid transition ve duplicate event metriklerini izleyin.
İlişkili model
Bu state machine event-level audit için mevcut Booking Lifecycle Event Model ile birlikte kullanılmalıdır. State model "şu an neredeyiz?" sorusunu; event model "buraya nasıl geldik?" sorusunu cevaplar.
Mimarinizi birlikte review edelim.
Travel distribution ve metasearch mimarinizi ölçeklenebilirlik, hata senaryoları ve operasyon açısından değerlendirebiliriz.