Unified Customer Profile
The single, continuously-updated record of a customer assembled from every touchpoint and business system — the object every other Intelligence & Services capability reads from.
High-Level Design
Every touchpoint and business system ultimately resolves into one profile record.
💼 Business Context
- Gives every team — marketing, support, sales — the same view of a customer instead of each system holding a fragmented slice of the relationship
- Directly enables personalization, support-context lookups, and propensity scoring, all of which depend on one trustworthy profile rather than reconciling several
- Owned by Data Engineering / Customer Data Platform team
🔌 Technical Overview
A scheduled dbt model rebuilds marts.customer_profile from the curated zone's identity-stitched events, merging demographic attributes, lifecycle stage, consent state, and computed fields (LTV band, churn risk) into one row per customer. The result is served by a .NET Core Analytics/AI API — packaged as a Docker container on Azure Container Apps — that exposes it through the Profile API, backed by Azure Database for PostgreSQL for low-latency point lookups and Azure Cache for Redis for the highest-traffic keys.
Profile Attributes
💾 Profile Record
{
"customer_key": "cust_004821",
"lifecycle_stage": "active",
"ltv_band": "gold",
"preferred_channel": "email",
"consent_basis": { "marketing": true, "analytics": true },
"updated_at": "2026-08-02T06:00:00Z"
}
🔗 Integration Points
- Curated Zone (Unified Data Foundation) — source of the identity-stitched events the profile is built from
- dbt — the modeling framework that materializes marts.customer_profile on a schedule
- Identity Graph — supplies the resolved customer_key this record is keyed on
- Profile API — the read path every downstream service and destination uses
🧰 Services Consumed
- Owning microservice —
Cxos.Profile.Api(see the Full Application Service Map) - Database — Azure Cosmos DB (Core API + Gremlin API) + Azure Cache for Redis
⚠️ Non-Functional Considerations
- Scale: profile table grows linearly with customer count, not event count, keeping it compact relative to the raw event volume
- Latency: point lookups by customer_key return in single-digit milliseconds via Redis cache in front of PostgreSQL
- Reliability: rebuilt on a fixed dbt schedule with dbt test coverage, so a bad upstream batch is caught before it overwrites a good profile
- Security/Privacy: every field carries the classification tags inherited from its source (Data Classification), and consent_basis gates which downstream purposes may read it
🎯 Enterprise Example
A support agent opens a ticket and the console calls the Profile API once, getting lifecycle stage, LTV band, and consent state in one round trip — replacing what used to be three separate lookups against CRM, Commerce, and a marketing tool that frequently disagreed with each other.