Busflow Docs

Internal documentation portal

Skip to content

ADR-021: Customer Intelligence Bounded Context ​

Date: 2026-04-17 Status: Proposed [future β€” Phase 3]Deciders: Julian BrΓΌning

Context ​

The Busflow platform lists "360Β° Customer Profile" as a core differentiator (see PRODUCT_differentiators-10-percent.md Β§1). The current architecture stores passenger identity data on backoffice.passenger_profiles (8 columns: name, contact info, dietary needs) and links it to Commerce bookings and Communications contacts via soft FKs.

This baseline structure captures who the customer is but provides no mechanism to capture what they do, what they prefer, or what they are likely to want next. The planned feature surface requires:

  • Intelligent per-user recommendations (personalized tour suggestions)
  • Collaborative recommendations ("passengers who booked Nordsee also booked Ostsee")
  • Behavioral aggregation (booking frequency, lifetime value, channel preference, no-show rate)
  • Proactive anticipation (pre-fill checkout, seasonal rebooking prompts)
  • Seamless cross-media experience (unified identity across booking widget, WhatsApp, email, phone)

None of these capabilities belong cleanly in any existing bounded context:

ContextWhy It Doesn't Fit
BackofficeOwns PassengerProfile as master data, but behavioral analytics and ML models are outside its cohesion boundary.
CommerceOwns bookings and payments, but recommendations span beyond purchases (boarding behavior, communication patterns, trip feedback).
CommunicationsOwns messaging delivery, but deciding what to say (personalized content) is a separate concern from how to deliver it.
OperationsOwns fleet execution. Customer analytics falls outside its responsibility.

Decision ​

We introduce a fifth bounded context β€” Customer Intelligence β€” as a [future β€” Phase 3] planned addition to the bounded context map. It operates as an event-sourced analytics domain that consumes activity signals from all four operational contexts and produces enrichment, segmentation, and recommendation outputs.

Subdomain Classification ​

Core Subdomain. The 360Β° customer profile and intelligent recommendations are key competitive differentiators. A bus-tourism-specific CDP cannot be purchased off the shelf, and it directly drives customer retention and operator revenue.

Scope ​

The Customer Intelligence context owns:

  • CustomerActivityLog β€” event-sourced ledger of all customer touchpoints
  • BehaviorAggregate β€” materialized per-customer metrics (lifetime value, booking frequency, preferred seat, preferred boarding point, no-show rate)
  • CustomerSegment β€” cohort definitions for targeted marketing (e.g., "frequent Nordsee travelers", "high-value one-time bookers")
  • EngagementScore β€” computed customer health (NPS, satisfaction, churn risk)
  • RecommendationModel β€” ML pipeline outputs for per-user and collaborative suggestions
  • ChannelPreference β€” learned preferred communication channel per customer

The Customer Intelligence context does not own:

  • PassengerProfile β€” stays in Backoffice (identity + operator-managed preferences)
  • Contact β€” stays in Communications (messaging identity + delivery)
  • Booking / Passenger β€” stays in Commerce (transactional records)

Event Consumption ​

The context operates as a downstream consumer of domain events from all four operational contexts:

Source ContextEvents ConsumedData Extracted
CommerceBookingConfirmed, BookingCancelled, BookingNoShow, CheckoutAbandoned, AncillaryPurchased, PaymentCompletedBooking frequency, revenue, cancellation patterns, upsell behavior
OperationsBoardingEventCreated, OnboardSaleRecorded, ServiceLegCompletedBoarding behavior, onboard purchases, trip completion
CommunicationsMessageDelivered, MessageRead, ConversationResolvedChannel preference, response rates, engagement patterns
BackofficePassengerProfileUpdatedIdentity changes, dietary preference updates

Enrichment Outputs ​

The context produces enrichment signals consumed by other contexts:

Target ContextOutputPurpose
CommercePersonalizedOfferGeneratedTour recommendations for booking widget personalization
CommunicationsEngagementTrigger, ChannelPreferenceResolvedOptimal channel selection, re-engagement timing
BackofficeProfileEnrichmentAvailableAggregated metrics surfaced on the CRM screen and CTI pop-up

Relationship to PassengerProfile ​

PassengerProfile remains the identity anchor in Backoffice. Customer Intelligence reads it (via PassengerProfileUpdated events) but never writes to it. Instead, CI exposes a CustomerInsight read model that the Workspace UI consumes alongside the PassengerProfile β€” giving dispatchers the full 360Β° view without coupling Backoffice to analytics logic.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            Workspace UI (CRM Screen)        β”‚
β”‚                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ Passenger     β”‚   β”‚ Customer Insight  β”‚   β”‚
β”‚  β”‚ Profile       β”‚   β”‚ Read Model        β”‚   β”‚
β”‚  β”‚ (Backoffice)  β”‚   β”‚ (CI Context)      β”‚   β”‚
β”‚  β”‚               β”‚   β”‚                   β”‚   β”‚
β”‚  β”‚ Name, email,  β”‚   β”‚ Lifetime value,   β”‚   β”‚
β”‚  β”‚ phone, DOB,   β”‚   β”‚ booking count,    β”‚   β”‚
β”‚  β”‚ dietary needs β”‚   β”‚ preferred seat,   β”‚   β”‚
β”‚  β”‚               β”‚   β”‚ NPS score,        β”‚   β”‚
β”‚  β”‚               β”‚   β”‚ recommendations,  β”‚   β”‚
β”‚  β”‚               β”‚   β”‚ churn risk        β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Consequences ​

Positive ​

  • Clean separation of concerns: Operational contexts remain focused on their core workflows. Analytics logic does not bloat Backoffice or Commerce.
  • Event-sourced by design: The CustomerActivityLog can retroactively replay historical events once the context starts, filling the behavioral history from day one data.
  • ML-ready architecture: Dedicated context provides a natural home for recommendation models, feature stores, and training pipelines without polluting operational schemas.
  • GDPR-compliant by design: All customer analytics data concentrates in one context, simplifying erasure cascades and consent management.

Negative ​

  • Not implemented in Phase 1 or Phase 2. The operational contexts must emit the consumed events regardless β€” this creates a "publish now, consume later" pattern. All events listed above should already exist in the event catalog for operational purposes; CI simply adds a new consumer.
  • Cross-context read model complexity. The CustomerInsight read model requires Hasura Remote Relationships or a dedicated API endpoint to join with Backoffice data in the Workspace UI.

Risks ​

  • Premature optimization. Building the full CI context before understanding real usage patterns could lead to wrong aggregation choices. Mitigation: defer to Phase 3, let Phases 1–2 generate real data.
  • Event schema coupling. CI depends on a stable event schema from all four operational contexts. Breaking changes to event payloads affect CI consumers. Mitigation: event contracts are already versioned (see event-catalog.md).

Preparation (Phase 1–2) ​

While the full CI context is deferred, the following actions during Phases 1–2 lay the groundwork:

  1. Ensure all events listed above are emitted by their source contexts (most already exist in the event catalog).
  2. Add marketing_consent and locale to passenger_profiles β€” these are identity-level fields that belong on the profile regardless of CI.
  3. Document the Contact ↔ PassengerProfile merge strategy β€” ensure Communications auto-links new Contacts to existing profiles by email/phone match.
  4. Keep PassengerProfile lean β€” resist the temptation to add aggregated fields (lifetime_value, booking_count) directly to the profile. These belong in CI.

References ​

Internal documentation β€” Busflow