Building CRM Systems with Event-Driven Architecture
A practical guide to implementing customer relationship management using event sourcing, CQRS, and event-driven patterns for marketing automation and consent management
Abstract
Traditional CRM systems store customer state directly: a record per customer, mutated in place with each interaction. That model breaks when the product needs real-time personalization, GDPR-compliant audit trails, and multi-channel orchestration at the same time, because the current-state row has no memory of how it got there. Event-driven CRM inverts the model: every interaction is captured as an immutable event, and any view (profile, consent ledger, channel history) is a projection over that event stream. This post covers the architecture of an event-driven CRM on AWS, the projections for personalization and consent, the cross-channel orchestration layer, and the trade-offs (storage cost, eventual-consistency budgets, replay windows) that the pattern introduces.
The Event-Driven CRM Landscape
Most CRM systems start simple: a database with customers, contacts, and interactions. This works until you need to answer questions like "What marketing emails has this customer received?" or "When did they consent to SMS?" or "Why did we send them this notification?"
I've worked with teams migrating from traditional CRM architectures to event-driven systems, and the shift requires rethinking how you model customer data. Instead of updating a customer record when preferences change, you emit a CustomerPreferencesUpdated event. Instead of deleting consent records for GDPR, you emit a ConsentRevoked event.
The fundamental difference: your database becomes a projection of events, not the source of truth.
Why Event-Driven Architecture for CRM?
The CRM domain has specific characteristics that make event-driven architecture particularly valuable:
- Audit Requirements: GDPR mandates knowing exactly when consent was granted and for what purpose
- Multi-Channel Complexity: Customers interact across email, SMS, push, in-app, and each channel has different rules
- Real-Time Personalization: Marketing automation needs to react immediately to customer behavior
- Data Privacy: The "right to be forgotten" is easier when you can replay events with redaction
- Eventual Consistency: Marketing campaigns can tolerate slight delays if it means better scalability
Here's a realistic scenario: A customer browses your product page, abandons their cart, opts into SMS notifications, then completes purchase via email link. In a traditional CRM, you'd update the customer record multiple times, losing the sequence of events. In an event-driven system, you have the complete story.
System Architecture Overview
Let me show you how the core components fit together:
This architecture separates concerns effectively:
- Write path: Commands validate business rules and emit events
- Read path: Projections materialize views optimized for queries
- Services: React to events and orchestrate workflows
- Channels: Handle delivery with retry logic and failure tracking
Practical Implementation Guide
Before diving deep into components, let me show you how to get started with a real implementation.
Step-by-Step Getting Started
Step 1: Define Your Core Events
Start simple. Don't try to model everything at once:
Step 2: Set Up Event Store
Use what you have. DynamoDB works well for AWS shops, EventStoreDB for event sourcing purists:
Step 3: Create Command Handlers
Business logic lives here:
Step 4: Build Projections
Start with one read model - the customer view:
Step 5: Add Campaign Triggers
Start with one simple campaign - welcome email:
Step 6: Integrate Channels
Use existing providers. Don't build email infrastructure:
Complete End-to-End Example
Here's a full customer journey from signup to purchase confirmation:
Complete code for this flow:
This example shows every event, every projection update, and every campaign trigger. Start here, then expand to more complex workflows.
Customer Lifecycle Event Flow
Here's the complete picture of customer events over time:
Component Deep Dive
Event Sourcing for Customer Data
The core pattern: instead of storing current state, you store the sequence of events that led to that state. Here's a practical implementation:
The event store becomes your single source of truth:
Key gotcha: Event versioning becomes critical. When your event schema evolves, you need upcasters:
CQRS: Separating Reads and Writes
CQRS (Command Query Responsibility Segregation) means your write model and read model are completely different. In CRM context, this is powerful because marketing queries need different data structures than consent validation.
Write Model - Optimized for business rules:
Read Model - Optimized for queries:
The trade-off: eventual consistency. When a customer revokes consent, there's a delay before the read model updates. For CRM, this is usually acceptable - if a customer unsubscribes, a few seconds delay before campaigns stop is reasonable.
Complete CRUD Operations
Understanding how basic operations translate to events is fundamental. Let me walk through the complete lifecycle of customer data management.
Customer Creation Flow
When a new customer signs up, you're not just inserting a row - you're starting an event stream:
Projection building from these events:
Key gotcha: Registration flow needs to handle failures gracefully. If consent event fails to write but customer creation succeeds, you have an inconsistent state. Use event batching or saga patterns for atomic multi-event operations.
Customer Update Operations
Updates are where event sourcing shines - you have complete history of what changed and when:
Projection updates handle incremental changes:
Customer Deletion and Deactivation
This is where event sourcing differs significantly from traditional systems:
Impact on active campaigns:
Key difference: Deactivation is reversible and retains data for analytics. GDPR deletion is permanent and requires careful handling of related data across all systems.
Marketing Automation with Event Triggers
Marketing automation becomes a series of event processors watching for trigger conditions:
Real-world example: Abandoned cart campaign
Critical gotcha: Idempotency. Events might be processed multiple times due to retries. Every action needs an idempotency key:
Channel Orchestration and Preference Management
Different customers want different channels at different times. Event-driven architecture makes preference management straightforward:
Here's the event flow for preference updates:
GDPR Compliance Through Events
The "right to be forgotten" is actually easier with event sourcing:
Important consideration: Decide early whether you need true deletion or anonymization. For analytics and business intelligence, anonymized events are valuable. For compliance, document your approach clearly.
Purchase Flow & E-commerce Events
E-commerce integration is where event-driven CRM shows its real power. Every step from browsing to delivery generates events that drive marketing automation.
Order Event Chain
A complete purchase generates a rich event stream:
Order aggregate reconstruction from events:
Payment Event Handling
Payment failures need special attention in event-driven systems:
Refund handling:
Post-Purchase Marketing Automation
The order lifecycle drives sophisticated marketing campaigns:
Purchase-Based Customer Segmentation
Events enable sophisticated customer segmentation:
Customer Journey & Funnel Tracking
Tracking customer journeys across touchpoints reveals optimization opportunities and drives personalization.
Journey Event Definitions
Comprehensive journey tracking requires fine-grained events:
Building Funnels from Events
Funnel analysis reconstructed from event streams:
Multi-Touch Attribution
Understanding which touchpoints drive conversions:
Real-Time Funnel Progression Campaigns
Trigger campaigns based on funnel position:
This comprehensive journey tracking and funnel analysis enables precise, data-driven marketing decisions. By reconstructing customer paths from events, you can identify exactly where customers struggle and intervene with targeted campaigns.
Integration Patterns
Connecting with Third-Party Marketing Tools
Most marketing teams use specialized tools like SendGrid, Mailchimp, or HubSpot. Here's how to integrate while maintaining event-driven benefits:
Dead Letter Queues for Failed Communications
Not all messages successfully deliver. Event-driven architecture makes failure handling explicit:
Scaling Considerations and Trade-offs
Performance: Real-Time vs Batch
I've seen teams struggle with the decision: should projections update in real-time or in batches?
Real-time processing:
- Pros: Customer sees changes immediately, marketing campaigns react faster
- Cons: Higher costs, more complex infrastructure, potential thundering herd
- Best for: Consent updates, transactional notifications
Batch processing:
- Pros: Better throughput, easier to optimize, cheaper
- Cons: Eventual consistency delay, stale data in queries
- Best for: Analytics projections, segment calculations, daily email campaigns
Here's a hybrid approach that worked well:
Cost Optimization
Event-driven CRM can get expensive fast if you're not careful. Here's what I've learned:
Event storage costs scale with write volume. Use TTLs aggressively:
Lambda costs for event processors - batch when possible:
Schema Evolution Strategy
Your event schemas will change. Plan for it:
Lessons Learned and Gotchas
After implementing several event-driven CRM systems, here are the patterns that consistently matter:
1. Idempotency is Non-Negotiable
Every external action (email send, API call, database write) must be idempotent. Events will be replayed, processors will retry, and you'll send duplicate emails if you don't handle this.
The pattern I use: store idempotency keys with every action and check before executing.
2. Consent Checks Must Be Fast
If checking consent adds 200ms to every message send, you'll have a bottleneck. Cache consent status aggressively, with TTL of 5-10 minutes. For marketing emails, this delay is acceptable. For transactional emails, you might need shorter TTL or real-time checks.
3. Event Ordering Matters Less Than You Think
Most teams worry about event ordering, but for CRM it's rarely critical. If a customer updates preferences twice in quick succession, the final state is what matters. Use timestamps and version numbers to handle conflicts:
4. Start Simple, Add Complexity When Needed
I've seen teams build complex saga orchestrators for simple "send email after signup" flows. Start with basic event handlers. Add saga patterns only when you have multi-step workflows with compensation logic.
5. Monitoring is Different
Traditional CRM monitoring checks "is the database up?" Event-driven monitoring checks:
- Event processing lag (how far behind are projections?)
- Dead letter queue depth (how many failures?)
- Projection consistency (does aggregate match event replay?)
Closing Thoughts
Event-driven CRM architecture solves real problems: GDPR compliance, multi-channel orchestration, and real-time personalization. But it introduces new complexity: eventual consistency, event schema evolution, and more moving parts.
The pattern works best when you need:
- Complete audit trails for compliance
- Complex, multi-step marketing automation
- Integration with many external systems
- Scalability beyond single-database limits
It's overkill when you have:
- Simple email list management
- Small customer base (< 100k)
- Primarily transactional communications
Start with event sourcing for consent and preferences - this gives you GDPR compliance benefits without full commitment. Add CQRS when your read patterns diverge significantly from write patterns. Build marketing automation on events when you need sophisticated workflows.
The architecture enables powerful CRM capabilities, but like any pattern, it's a tool for specific problems. Use it where it adds value, not because it's interesting.