Airline Microservices Platform — Architecture Blueprint (Multi‑Tenant, Multi‑Provider, Multi‑Currency)¶
This document consolidates everything agreed and written in the conversation into a single, deliverable blueprint:
- True multi-tenant platform (3 airline brands) with multiple channels
- Search → Select → Ancillaries → Book → My Booking (view + modify + post-book ancillaries)
- Providers: start with ISO Gruppe integrator, later GDS (Amadeus) and NDC (Crazy Lama Easy Links)
- Offers may include legs from different providers
- One payment per purchase, single customer currency
- Discounts/Promotions and Loyalty pricing
- Change Orders for post-book paid changes
- Book now / Ticket later with rule-based windows (30 min → hours)
- Target scale: ~1000 searches/min (~16.7/sec) with provider fanout control and caching
1) Final service division (phase‑1 realistic, phase‑2 ready)¶
Platform / Tenant foundation¶
1. Tenant Config Service (owner of rules)¶
Owns (DB): - Tenants (airline brands) and channels - Allowed providers per tenant/channel/market - Markup/commission/rounding rules - Ticketing policies (issue now vs later windows) - PSP routing per tenant/currency/region - Feature flags (per tenant/channel)
Used by: Pricing, Search, Offer, Payment, Ticketing, BFF
2. Identity Service¶
Owns (DB): - Registered users, sessions, roles, auth claims
Provides: user identity for cross-channel continuity.
3. Guest Booking Access Service (PNR + last name)¶
Owns (DB): - Guest access grants (optional audit) - Token issuance policies
Purpose:
- User enters PNR + last name
- Service validates via Booking Service
- Issues short-lived BookingAccessToken with scoped permissions:
- read_booking
- modify_booking (optional)
- TTL short (15–60 minutes) and refresh requires re-validation
Do not treat “PNR+LastName” as authentication across services. Use the token.
Search & Shopping (pre‑booking)¶
4. Search Service (read side)¶
Owns (DB):
- SearchSession records
- Cached provider results (keyed by normalized search request + tenant/channel)
- Supplier health/latency statistics (optional)
Responsibilities: - High-throughput search fanout to Provider Gateway - Caching + partial results support - Returns “shopping view” options (not guaranteed final price)
Scaling notes: - 1000 searches/min ≈ 16.7/sec; provider calls are expensive → caching + concurrency limits are mandatory.
5. Itinerary Composition Service (required because offers can span providers)¶
Owns (DB): - Composition rules (connect-time constraints, combinability rules) - Optional cached compositions for a SearchSession
Responsibilities:
- Combine legs from multiple providers into a stable “virtual itinerary”
- Produce stable itineraryId and normalized segments
This keeps Search from becoming a “monster” and centralizes multi-provider combinability.
6. Offer Service (sellable contract)¶
Owns (DB): - Offers (time-limited) - Provider references per leg - BookingPlan (the orchestration plan to fulfill the offer) - Revalidation requirements per provider leg - Offer locking / reservation intent state
Responsibilities:
- Convert an itineraryId into a sellable Offer
- Store expiry per leg/provider and overall expiry
- Store the BookingPlan (multi-provider steps + compensation rules)
7. FX & Money Service (separate from Pricing)¶
Owns (DB):
- FX rates (ingested) + provider/source metadata
- Rate versions (fxRateVersionId)
- Rounding rules per currency
- “Rate lock” policy (how long a rate is honored)
Responsibilities: - Single source of truth for FX + rounding - Used by Pricing; referenced by Order for auditability
8. Pricing Service (multi-currency + channel + loyalty aware)¶
Owns (DB): - Optional pricing audit logs (recommended) - Optional caching of computed quotes keyed by (offerId, currency, customerContext, promo set)
Responsibilities:
- Compute totals in single customer currency
- Apply tenant/channel markups
- Apply loyalty pricing adjustments
- Apply promotions (via Promotions Service)
- Return breakdown + priceSignature (hash) to detect changes
9. Promotions Service¶
Owns (DB): - Campaigns, promo codes, eligibility, stacking, budgets, usage limits, audit
Responsibilities: - Validate promo codes - Return discount components + reasons - Does not mutate money directly; Pricing consumes results
10. Ancillaries Service (pre‑book and post‑book)¶
Owns (DB): - Ancillary catalog (if you maintain your own) - Rules and validation logic - Optional caching of seat maps / availability
Responsibilities: - List available ancillaries for an Offer (pre-book) - List available ancillaries for a CompositeBooking (post-book) - Validate compatibility and create ancillary line items
11. Cart Service (persistent cross‑channel)¶
Owns (DB): - Carts, cart lines, snapshots - Latest priceSignature, expiry, promo refs
Responsibilities: - Persistent cart across devices/channels for anonymous + logged-in - Store: - Offer reference - Passengers - Ancillaries selections - Promotions references - Price snapshot + priceSignature - Detect price changes / offer expiry
Commercial & Payment (money and contracts)¶
12. Order Service (Initial Orders + Change Orders)¶
Owns (DB): - Orders (immutable commercial record) - Order line items - Totals breakdown and currency - Status transitions - References to booking and ticketing outcomes
Responsibilities:
- Create Initial Order from cart snapshot
- Create Change Orders for post-book paid changes
- Emit OrderPaid after payment confirmed
13. Payment Service¶
Owns (DB): - Payment intents, transactions - Webhook inbox/outbox - Refunds, partial captures, retries - PSP routing metadata
Responsibilities: - PSP abstraction (per tenant/currency routing) - Payment lifecycle; webhooks - Refunds / chargebacks handling (future)
Travel domain (reservation + ticketing separated)¶
14. Booking Service (Composite Booking)¶
Owns (DB): - CompositeBooking records (unified view) - Mapping to ProviderBookings (PNRs) - Unified passenger list + itinerary summary - Change history/audit
Responsibilities:
- Consume OrderPaid and execute Offer.bookingPlan steps
- Create provider bookings (possibly multiple) through Provider Gateway
- Maintain unified booking state for “My Booking”
- Apply paid changes after Change Orders are paid
Status requirements (critical):
- Composite booking statuses must include:
- PENDING
- PARTIALLY_CONFIRMED
- CONFIRMED
- FAILED
- MANUAL_ACTION_REQUIRED
Because multi-provider booking isn’t atomic.
15. Ticketing Service (rule engine + queue)¶
Owns (DB): - Ticketing jobs (queue) - Attempt log + next schedule - Ticket issuance state per provider booking - Rules evaluation results
Responsibilities: - Decide issue now vs ticket later based on tenant/channel rules - Handle delay windows (30 minutes to hours) - Retries / backoff / manual queue - Ticket operations: issue, reissue, void (future)
Provider integration layer (shield the domain)¶
16. Provider Gateway (integration orchestrator)¶
Owns (DB): - Idempotency store - Correlation logs - Provider webhook inbox - Provider call audit (safe, minimal)
Responsibilities: - Normalized commands with resilience: - retries/backoff/circuit breaker - rate limiting - idempotency - correlation IDs and tracing - Webhook ingestion → normalized events
17. Provider Adapters (one per provider)¶
- ISOGruppeAdapter (phase 1)
- AmadeusAdapter (phase 2)
- NdcEasyLinksAdapter (phase 2)
Responsibilities: - Provider-specific mapping, quirks, credentials, endpoints
Supporting services¶
18. Notifications Service¶
Consumes order/booking/ticketing events and sends: - receipts - booking confirmations - ticket issued notifications - change confirmations
19. BFFs (Backend‑for‑Frontend) per channel/tenant (API composition)¶
Not a core “data owner”, but critical for: - DTO shaping - orchestration across services - caching and UI-friendly endpoints
Can be a shared codebase configured per tenant/channel.
2) Key domain contracts (schemas)¶
A) Itinerary (output of Itinerary Composition)¶
{
"itineraryId": "ITI_9f3c...",
"legs": [
{
"legId": "LEG_1",
"providerId": "ISO",
"providerSearchRef": "ISO_SRCH_abc",
"segments": [
{
"from": "TLV",
"to": "ATH",
"dep": "2026-02-01T08:00",
"arr": "2026-02-01T10:10",
"flightNo": "IZ123"
}
]
},
{
"legId": "LEG_2",
"providerId": "AMADEUS",
"providerSearchRef": "AMA_SRCH_xyz",
"segments": [
{
"from": "ATH",
"to": "MAD",
"dep": "2026-02-01T12:00",
"arr": "2026-02-01T14:40",
"flightNo": "IB456"
}
]
}
],
"passengers": { "adt": 1, "chd": 0, "inf": 0 }
}
B) Offer (multi-provider legs + BookingPlan)¶
{
"offerId": "OFF_123",
"tenantId": "AIRLINE_A",
"channelId": "WEB",
"customerCurrency": "EUR",
"expiresAt": "2026-01-15T13:45:00Z",
"legs": [
{
"legId": "LEG_1",
"providerId": "ISO",
"providerOfferRef": "ISO_OFFER_777",
"legExpiresAt": "2026-01-15T13:40:00Z",
"revalidateRequired": true
},
{
"legId": "LEG_2",
"providerId": "AMADEUS",
"providerOfferRef": "AMA_OFFER_888",
"legExpiresAt": "2026-01-15T13:42:00Z",
"revalidateRequired": true
}
],
"bookingPlan": {
"steps": [
{
"step": 1,
"providerId": "ISO",
"action": "CREATE_RESERVATION",
"legs": ["LEG_1"],
"timeoutSeconds": 20,
"compensation": { "onFailure": "NONE" }
},
{
"step": 2,
"providerId": "AMADEUS",
"action": "CREATE_RESERVATION",
"legs": ["LEG_2"],
"timeoutSeconds": 25,
"compensation": { "onFailure": "CANCEL_STEP_1_IF_POSSIBLE" }
}
],
"finalize": [
{ "action": "LINK_COMPOSITE_BOOKING" },
{ "action": "SCHEDULE_TICKETING" }
]
}
}
C) Price Quote (single customer currency + signature)¶
{
"offerId": "OFF_123",
"fxRateVersionId": "FXV_2026-01-15T13:00Z",
"currency": "EUR",
"components": [
{ "type": "BASE", "amount": 220.00 },
{ "type": "TAX", "amount": 54.30 },
{ "type": "CHANNEL_MARKUP", "amount": 9.99 },
{ "type": "LOYALTY_DISCOUNT", "amount": -12.00 },
{ "type": "PROMO", "code": "WINTER10", "amount": -10.00 }
],
"total": 262.29,
"priceSignature": "SIG_7baf..."
}
D) Composite Booking (unified “My Booking”)¶
{
"compositeBookingId": "CBK_555",
"tenantId": "AIRLINE_A",
"status": "CONFIRMED",
"providerBookings": [
{ "providerId": "ISO", "providerBookingId": "PNR1AB2", "status": "CONFIRMED" },
{ "providerId": "AMADEUS", "providerBookingId": "PNR9ZZ8", "status": "CONFIRMED" }
],
"ticketingStatus": "PENDING",
"passengers": [
{ "id": "P1", "lastName": "BOTO", "firstName": "MISYEA" }
],
"itinerarySummary": { "...": "..." }
}
3) Event backbone (topics and responsibilities)¶
Each service should use an Outbox pattern when emitting events to ensure consistency between DB state and published events.
Shopping → Order/Payment topics¶
OfferCreatedCartUpdatedOrderCreatedPaymentIntentCreatedPaymentSucceededPaymentFailed
Fulfillment topics¶
OrderPaid(Order emits after PaymentSucceeded is verified/reconciled)CompositeBookingCreationStartedProviderBookingCreated(per provider)CompositeBookingCreatedTicketingScheduledTicketIssuedTicketingFailedBookingChangeRequestedBookingChangeAppliedBookingChangeFailed
Notifications consumes¶
OrderPaidCompositeBookingCreatedTicketIssuedBookingChangeAppliedPaymentFailed(optional user messaging)
4) Minimal BFF endpoint set (phase 1)¶
Search¶
POST /searchGET /search/{searchSessionId}(polling status + partial results)
Offers¶
POST /offers(from itineraryId)GET /offers/{offerId}
Pricing¶
POST /pricing/quote
Cart¶
GET /cartPOST /cart/linesDELETE /cart/lines/{lineId}
Order/Payment¶
POST /orders(from cart snapshot)GET /orders/{orderId}
My Booking¶
POST /guest-access(pnr + last name → BookingAccessToken)GET /bookings/{compositeBookingId}(orGET /bookings/by-pnr/{pnr})POST /bookings/{id}/changes(initiates change order flow)
5) Reliability and scaling notes (the non‑negotiables)¶
Search fanout control¶
- Concurrency limits per provider
- Timeouts (return partial results)
- Cache by normalized request key + tenant/channel
- Track supplier health and degrade gracefully
Idempotency everywhere¶
- Offer creation
- Order creation
- Booking plan steps (each provider call)
- Payment webhooks
Async booking and ticketing¶
- Booking and ticketing are long-running workflows:
- return “in progress” states and allow polling
- emit state transitions as events
Multi-provider booking is not atomic¶
- Support
PARTIALLY_CONFIRMEDandMANUAL_ACTION_REQUIRED - Compensation rules per booking step:
- cancel prior steps if possible
- otherwise route to manual ops queue
Multi-currency auditability¶
- Order stores:
currency(customer currency)fxRateVersionIdand/or explicit applied rate IDs- breakdown components in customer currency
- provider settlement currency references (future)
Mermaid Diagrams (All Flows + Service Map)¶
Copy/paste these into Markdown files or Mermaid renderers.
Each diagram is syntactically valid Mermaid.
Diagram 1 — Service Landscape & Communication Directions¶
flowchart LR
%% Clients
subgraph clients["Clients"]
WebA["Airline A Website"]
WebB["Airline B Website"]
WebC["Airline C Website"]
Partners["Partner Channels"]
end
%% BFF
subgraph bff["BFF"]
BFFA["BFF Tenant Channel"]
end
%% Platform
subgraph platform["Platform"]
TenantCfg["Tenant Config"]
Identity["Identity"]
GuestAccess["Guest Booking Access"]
end
%% Shopping
subgraph shopping["Shopping"]
Search["Search Service"]
Compose["Itinerary Composition"]
Offer["Offer Service"]
Pricing["Pricing Service"]
FX["FX and Money"]
Promo["Promotions"]
Anc["Ancillaries"]
Cart["Cart"]
end
%% Commercial
subgraph commercial["Commercial"]
Order["Order Service"]
Payment["Payment Service"]
end
%% Travel
subgraph travel["Travel Domain"]
Booking["Booking Service Composite"]
Ticket["Ticketing Service"]
end
%% Integration
subgraph integration["Integration"]
PGW["Provider Gateway"]
ISO["ISO Adapter"]
AMA["Amadeus Adapter"]
NDC["NDC Easy Links Adapter"]
end
%% Support
subgraph support["Support"]
Notif["Notifications"]
end
%% Client entry
WebA --> BFFA
WebB --> BFFA
WebC --> BFFA
Partners --> BFFA
%% Platform access
BFFA --> TenantCfg
BFFA --> Identity
BFFA --> GuestAccess
%% Shopping flow
BFFA --> Search
BFFA --> Offer
BFFA --> Pricing
BFFA --> Anc
BFFA --> Cart
BFFA --> Order
%% Internal shopping links
Compose --> Search
Offer --> Compose
Pricing --> FX
Pricing --> Promo
Anc --> PGW
%% Commercial
Order --> Payment
%% Travel
Booking --> PGW
Ticket --> PGW
%% Providers
PGW --> ISO
PGW --> AMA
PGW --> NDC
%% Notifications
Payment --> Notif
Order --> Notif
Booking --> Notif
Ticket --> Notif
%% Config influence
TenantCfg --> Search
TenantCfg --> Pricing
TenantCfg --> Payment
TenantCfg --> Ticket
Diagram 2 — Flow 1: Search → Itinerary → Offer → Price → Cart¶
sequenceDiagram
autonumber
actor U as User
participant BFF as BFF
participant TC as TenantConfig
participant S as SearchService
participant PGW as ProviderGateway
participant ISO as ISOAdapter
participant COMP as ItineraryComposition
participant OFF as OfferService
participant PR as PricingService
participant FX as FxMoney
participant PROMO as Promotions
participant CART as CartService
U->>BFF: Search request dates pax route
BFF->>TC: Get tenant and channel rules
BFF->>S: Search flights tenantId channelId criteria
S->>PGW: Search normalized request
PGW->>ISO: Provider search phase one
ISO-->>PGW: Results
PGW-->>S: Normalized results with supplier status
S->>COMP: Compose itineraries from results
COMP-->>S: Itineraries itineraryId list
S-->>BFF: searchSessionId and itineraries
U->>BFF: Select itineraryId
BFF->>OFF: Create offer itineraryId tenantId channelId currency
OFF->>COMP: Get itinerary details by itineraryId
COMP-->>OFF: Itinerary details
OFF-->>BFF: Offer created offerId expiresAt
BFF->>PR: Request pricing quote offerId customerContext currency
PR->>FX: Get fxRateVersionId and rounding
FX-->>PR: fxRateVersionId and rate data
PR->>PROMO: Validate promotion eligibility
PROMO-->>PR: Discount components
PR-->>BFF: Price quote breakdown and priceSignature
U->>BFF: Add to cart
BFF->>CART: Add cart line offerId selections priceSignature
CART-->>BFF: Cart updated
Diagram 3 — Flow 2: Checkout (One Payment) → BookingPlan (Multi‑Provider) → Ticketing Now/Later¶
sequenceDiagram
autonumber
actor U as User
participant BFF as BFF
participant CART as Cart Service
participant ORD as Order Service
participant PAY as Payment Service
participant BK as Booking Service
participant PGW as Provider Gateway
participant ISO as ISO Adapter
participant AMA as Amadeus Adapter
participant TKT as Ticketing Service
participant NOTIF as Notifications
U->>BFF: Checkout
BFF->>CART: GET /cart
CART-->>BFF: Cart snapshot (lines + priceSignature)
BFF->>ORD: POST /orders (cart snapshot, currency)
ORD-->>BFF: OrderCreated (orderId, status=PendingPayment)
ORD->>PAY: Create payment intent (orderId, amount, currency)
PAY-->>BFF: paymentIntent info (redirect/3DS if needed)
U->>PAY: Complete payment (PSP UI)
PAY-->>PAY: PSP webhook received
PAY-->>ORD: PaymentSucceeded (orderId, txnId)
ORD-->>ORD: Mark order Paid
ORD-->>BK: Event: OrderPaid (orderId, offerId, passenger data, etc.)
BK-->>BK: Start BookingPlan execution
BK->>PGW: Step 1 - CREATE_RESERVATION (ISO legs)
PGW->>ISO: Create reservation
ISO-->>PGW: ProviderBookingId/PNR
PGW-->>BK: ProviderBookingCreated (ISO)
BK->>PGW: Step 2 - CREATE_RESERVATION (AMA legs)
PGW->>AMA: Create reservation
AMA-->>PGW: ProviderBookingId/PNR
PGW-->>BK: ProviderBookingCreated (AMA)
BK-->>BK: Link CompositeBooking
BK-->>ORD: CompositeBookingCreated (compositeBookingId, status)
BK-->>NOTIF: Booking confirmation (optional "in progress" state)
ORD-->>TKT: Event: TicketingScheduled (based on tenant rules)
TKT-->>TKT: Evaluate ticketing rules (issue now vs later window)
alt Issue Now
TKT->>PGW: TicketIssue (ISO PNR)
PGW->>ISO: Issue ticket
ISO-->>PGW: Ticket numbers
PGW-->>TKT: TicketIssued (ISO)
TKT->>PGW: TicketIssue (AMA PNR)
PGW->>AMA: Issue ticket
AMA-->>PGW: Ticket numbers
PGW-->>TKT: TicketIssued (AMA)
TKT-->>ORD: TicketIssued (compositeBookingId)
TKT-->>NOTIF: Tickets issued notification
else Ticket Later
TKT-->>TKT: Create job (notBefore + deadline)
TKT-->>NOTIF: "Ticketing scheduled" (optional)
end
Diagram 4 — Flow 3: My Booking (Registered or Guest) + Post‑Book Ancillaries (Change Order)¶
sequenceDiagram
autonumber
actor U as User
participant BFF as BFF
participant ID as Identity
participant GA as Guest Booking Access
participant BK as Booking Service
participant ANC as Ancillaries Service
participant PR as Pricing Service
participant FX as FX & Money
participant ORD as Order Service
participant PAY as Payment Service
participant PGW as Provider Gateway
participant ISO as ISO Adapter
participant TKT as Ticketing Service
participant NOTIF as Notifications
alt Registered user
U->>BFF: Login
BFF->>ID: Authenticate
ID-->>BFF: Access token
else Guest user (PNR + LastName)
U->>BFF: Enter PNR + LastName
BFF->>GA: POST /guest-access (pnr, lastName)
GA->>BK: Validate booking (by PNR)
BK-->>GA: Valid/invalid
GA-->>BFF: BookingAccessToken (scoped, short-lived)
end
U->>BFF: View booking
BFF->>BK: GET /bookings/{id} (token)
BK-->>BFF: Composite booking details
U->>BFF: Add post-book ancillaries
BFF->>ANC: Get available ancillaries (compositeBookingId)
ANC->>PGW: Provider ancillary availability (per provider booking)
PGW->>ISO: Query ancillaries (if ISO involved)
ISO-->>PGW: Availability
PGW-->>ANC: Normalized availability
ANC-->>BFF: Available ancillaries
BFF->>PR: Price delta quote (change context)
PR->>FX: Get fxRateVersionId
FX-->>PR: fxRateVersionId
PR-->>BFF: Delta PriceQuote (signature)
U->>BFF: Confirm purchase of change
BFF->>ORD: Create Change Order (delta lines + currency + signature)
ORD->>PAY: Create payment intent (change order)
PAY-->>BFF: paymentIntent info
U->>PAY: Complete payment
PAY-->>ORD: PaymentSucceeded (change order)
ORD-->>BK: Event: ChangeOrderPaid (what to apply)
BK->>PGW: Apply ancillaries to provider bookings
PGW->>ISO: Add ancillary (if relevant)
ISO-->>PGW: OK
PGW-->>BK: Change applied per provider
BK-->>ORD: BookingChangeApplied
BK-->>NOTIF: Change confirmation
opt Ticketing needed (EMD/reissue)
BK-->>TKT: Event: TicketingScheduled (change context)
TKT->>PGW: Issue EMD/Reissue
PGW->>ISO: Ticket action
ISO-->>PGW: OK
PGW-->>TKT: TicketIssued
TKT-->>NOTIF: Updated ticket notification
end
Diagram 5 — Ticket‑Later Rule Engine (Decision + Queue)¶
flowchart TD
A["TicketingScheduled event"] --> B{"Evaluate rules<br/>tenant, channel, provider<br/>payment, fare, risk"}
B -->|Issue now| C["Create immediate issuance jobs"]
B -->|Delay window| D["Create delayed job<br/>notBefore and deadline"]
B -->|Manual| E["Route to manual ops queue"]
C --> F["Attempt issuance"]
D --> F
F -->|Success| G["TicketIssued event"]
F -->|Failure retryable| H["Retry with backoff<br/>until deadline"]
H --> F
F -->|Failure not retryable| I["TicketingFailed event"]
I --> E
Starter Repo Blueprint (Monorepo Recommended)¶
This blueprint is designed for a true multi-tenant platform with many services, shared contracts, and consistent infra.
1) Repository structure¶
airline-platform/
README.md
docs/
architecture/
00-overview.md
01-services.md
02-events.md
03-flows.md
04-diagrams.md
mermaid/
flow-1-search-to-cart.mmd
flow-2-checkout-book-ticket.mmd
flow-3-mybooking-changeorder.mmd
landscape-services.mmd
ticketing-rules.mmd
contracts/
AirlinePlatform.Contracts/
src/
Events/
Dtos/
Common/
AirlinePlatform.Contracts.csproj
README.md
shared/
AirlinePlatform.SharedKernel/
src/
Money/
Tenant/
Time/
Idempotency/
Validation/
AirlinePlatform.SharedKernel.csproj
AirlinePlatform.Observability/
src/
Logging/
Tracing/
Metrics/
AirlinePlatform.Observability.csproj
AirlinePlatform.Http/
src/
Resilience/
Auth/
AirlinePlatform.Http.csproj
services/
bff/
Airline.Bff/
src/
tests/
Airline.Bff.csproj
tenant-config/
TenantConfig.Api/
src/
tests/
TenantConfig.Domain/
TenantConfig.Infrastructure/
identity/
Identity.Api/
Identity.Domain/
Identity.Infrastructure/
guest-access/
GuestAccess.Api/
GuestAccess.Domain/
GuestAccess.Infrastructure/
provider-gateway/
ProviderGateway.Api/
ProviderGateway.Domain/
ProviderGateway.Infrastructure/
adapters/
IsoGruppe.Adapter/
Amadeus.Adapter/ # phase 2
NdcEasyLinks.Adapter/ # phase 2
search/
Search.Api/
Search.Domain/
Search.Infrastructure/
itinerary-composition/
Composition.Api/
Composition.Domain/
Composition.Infrastructure/
offer/
Offer.Api/
Offer.Domain/
Offer.Infrastructure/
fx-money/
FxMoney.Api/
FxMoney.Domain/
FxMoney.Infrastructure/
pricing/
Pricing.Api/
Pricing.Domain/
Pricing.Infrastructure/
promotions/
Promotions.Api/
Promotions.Domain/
Promotions.Infrastructure/
ancillaries/
Ancillaries.Api/
Ancillaries.Domain/
Ancillaries.Infrastructure/
cart/
Cart.Api/
Cart.Domain/
Cart.Infrastructure/
order/
Order.Api/
Order.Domain/
Order.Infrastructure/
payment/
Payment.Api/
Payment.Domain/
Payment.Infrastructure/
booking/
Booking.Api/
Booking.Domain/
Booking.Infrastructure/
ticketing/
Ticketing.Api/
Ticketing.Domain/
Ticketing.Infrastructure/
notifications/
Notifications.Worker/
Notifications.Infrastructure/
infra/
docker/
docker-compose.local.yml
k8s/
base/
namespaces.yaml
configmaps.yaml
services/
search.yaml
offer.yaml
pricing.yaml
cart.yaml
order.yaml
payment.yaml
booking.yaml
ticketing.yaml
provider-gateway.yaml
tenant-config.yaml
identity.yaml
guest-access.yaml
ancillaries.yaml
promotions.yaml
fx-money.yaml
notifications.yaml
bff.yaml
gateways/
envoy-gateway/
gateway.yaml
httproutes.yaml
tls.yaml
observability/
otel-collector.yaml
grafana-dashboards/
loki/
tempo/
migrations/
postgresql/
README.md
build/
Directory.Build.props
Directory.Packages.props
nuget.config
.github/
workflows/
ci-contracts.yml
ci-shared.yml
ci-services.yml
deploy-k8s.yml
tools/
scripts/
dev-bootstrap.ps1
dev-bootstrap.sh
generate-contracts.ps1
generate-contracts.sh
2) Solution & project conventions (recommended)¶
A) One solution file per service + one root “meta” solution¶
services/search/Search.slnservices/offer/Offer.sln- plus
airline-platform.slnat root for developer convenience
B) Each service uses Clean Architecture-ish layering¶
*.Api(controllers, endpoints, auth, DTO mapping)*.Domain(entities, value objects, state machines)*.Infrastructure(EF Core, messaging, external calls)
C) Shared packages¶
contractsis versioned together in monorepo (or published as NuGet internally)sharedkernelcontains:- Tenant context (tenantId/channelId)
- Money types (currency, amount, rounding policy)
- Idempotency helper
- Validation utilities
3) Shared Contracts (Events + DTOs)¶
Event design rules¶
- Events are immutable facts (past tense)
- Include correlation IDs
- Include tenantId + channelId always
- Prefer small payloads with stable IDs referencing internal storage
Example event envelope:
{
"eventId": "evt_...",
"eventType": "OrderPaid",
"occurredAt": "2026-01-15T13:20:00Z",
"correlationId": "corr_...",
"tenantId": "AIRLINE_A",
"channelId": "WEB",
"data": {
"orderId": "ORD_123",
"offerId": "OFF_123",
"currency": "EUR",
"total": 262.29
}
}
4) Data ownership (DB per service)¶
Recommended: database-per-service (PostgreSQL schemas per service are acceptable early if you must, but isolate strongly).
- TenantConfig DB
- Identity DB
- GuestAccess DB (or reuse Identity DB with strict separation)
- ProviderGateway DB (idempotency + webhook inbox)
- Search DB (sessions/cache)
- Composition DB (optional)
- Offer DB
- FX DB
- Pricing DB (optional)
- Promotions DB
- Ancillaries DB
- Cart DB
- Order DB
- Payment DB
- Booking DB
- Ticketing DB
- Notifications DB (optional)
5) Local development blueprint (docker compose)¶
Include local dependencies: - PostgreSQL (multiple DBs or schemas) - Redis (cache/session) - RabbitMQ or Kafka (event bus) - OTel Collector + Grafana/Loki/Tempo (optional)
6) Messaging and workflow blueprint¶
A) Event bus¶
- RabbitMQ (topic exchanges) or Kafka (topics)
- Standardize:
- exchange/topic naming
- retry + DLQ strategy
- schema versioning rules
B) Sagas / workflows¶
- Booking is a saga driven by
OrderPaid - Ticketing is a saga driven by
TicketingScheduled
C) Outbox pattern¶
- Each service that emits events writes them to an outbox table transactionally
- A publisher worker reliably publishes and marks sent
7) Steps checklist (end‑to‑end, no missing steps)¶
- Search:
- BFF → Search (tenant/channel context)
- Search → ProviderGateway → ISO adapter (phase 1)
-
Search stores SearchSession and returns partial results if needed
-
Composition:
-
Composition creates
itineraryIdobjects, possibly combining providers -
Offer:
- Offer Service creates Offer for
itineraryId -
Offer stores multi-provider legs + BookingPlan + expiries
-
Quote:
- Pricing calls FX for
fxRateVersionId - Pricing calls Promotions + Loyalty source (Identity/Profile)
-
Pricing returns breakdown + signature
-
Cart:
- Cart stores offer + selections + signature snapshot
-
Cart detects expiry/price changes
-
Checkout:
- Order created from cart snapshot
-
Payment intent created (single payment)
-
Payment:
- PSP completes
- Payment webhooks processed and deduped
-
Order marks paid and emits
OrderPaid -
Booking saga:
- Booking consumes
OrderPaid - Executes Offer.bookingPlan steps through ProviderGateway
- Handles compensation / partial bookings / manual action
-
Emits
CompositeBookingCreated -
Ticketing saga:
- Ticketing evaluates rules and either:
- issues now
- schedules job window (30 min to hours)
- routes to manual queue
-
Emits ticket events
-
My Booking:
- Registered user uses Identity token
-
Guest user uses BookingAccessToken from GuestAccess
-
Post-book ancillaries:
- Ancillaries returns available post-book add-ons
- Pricing returns delta in same customer currency
- Change Order created
- Payment taken
- Booking applies changes, ticketing reissues if required
- Notifications sent
Appendix: Notes on future provider additions (Amadeus/NDC)¶
- Keep provider-specific semantics inside adapters.
- ProviderGateway normalized API must remain stable as new providers arrive.
- Offer and BookingPlan should keep per-leg provider IDs and references.