Busflow Docs

Internal documentation portal

Skip to content
Reviewed 02 May 2026

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 person identity data on backoffice.person_profiles (8 columns: name, contact info, dietary needs) and links it to Commerce bookings and Communications contacts via soft FKs. See ADR-037 for the identity model decision.

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

  • PersonProfile β€” 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 (booker_profile_id), BookingCancelled, BookingNoShow, CheckoutAbandoned, AncillaryPurchased, PaymentCompletedBooking frequency, revenue (attributed to booker), cancellation patterns, upsell behavior. Note: only BookingConfirmed carries booker_profile_id in the payload. Other lifecycle events resolve the booker by joining booking_id β†’ bookings.booker_profile_id at consumption time.
OperationsBoardingEventCreated, OnboardSaleRecorded, ServiceLegCompletedBoarding behavior, onboard purchases, trip completion
CommunicationsMessageDelivered, MessageRead, ConversationResolvedChannel preference, response rates, engagement patterns. Hard filter: discard events from Contact records without a person_profile_id link.
BackofficePersonProfileUpdatedIdentity 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 PersonProfile ​

PersonProfile remains the identity anchor in Backoffice. Customer Intelligence reads it (via PersonProfileUpdated events) but never writes to it. CustomerProfile carries person_profile_id (soft FK to Backoffice PersonProfile) β€” CI creates a CustomerProfile only when a PersonProfile exists. CI never creates identity, it only enriches existing identity.

CI exposes a CustomerInsight read model that the Workspace UI consumes alongside the PersonProfile β€” giving dispatchers the full 360Β° view without coupling Backoffice to analytics logic.

Booker attribution: BookingConfirmed events carry booker_profile_id. CI attributes lifetime_revenue, booking_count, and average_booking_lead_time to the booker's CustomerProfile, not to accompanying travelers. Travelers receive travel-specific metrics (preferred seat, boarding behavior, tour preferences). See ADR-037.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            Workspace UI (CRM Screen)        β”‚
β”‚                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚ Person        β”‚   β”‚ 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 person_profiles β€” these are identity-level fields that belong on the profile regardless of CI.
  3. Document the Contact ↔ PersonProfile merge strategy β€” ensure Communications auto-links new Contacts to existing profiles by email/phone match. When a booker is identified on a Booking, Communications auto-creates or matches a Contact for the booker's PersonProfile.
  4. Keep PersonProfile lean β€” resist the temptation to add aggregated fields (lifetime_value, booking_count) directly to the profile. These belong in CI.

References ​

Internal documentation β€” Busflow