Your Event-Driven Architecture Is Really CDC

⏱ 20 min read

There’s a hard truth sitting in the middle of many so-called event-driven architectures: they are not event-driven in any meaningful business sense. They are change propagation pipelines with nicer branding.

That sounds harsher than I mean it to. But if your landscape is a row of microservices listening to database changes, replaying topics, and updating local read models because some upstream table flipped from PENDING to SHIPPED, then what you have is not a choreography of rich domain events. It is Change Data Capture wearing a conference badge.

And that’s not a criticism. In many enterprises, CDC is exactly the right answer.

The trouble begins when teams confuse one thing for the other. They tell themselves they have domain events, but the payloads are really table mutations. They talk about autonomy, yet every service quietly depends on the source schema of the service upstream. They call it decoupling, but the coupling has simply moved from REST contracts into topic shapes and replication semantics.

This distinction matters because architecture is not made of diagrams. It is made of consequences.

If you understand that your “event-driven” system is really a change propagation mechanism, you make better choices. You use CDC deliberately. You design for reconciliation. You accept eventual consistency not as an abstract principle but as an operational tax. You separate business meaning from storage churn. And, crucially, you stop forcing domain-driven language into a plumbing problem.

So let’s be honest about the shape of the thing. A great many enterprise event platforms are really CDC-led integration architectures. The right move is not to deny that. The right move is to architect it properly. integration architecture guide

Context

Modern enterprises are full of pressure in both directions.

On one side sits the old world: monoliths, packaged applications, shared databases, batch jobs, and operational systems that were never designed to publish clean domain events. SAP, Oracle, mainframes, policy admin platforms, claims engines, warehouse systems, and hand-built transactional applications all keep the business alive. They hold the truth that matters.

On the other side sits the new world: Kafka, streaming platforms, cloud-native services, operational data products, analytics pipelines, customer notification services, fraud models, and digital channels that want data as soon as it changes. Not nightly. Not in a settlement batch. Now. event-driven architecture patterns

That tension gives rise to an architecture pattern that appears again and again:

  • A core transactional system changes state
  • CDC reads the transaction log or equivalent source
  • Changes are published to Kafka or another event backbone
  • Downstream microservices react, transform, enrich, and project data
  • The enterprise calls this event-driven architecture

Again: often that is a perfectly sensible move.

The mistake is pretending these technical change records automatically carry business semantics. A customer row updated three times in ten seconds is not the same thing as “Customer Relocated.” An order line item changing status is not necessarily “Order Confirmed.” A policy premium adjustment is not automatically “Policy Repriced” in a domain sense. Storage changes and domain facts overlap, but they are not twins. They are cousins with an uncomfortable family resemblance.

That is where domain-driven design enters the picture. Not as ceremony. As a survival tool.

Problem

The central problem is simple to state and awkward to solve:

How do you propagate change across enterprise systems quickly and safely without turning every consumer into a hostage of upstream persistence design?

Most organizations land on CDC because it is one of the few techniques that works against existing systems at scale. You can extract change from a monolith without rewriting the monolith. You can stream updates from a packaged application you do not control. You can avoid hammering source systems with polling. You can build downstream autonomy without waiting for a multi-year core replacement.

But CDC has an inconvenient property: it emits what changed in storage, not necessarily what happened in the business.

That gap creates a string of architectural headaches:

  • Consumers infer business meaning from low-level updates
  • Source schema changes ripple through the estate
  • Ordering becomes murky across aggregates
  • Deletions, merges, and corrections become dangerous
  • “Exactly once” gets oversold and under-delivered
  • Read models drift from source truth over time
  • Teams debate whether an event is canonical when it is really just replicated state

This is where many architecture programs go sideways. They try to solve a semantic problem with transport technology. More Kafka topics. More schema registry controls. More stream processors. More enrichment layers. Useful tools, all of them. None of them magically convert storage deltas into bounded-context language.

A system can be event-shaped and still be semantically thin.

Forces

Several forces make this problem stubborn.

Legacy gravity

Large enterprises rarely get to start with event-native systems. They inherit platforms where the transaction log is the cleanest signal available. A payments core, claims engine, ERP, or order management system may not expose domain events at all. CDC becomes the only practical seam.

Speed of propagation

Business now expects near-real-time visibility. Fraud checks, inventory promises, customer notifications, and downstream risk calculations all want fresh data. Batch is too slow. CDC gives a path to immediate propagation with minimal source impact.

Domain boundaries are messy

Domain-driven design tells us to align systems with bounded contexts. Good advice. But real enterprises are not clean maps. Customer, account, order, claim, shipment, contract, and invoice concepts bleed across teams and platforms. One system’s aggregate is another system’s reference data. Event meaning is not universally agreed.

Autonomy versus consistency

Microservices promise independent deployability and local models. But the more data they replicate, the more they inherit eventual consistency problems. Local autonomy increases the need for reconciliation. You can have looser runtime coupling, but you do not get to skip data stewardship.

Compliance and audit

Regulated domains often need an immutable record of what changed, when, and why. CDC helps with traceability. But audit-grade traceability is not the same as business-grade event semantics. A regulator may care that a field changed. A downstream pricing engine may care why.

Platform economics

Kafka and modern streaming infrastructure make change propagation cheap, scalable, and repeatable. Once the platform exists, every integration problem starts looking like a topic. The tool invites overuse. Enterprises do this because platforms create gravity too.

Solution

The practical solution is not “never use CDC.” It is this:

Treat CDC as a technical event source for change propagation, then introduce domain semantics deliberately where they matter.

That means separating two layers that organizations often muddle together:

  1. Propagation layer
  2. Reliable movement of state changes from source systems into the enterprise backbone.

  1. Semantic layer
  2. Translation of those changes into bounded-context concepts, business events, commands, read models, or integration contracts fit for consumers.

This distinction sounds small. It is not. It changes ownership, schema strategy, migration sequencing, and operational controls.

At the propagation layer, the contract is technical and explicit:

  • source identity
  • change type
  • before/after state or diff
  • transaction ordering metadata
  • replayability
  • idempotency support

At the semantic layer, the contract is business-oriented:

  • aggregate identity
  • event intent
  • invariant meaning
  • lifecycle significance
  • consumer-safe fields
  • bounded-context language

A good architecture does not force every consumer to interpret raw CDC. That is lazy, and laziness at the integration boundary compounds. Instead, it places translation where the business value appears. Some consumers may use raw change streams. Others should receive curated domain or integration events.

The memorable line here is this:

CDC is how the system twitches. Domain events are how the business speaks.

Confuse the twitch for the speech and you will build brittle systems very quickly.

Architecture

A practical enterprise architecture usually has four distinct zones:

  1. System of record
  2. CDC ingestion and transport
  3. Semantic translation and stream processing
  4. Consumer services, projections, and analytics

Here is the high-level shape.

Architecture
Architecture

This is not just a pipeline. It is a set of responsibilities.

System of record

This remains the source of truth for transactional mutation. In a migration, it may still own the authoritative write path for years. Pretending otherwise does not speed transformation.

CDC connector

Tools such as Debezium, vendor replication products, or database-native log capture emit raw change records. They are excellent at moving facts about persistence transitions. They are not domain modelers. Ask them to be one and you are inviting accidental complexity.

Kafka raw change topics

These topics should be treated as platform-level data products, not universal business APIs. Their audience is limited: platform services, translators, reconciliation jobs, some analytics uses, and carefully chosen technical consumers.

Raw topics are usually partitioned by entity key or table key, with strong schema governance around metadata. Retention and replay strategy matter enormously here. These streams are the enterprise memory of technical change. EA governance checklist

Translation service or stream processor

This is where many architectures earn their keep. A translator can:

  • combine multiple low-level changes into a meaningful business transition
  • suppress noisy intermediate updates
  • enrich with reference data
  • validate invariants
  • emit consumer-safe integration events
  • map from storage terms to domain terms
  • maintain stateful correlation across tables or transactions

This may be implemented with Kafka Streams, Flink, bespoke consumers, or even a small application service. The key is not the product choice. The key is recognizing that semantics live here, not in the CDC connector.

Domain or integration topics

Now we get to useful enterprise contracts. A ShipmentDispatched event means something. An InvoicePosted event means something. An AccountStatusChanged event may or may not mean enough depending on your domain, but at least it is trying.

These topics should be bounded-context aware. They are not “canonical enterprise events” in the old integration-program sense unless you enjoy never-ending committee debates. Better to publish context-specific contracts that are stable enough for their consumers.

Consumer services

Microservices should consume the highest-level event that matches their need. Some will subscribe to integration events. A few platform services may consume raw CDC for technical purposes. That is healthy. Not every consumer deserves direct exposure to persistence churn.

Domain semantics discussion

This is where DDD matters most.

Domain-driven design is often misread as “name your services after nouns.” That is the least interesting part. The important idea is that language and boundaries should reflect the business model, not the database model.

A customer master table may contain demographic updates, preference changes, loyalty adjustments, consent changes, and merge operations. Those are not one thing in domain terms. A single table can span multiple subdomains and policies. If you publish all updates from that table as one generic event stream and let consumers infer meaning, you are pushing the complexity outward. You are also forcing every consuming team to reverse-engineer your aggregate semantics from your storage layout.

That is not architecture. That is leakage.

A better pattern is to identify a bounded context where the semantics matter and create events from that perspective:

  • CustomerConsentWithdrawn
  • CustomerMerged
  • LoyaltyTierChanged
  • CustomerAddressCorrected

Notice the difference. We’ve moved from “row changed” to “business fact occurred.”

Sometimes you cannot get all the way there. Fine. Publish well-defined integration events instead of pretending to have pure domain events. A carefully curated CustomerProfileUpdated integration event is more honest than a raw database delta masquerading as business truth.

Honesty is underrated in architecture.

Migration Strategy

The migration path matters more than the target diagram. Enterprises do not replace their core systems in one noble leap. They strangle them, awkwardly, over time.

CDC is often the first seam in a progressive strangler migration because it lets new capabilities observe legacy state changes without invasive modification to the legacy system. That is incredibly useful. But the migration must be staged carefully.

Migration Strategy
Migration Strategy

Stage 1: Observe

Start by capturing changes from the legacy system and publishing them into Kafka. Resist the urge to call everything a domain event. The goal at this stage is visibility and decoupled consumption.

Use this phase to learn:

  • actual change frequency
  • ordering patterns
  • dirty data realities
  • transaction boundaries
  • downstream use cases
  • reconciliation needs

Reality always arrives with more edge cases than the PowerPoint deck suggested.

Stage 2: Project

Build downstream read models, search indexes, notifications, and analytics consumers. This gives quick business value with limited write-side risk. It also proves whether the CDC stream is stable enough to support operational workloads.

Stage 3: Translate semantics

Introduce translation services that emit business-oriented integration events. Do this around high-value domains first: order lifecycle, payment lifecycle, customer consent, shipment milestones, case status, policy issuance.

This is where bounded contexts become explicit. The translator becomes a bridge from legacy data behavior to modern service contracts.

Stage 4: Carve out capabilities

New domain services begin owning capabilities that were once trapped in the monolith. At first they may still depend on the monolith for reference state. Over time they take over pieces of the write path.

Stage 5: Redirect writes selectively

Do not redirect writes until you understand the reconciliation model. During coexistence, dual writes are dangerous, and eventual consistency will expose every hidden assumption in the business process. Write redirection must be incremental and accompanied by explicit source-of-truth decisions.

Stage 6: Retire legacy slices

Only retire legacy functionality when:

  • ownership boundaries are clear
  • downstream dependencies are cataloged
  • reconciliation confidence is high
  • operational support is ready
  • fallbacks are defined

A strangler migration succeeds not by speed alone, but by controlling semantic drift during transition.

Reconciliation discussion

If CDC is your integration backbone, reconciliation is not optional. It is the price of admission.

Why? Because downstream services with local stores will drift. Messages are delayed. Consumers fail. Schemas evolve. Backfills happen. Source systems get corrected manually. Data is reprocessed. Duplicate delivery occurs. Some messages arrive out of order. This is normal. The architecture must assume it.

Reconciliation comes in several forms:

  • Point-in-time comparison
  • Compare downstream projections to source-of-truth snapshots.

  • Key-based completeness checks
  • Ensure every source entity exists where it should downstream.

  • Aggregate-level validation
  • Verify business invariants, not just row counts.

  • Replay-based repair
  • Rebuild state from retained change logs or semantic topics.

  • Compensating correction events
  • Publish correction messages when bad transformations or source errors are discovered.

Here is the uncomfortable truth: if you cannot reconcile, you do not really own the system. You are merely hoping.

A mature architecture includes:

  • replayable Kafka topics
  • deterministic consumer logic where possible
  • dead-letter handling with business triage, not just technical parking lots
  • snapshotting strategy for large rebuilds
  • periodic control reports
  • clear source-of-truth designation per data set

In regulated industries, reconciliation is often what turns an experimental event platform into a production-grade integration backbone.

Enterprise Example

Consider a global retailer modernizing its order management landscape.

The company has:

  • a legacy order management monolith on Oracle
  • warehouse systems in multiple regions
  • a CRM platform
  • e-commerce channels
  • a growing set of microservices for customer notifications, inventory visibility, and returns
  • Kafka as the enterprise streaming backbone

The architecture team initially declared an “event-driven transformation.” In practice, the first milestone was Oracle log-based CDC into Kafka. Every insert and update on order headers, order lines, shipment tables, and payment authorization records flowed into raw topics.

Downstream teams rushed in. Notification services sent customer emails when certain fields changed. Inventory services inferred reservation events from line updates. Analytics built operational dashboards. Returns processing stitched together shipment and invoice changes.

It worked. Until it didn’t.

Problems surfaced quickly:

  • multiple table updates represented one business action, but arrived as separate messages
  • some updates were intermediate states invisible to the customer but visible to consumers
  • a schema change in the monolith broke half a dozen downstream consumers
  • order cancellations and amendments produced conflicting interpretations
  • replays caused duplicate notifications because consumers treated state changes as one-time business events
  • warehouse systems disagreed with order projections due to delayed messages and manual corrections

The turning point came when the retailer introduced a translation layer.

A stream processor correlated raw order and shipment CDC records and emitted explicit integration events:

  • OrderAccepted
  • OrderRejected
  • OrderCancelled
  • ShipmentAllocated
  • ShipmentDispatched
  • OrderReadyForRefund

Now notification services consumed shipment and order events rather than guessing from table mutations. Inventory visibility consumed allocation and cancellation events. Returns processing consumed refund readiness events. Raw CDC remained available for audit, troubleshooting, and a few specialist technical consumers.

The result was not ideological purity. It was operational sanity.

The monolith still existed. CDC still powered the platform. But semantics were lifted into the right layer, and the migration could proceed one capability at a time.

Operational Considerations

An architecture like this lives or dies in operations.

Topic design

Raw CDC topics and semantic topics serve different purposes and should not be governed the same way. Raw topics need strong retention, metadata consistency, and limited consumer access. Semantic topics need clear ownership, versioning rules, and consumer-oriented SLAs.

Partitioning and ordering

Kafka gives ordering within a partition, not across the universe. That is enough if your partitioning aligns with the aggregate that matters. It is not enough if your business event spans multiple aggregates without correlation logic.

Ordering bugs are classic failure modes in CDC-led systems. Design around aggregate boundaries and transaction semantics explicitly.

Idempotency

Consumers must be idempotent. Full stop.

Replays, duplicates, retries, and compensations are normal. If a service cannot safely process the same logical event more than once, it is not ready for production event consumption.

Schema evolution

CDC streams are notoriously sensitive to source schema changes. Additive change is manageable. semantic reinterpretation is not. Downstream consumers of raw topics should be few and disciplined. Translation layers absorb a great deal of this pain.

Backfills

You will need backfills. Every enterprise eventually does. A new service appears, an old bug is found, a projection must be rebuilt, or a regulator asks for replayed history. Plan for controlled backfill paths that do not accidentally retrigger business actions.

Security and data minimization

Raw CDC often contains more data than consumers need, including sensitive fields. That alone is a strong reason to prefer curated semantic topics for general consumption. Data governance is easier when contracts are intentional. ArchiMate for governance

Tradeoffs

CDC-led event propagation is powerful, but it is not free.

What you gain

  • low-impact integration with legacy systems
  • near-real-time propagation
  • scalable enterprise backbone with Kafka
  • replayability and audit support
  • progressive migration path for monoliths
  • decoupled downstream reads and reactions

What you pay

  • weaker native domain semantics
  • potential coupling to source persistence structures
  • eventual consistency everywhere
  • need for reconciliation and repair
  • ordering and deduplication complexity
  • translation services that become critical infrastructure

This is the trade that matters: CDC reduces source-system intrusion but increases semantic work downstream. It shifts complexity; it does not erase it.

And that can be a very good trade. Especially in large enterprises where changing the source is politically or technically impossible.

Failure Modes

Architects should name failure modes plainly. Systems fail along predictable seams.

Failure Modes
Failure Modes

Semantic drift

Consumers attach different meanings to the same raw change. One team thinks status X means accepted; another thinks it means pending review. Both are wrong in edge cases. This is the most common enterprise failure.

Consumer explosion on raw topics

Too many consumers depend directly on CDC streams. Now every source schema change becomes an enterprise coordination event. You have recreated shared database coupling in streaming form.

Broken ordering assumptions

Teams assume message order across entities or across tables. Production teaches them otherwise.

Duplicate side effects

Replays or retries trigger duplicate emails, refunds, workflow actions, or external API calls because consumers are not idempotent.

Drift without reconciliation

Read models slowly diverge from source truth. Nobody notices until quarter close, customer complaints, or an audit.

Translation bottlenecks

A semantic translation service becomes a hidden monolith if it accumulates too many bounded contexts. The cure for this is not to remove translation. It is to align translation ownership with domains.

When Not To Use

CDC is not a universal answer.

Do not lead with CDC when:

  • you control the source application and can publish proper domain events from the transaction boundary
  • the business process requires strong synchronous consistency across participants
  • the source data model is unstable and poorly governed
  • the semantics of change cannot be inferred safely from persistence updates
  • downstream consumers need only a simple API, not a streaming integration model
  • data sensitivity makes broad replication unacceptable

Likewise, do not call something event-driven just because Kafka is present. If all roads lead back to database row replication and there is no meaningful event contract, be honest and design for CDC. The label matters less than the consequences, but misleading labels encourage bad decisions.

If you are building a greenfield domain service with strong aggregate boundaries, transactional outbox plus domain event publication is usually cleaner than CDC. You own the semantics there. Use them.

Several patterns sit close to this architecture.

Transactional Outbox

For systems you do control, the outbox pattern is often preferable to raw CDC on business tables. The application writes domain or integration events into an outbox within the same transaction as state change, then publishes them reliably. Better semantics. Less inference. More intentional design.

Event Sourcing

Event sourcing is not the same as CDC. Event sourcing stores business events as the system of record. CDC observes storage mutations after the fact. They solve different problems and should not be collapsed into one another.

CQRS

CDC often feeds CQRS-style read models. That can work very well. But remember: a read model built from raw changes inherits the semantic quality of those changes.

Strangler Fig Pattern

This is the migration frame around the whole story. CDC creates a seam through which new capabilities can emerge while the old core still runs the business.

Data Mesh and Data Products

Raw CDC streams can act as foundational data products, but they are often too technical for broad analytical or operational consumption. Curated semantic streams usually make better products.

Summary

Many enterprises say they are doing event-driven architecture when what they are really doing is CDC-based change propagation. That is not a failure. It is often the most practical path available.

The trouble starts when technical change records are mistaken for business events. Then semantics leak, coupling spreads, and every downstream team becomes an amateur archaeologist of someone else’s schema.

The better approach is deliberate and a bit more humble:

  • use CDC to move change quickly and reliably
  • use Kafka to provide scalable transport and replay
  • use translation layers to recover domain semantics where they matter
  • use DDD to define bounded-context contracts instead of enterprise-wide fantasy events
  • use strangler migration to modernize progressively
  • use reconciliation to keep eventual consistency honest

In short: architect the thing you actually have.

If your system is really CDC, say so. Then make it excellent at being CDC. Put semantics in the right place. Accept the tradeoffs. Design for failure. Reconcile relentlessly. And only call it event-driven when the business meaning survives the trip.

Frequently Asked Questions

What is enterprise architecture?

Enterprise architecture aligns strategy, business processes, applications, and technology in a coherent model. It enables impact analysis, portfolio rationalisation, governance, and transformation planning across the organisation.

How does ArchiMate support architecture practice?

ArchiMate provides a standard language connecting strategy, business operations, applications, and technology. It enables traceability from strategic goals through capabilities and services to infrastructure — making architecture decisions explicit and reviewable.

What tools support enterprise architecture modeling?

The main tools are Sparx Enterprise Architect (ArchiMate, UML, BPMN, SysML), Archi (free, ArchiMate-only), and BiZZdesign. Sparx EA is the most feature-rich, supporting concurrent repositories, automation, scripting, and Jira integration.