Project pattern · Financial services

Bank data into the public cloud – and through the audit

A consumer-finance institution, part of an international banking group, replaces its email system with Adobe Journey Optimizer. Introducing the tool was the smaller part. The hard part was releasing internal customer data to a cloud the bank does not own.

IndustryConsumer finance · Banking groupPlatformAdobe Journey Optimizer · Experience PlatformRoleLead Architect · Campaign EngineerDuration20 months to handover
Starting point

An email system that sends lists

What was running before – and why it no longer held.

Lists instead of profiles. Sending based on exported recipient lists. No continuous customer profile, no reaction to events.

Data in silos. Warehouse, core systems and third parties delivered separately. Merging happened manually, shortly before the send.

One channel. Email alone. SMS and push did not exist as orchestrated channels, at best as isolated solutions.

Context

What Adobe Journey Optimizer is – and why a bank chooses it

Adobe Journey Optimizer is the orchestration application of Adobe Experience Cloud. Not an email tool with a database attached, but an application on Adobe Experience Platform: every journey reads the same customer profile that segmentation, governance and Customer Journey Analytics use.

For the institution this meant one decision that carries everything else: which data leaves the building – and which does not. The warehouse remained the system of record. The platform received a defined slice, loaded in a batch cycle, with retention periods per dataset.

Project architecture: warehouse, Adobe Experience Platform, Journey Optimizer Three layers stacked. At the top the bank’s own house with the data warehouse as system of record and the core systems. In the middle Adobe Experience Platform with the Real-Time Customer Profile, the data lake with retention periods and the governance layer. At the bottom Adobe Journey Optimizer with the journey and the channels email, SMS, push, in-app and custom action. At the very bottom a return flow: unsubscribes go back to the warehouse in a 24-hour cycle. IN-HOUSE Data WarehouseSystem of record · retention Core systemsAccount status, products, consent Batch cycle · only the data needed for activation ADOBE EXPERIENCE PLATFORM Real-Time Customer Profile One record per customer – a single customer view instead of a recipient list Data LakeXDM schemas · TTL per dataset GovernanceConsent · audit logs · SSO & roles ADOBE JOURNEY OPTIMIZER Journey Event → condition → wait → channel Email SMS Push In-app Custom action Return flow: unsubscribes back to the warehouse in a 24-hour cycle
Simplified project architecture. The warehouse stays the system of record, the platform receives a defined slice. In-app was prepared, not rolled out. Own illustration based on the Adobe Experience Platform blueprints.

One profile instead of lists. Every send used to read an exported recipient list. In the Real-Time Customer Profile there is one record per customer, shared by segmentation, journey and reporting – whoever withdraws is withdrawn everywhere.

Events instead of send dates. Account opening, an application, an expiring deadline: the journey reacts to what happens, with wait steps and conditions in one logic instead of three tools.

New channels without new systems. SMS and push are outputs of the same journey as email. Consent, frequency and retention apply once – for all channels. That was the prerequisite for starting omnichannel at all.

The system of record stays in the building. The platform receives exactly as much as it needs to activate.
The hardest part

Customer data leaves the building – under what conditions?

At a bank, the question is not whether a marketing platform works technically. The question is which customer data it may see at all, how long it may keep it, and how it is proven that the data disappears again. This release was the longest and hardest part of the project – not the configuration.

The load-bearing architecture decision: the internal data warehouse remained the actual customer data platform. Journey Optimizer did not receive the full customer base, but specifically the attributes, events and flags needed for activation – in dedicated datasets, with a defined lifetime.

Concretely: a strict TTL concept per dataset, dedicated datasets instead of shared storage, deletion logic via the Data Hygiene API, and a robust connection back to the warehouse. Plus the evidence trail for the cyber-security audits: certificates, server locations, data flows, protocols, tool access.

Part of this was the preference center: timestamps and logic were agreed with Legal and Data Privacy, and unsubscribes run back to the warehouse in a 24-hour cycle with error handling – so that a withdrawal arrives where the data is held as system of record, not only in the platform.

Not the raw field into the cloud, but the derived attribute. What the platform does not need, it does not get.
Data model

From product to data requirement: the attribute catalogue

“What data do you need?” is the wrong first question. The right one is: which decision should the journey make – and what is the minimum information that carries it?

Before a single field was mapped, a catalogue was built. For every product and every use case of the institution the work ran backwards: from the message that should arrive at the customer, via the decision the journey has to make for it, to the data point that carries that decision. Only then came the technical side – event or attribute, XDM field, source system, load path.

Every row got two columns that are often missing in marketing projects and that decide the release in a bank: purpose and retention period. This table later became the basis for the conversations with Legal and Data Privacy – and the document that lay on the table in the audits.

Use caseDecision in the journeyData pointTypePurpose & retention
Welcome trackIs the contract active – and since when?Contract statusAttributeContractual communication · term + statutory period
Reacting to an applicationWas an application submitted, and is it open?Application receivedEventService communication · short period after closing
Regional targetingWhich region – without transferring the address?Region, derivedderivedRegional offers · tied to the contract
Channel choiceMay we contact by push?Consent per channelAttributeProof of consent · until withdrawal + evidence period
Offer logicThrough which sales route did the customer arrive?Origin flagAttribute + validityOffer control · duration of the programme

Example rows, anonymised and reduced to the pattern. The real catalogue covered the institution’s product range and was approved row by row.

The third row shows the principle that separates a catalogue from a wish list: the platform does not get the address, it gets the region. For the decision “which regional offer” the derived attribute is enough – and a field that is never transferred does not have to be deleted, protected and explained in an audit. Data minimisation here is not a compliance concession; it saves work in three places at once.

Origin is a basis for decisions, not an administrative field

A customer does not reach the institution only directly. Part of the business runs through sales partners – and what a customer may be offered afterwards depends on where they came from. For orchestration this is not an edge case but a class of requirements in its own right: origin needs its own attribute, a validity period, a precedence rule for the case where several programmes apply – and it must be read at the moment the message is built, not during the nightly import.

That made it clear why a recipient list no longer holds: the same campaign has to produce two different contents for two customers because their origin differs. That is personalisation as a rule set, not as a text block.

Journey condition · AJO expression
// Entry: in the audience, not contacted for 7 daysinAudience("Active customers – credit card")  and not inLastDays(#{Profile.lastContact.timestamp}, 7)// Offer logic: check origin while the programme is validnot isEmpty(#{Profile.origin.programId})  and nowWithDelta(0, "days") < toDateTime(#{Profile.origin.validUntil})// Channel: push only with consent and a device, otherwise emailisEmpty(#{Profile.pushToken}) or #{Profile.consents.push.val} != "y"

Functions inAudience, inLastDays, isEmpty, nowWithDelta, toDateTime from the AJO function reference; field paths are placeholders.

Schema design

From catalogue to schema: how an XDM tree is built

The attribute catalogue says which information is needed. The schema says what it looks like in the platform. Adobe puts it as an equation: Class + Schema Field Groups = XDM Schema.

A schema is “a set of rules that represent and validate the structure and format of data”. The class determines the behaviour of the data – record or time-series – and with it which field groups are eligible at all. A field group is a reusable component that defines related fields. The dataset is finally the table that data is ingested into; all data must conform to a pre-defined XDM schema.

For a marketing data model one distinction matters above all: XDM Individual Profile is record-based and describes the attributes of a person – mutable. XDM ExperienceEvent is time-series-based and captures the state of the system when something happened – immutable. Contract status is a profile attribute. “Application received” is an event. This assignment later decides whether a journey can react to an event or can only check a condition.

Which is exactly why Adobe’s best practices put one step before modelling: “Sort your data tables into profile, lookup, and event categories before constructing your schemas.” In the project this was the bridge from catalogue to schema – every row was assigned one of those three categories up front.

The project’s XDM tree, reduced to the pattern. Custom fields live under the tenant namespace: “Any custom properties must be nested under your TENANT_ID to avoid collisions with other field groups or fields.” Exactly one primary identity is required for the schema to be enabled for the Real-Time Customer Profile.

Through the Schema Registry API the same structure looks like this – the class is referenced via allOf, custom fields live in the tenant namespace:

XDM · Schema Registry API
// Reference the class – the "base class" of the schema{  "title": "Customer – activation",  "allOf": [ { "$ref": "https://ns.adobe.com/xdm/context/profile" } ]}// Custom field group: everything under the tenant namespace"_{TENANT_ID}": {  "activation": {    "origin": {      "programId":  { "type": "string" },      "validUntil": { "type": "string", "format": "date-time" }    }  }}// Identities – exactly one primary per schema"identityMap": {  "CRMID": [ { "id": "2e33192000007456-...", "primary": true  } ],  "email": [ { "id": "...",                "primary": false } ]}

Structure and identityMap per the Adobe documentation (Schema Composition, Schema Registry API); field and tenant names are placeholders from the project pattern. Experience Platform accepts neither null nor empty values in required fields on ingestion.

Two rules from the same documentation were more than style questions in a banking context. “Keep schemas as simple as possible. Add new fields only when necessary.” And: “If you are not sure whether a particular field is necessary to include in a schema, the best practice is to leave it out.” What the catalogue could not justify did not enter the schema – and therefore did not have to be defended in the audit. That schema changes are additive and breaking changes are not supported makes this discipline a necessity: a field that is in, does not quietly disappear again.

The difference between profile and event has one more consequence for retention: according to Adobe, events carry a higher risk of automatically expiring and being purged from the profile store. Anyone building a journey on an event needs to know how long that event is readable at all – a question that sits next to the retention period in the catalogue.

Content

Personalisation is a rule set, not a text block

A data model on its own sends nothing. Between profile and inbox lies the layer a campaign team works with every day: templates, reusable fragments, and the expressions that turn a field into a sentence.

The message designer reads the same profile fields as the journey condition. Two notations are available: Handlebars {{…}} for profile attributes and loops, and the Profile Query Language {%= … %} for functions and conditions. In a bank, one detail matters more than any design question: what happens when a field is empty? An optional attribute may be empty – the salutation may not.

AJO · personalisation with fallback
// Fallback when the attribute is empty or nullHello {%= profile.person.name.firstName ?: "there" %},// Content by contract state – one template, two statements{%#if profile.contract.status = "active" %}  … content for existing customers{%else%}  … neutral content without product reference{%/if%}

Syntax per the AJO personalisation documentation: ?: is the default fallback helper, PQL comparisons use a single =, not ==. Field paths are placeholders.

The second building block are fragments – “reusable components that can be referenced in one or more emails”. For a regulated institution this is not convenience but governance: mandatory disclosures, imprint, right-of-withdrawal notice and unsubscribe link live centrally, once. When Legal changes a wording it changes everywhere – per the documentation, changes “are automatically propagated to all contents using that fragment, including live journeys and campaigns”, as long as inheritance has not been broken.

One limit of this belongs in the operating manual, because otherwise it surfaces in production: adding new personalised attributes to a live fragment is not supported. Anyone wanting to extend a personalisation plans it in advance – or builds a new version.

On top came content templates as starting points for recurring tracks, and event tagging so that reactions flow back into the profile as events and the next journey can respond to them. Only with this layer does a data model become something a team can operate without developers – and that was precisely the goal of the handover.

Delivery

Three layers that have to hold together

Data foundation

Schemas and datasets following the attribute catalogue, mapping from the warehouse via Data Prep – including transformations and calculated fields, so that derived attributes are created on ingestion and not in the source system. Plus identities and merge rules, retention per dataset, and sandboxes for development, test and production so a change is not verified in live operation.

Channels

Email replacing the legacy system, plus SMS and push as orchestrated channels of the same journey. Consent and frequency apply per customer, not per campaign. Custom actions connect systems that have no channel of their own.

Operational readiness

SSO via SAML, a role model for campaign engineering, administration and approval, tasks and dependencies in Jira, dry runs before every step, and handover to the internal team with their own accounts.

Plan & blueprintTarget picture, scope, data requirements
Data foundationCatalogue, schemas, datasets, mapping
Release & auditsEvidence, reviews, deletion conceptruns in parallel from here
Channels & contentEmail, SMS, push, templates
EnablementWorkshops, dry runs, documentation
HandoverAccounts, roles, operational readiness
Approvals continue in parallel from here

The release did not happen at the end but ran in parallel from the data foundation onwards – every new data category brought a new review round.

The reviews

What an audit wants to see – and what it will not accept

The release did not happen in a single meeting. It was a series of reviews with the institution’s architects, with cyber security and with data privacy – each with its own questions and its own evidence.

What was delivered was not a presentation but a chain of evidence:

  • Data flows per data category – from source through ingestion and profile to channel and deletion, as a diagram and as a description.
  • Server locations and certificates of the vendor, mapped to the services actually in use.
  • Deletion concept with evidence – TTL per dataset, Data Hygiene API, and the answer to how you can tell that deletion happened.
  • Role and permission model – who may see which data, who may send, who may approve, connected via SSO.
  • Withdrawal path – preference center, timestamps, return flow to the warehouse in a 24-hour cycle with error handling.
  • The attribute catalogue – every row with purpose and retention, approved rather than asserted.

And the counter-check, because it costs the most time in projects like this: an audit does not accept “we only use what is necessary” without a field list. No deletion without evidence of how it is proven. No role that nobody owns by name. And no architecture sketch that does not show where the data sits.

Preparing these six points before the first audit shortens the release considerably. Supplying them afterwards means renegotiating every time.

Enablement & handover

What was handed over so it keeps running without me

A platform only the consultant can operate is not a result. The handover was therefore not a meeting at the end but a workstream of its own – parallel to the build.

Three workshop days took place on site, alongside remote sessions for accounts, sandbox approvals and open questions from day-to-day work. More than ten people were trained, from the campaign team up to management – not the same content for everyone: whoever builds journeys needs conditions and fragments; whoever approves needs the role model and the approval path; whoever owns the budget needs the architecture in one picture.

Blueprints and templates for the recurring tracks, so the team adapts rather than deciding from scratch for every campaign.

Documentation of the data model – the attribute catalogue with purpose and retention, the schemas, the mapping rules from the warehouse.

Role and approval model with individual accounts via SSO: campaign engineering, administration and approval separated instead of one shared login.

Backlog and dependencies in Jira, so open points do not live in an email thread after handover.

Dry runs before every step – documented, including the errors they found. That is the part that saves time at the next release.

In the end the data model, pipelines, deletion logic, SSO, roles, channels and approval processes were set up and documented. The security audits were evidenced with certificates, data flows and server locations. The internal team had their own accounts – and production was ready, the first test email delivered successfully.

How this enablement part is structured is described in detail under Enablement.

Where the road was meant to lead

The batch cycle was a deliberate decision, not a limitation: as long as the warehouse is the system of record, there is no reason to move data faster than it is needed. The planned next stage after rollout was near-real-time synchronisation via the Edge Network and Real-Time CDP – so that an event triggers a journey in seconds instead of in a daily cycle.

Email sending then becomes customer journey orchestration: SMS and push were connected, decisioning and in-app prepared. And because every journey runs on the same profile, decisions become measurable – who received which message when, what happened next, where the path breaks. For campaign engineers and architects this is exactly where the lever sits: not sending more emails, but making data-driven decisions visible across the company.

Transferable

Same pattern, different auditor

The task repeats in every regulated industry: a marketing tool is introduced, but the real work lies beneath it – in the data model, the retention periods, the evidence for the auditors.

In pharma the auditor is MLR instead of cyber security, the HCP profile replaces the customer profile, and instead of account status a claim approval decides. The structure of the problem stays the same: the system of record stays in the building, the platform receives exactly as much as it needs to activate – and the attribute catalogue decides how long the release takes. How this differs by industry is described under Industries. Why an initiative like this only holds if marketing, analytics, leadership and architecture have the same discussion is covered in the fundamentals article What Omnichannel Really Means.

Adobe Experience Cloud in detail
Frequently asked

What decision-makers ask before a project like this

Does our data warehouse remain the system of record?
Yes – and in regulated institutions that is usually the right decision. The platform receives a defined slice of the data for activation, not the customer base. Withdrawal and deletion run back to the warehouse, so that the leading data set is correct and not just the marketing platform.
What does a security audit actually require?
In this project it was six pieces of evidence: data flows per data category from source to deletion, server locations and vendor certificates, a deletion concept with proof, a role and permission model with named owners, the documented withdrawal path, and the attribute catalogue with purpose and retention per field.
How long does the data release take?
Longer than the technical introduction – and it does not run in one piece. Every new data category brings its own review round. Preparing the attribute catalogue with purpose and retention before the first audit shortens the release considerably; justifying fields afterwards means renegotiating every time.
What happens with unsubscribes and objections?
The withdrawal is created in the preference center, stored with a timestamp and runs back to the warehouse in a 24-hour cycle with error handling. Because all channels read the same profile, an unsubscribe takes effect for email, SMS and push at the same time – not per channel.
Does this require real time?
Not at the start. As long as the warehouse is the system of record and the use cases run on a daily rhythm, a batch cycle holds. Real time via the Edge Network and Real-Time CDP is a later stage – worthwhile as soon as events require a reaction within seconds.

Sources: Adobe Experience Platform blueprints, XDM Schema Composition, Best Practices for data modeling, Schema Registry API and the AJO personalisation and function references (Experience League, accessed 2 Sep 2026). Own illustrations. Project details anonymised; what is described is the work delivered – no customer data, no operating figures.

Let’s get to know each other.

Book an intro call