Data Sync Operations
How the CRM processes events from source services.
Event Architecture
┌───────────────────────────────────────────────────────────────────┐
│ SOURCE SERVICES │
├───────────────┬───────────────────┬───────────────────────────────┤
│ SCL Service │ TeeTime Service │ Messaging Service │
│ DomainOutbox │ DomainOutbox │ EventEmitter │
└───────┬───────┴─────────┬─────────┴───────────────┬───────────────┘
│ │ │
│ member.* │ player.* │ contact.*
│ tier.* │ teetime.* │ message.*
│ payment.* │ handicap.* │ consent.*
└─────────────────┼─────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ REDIS / BULLMQ │
│ Queue: crm-events │
└─────────────────┬───────────────────┘
│
▼
┌─────────────────────────────────────┐
│ CRM WORKER │
│ 1. Parse event │
│ 2. Resolve identity │
│ 3. Update profile │
│ 4. Create activity │
│ 5. Trigger scoring │
│ 6. Update segments │
└─────────────────────────────────────┘
Events Consumed
From SCL
| Event | CRM Action |
|---|---|
member.created | Create/link profile, activity |
member.updated | Update profile, activity |
tier.changed | Update tier, activity, rescore |
payment.received | Update LTV, activity |
payment.failed | Activity, flag for follow-up |
From TeeTime
| Event | CRM Action |
|---|---|
player.created | Create/link profile, activity |
teetime.booked | Activity, update frequency |
teetime.completed | Activity, trigger review journey |
competition.published | Auto-promote (if enabled) |
handicap.updated | Update handicap, activity |
From Messaging
| Event | CRM Action |
|---|---|
message.sent | Activity |
message.delivered | Activity |
email.opened | Activity, engagement score |
link.clicked | Activity, engagement score |
consent.changed | Update opt-in flags |
Monitoring Queue
Check Queue Depth
redis-cli LLEN crm-events
Check Processing Rate
kubectl logs -l app=crm-worker -n crm | grep "processed"
View Failed Events
SELECT id, event_type, error_message, retry_count, created_at
FROM "SyncLog"
WHERE status = 'FAILED'
ORDER BY created_at DESC
LIMIT 20;
Retry Failed Events
-- Retry recent failures
UPDATE "SyncLog"
SET status = 'PENDING', retry_count = 0
WHERE status = 'FAILED'
AND created_at > now() - interval '1 hour';
Idempotency
Events are deduplicated by event ID:
-- Check if event was already processed
SELECT * FROM "SyncLog" WHERE event_id = 'event-uuid-here';
Backpressure
When queue is too deep:
- Scale workers:
kubectl scale deployment/crm-worker --replicas=4 -n crm - Check for stuck events
- Monitor processing rate
Event Envelope
All events follow this format:
interface CrmEvent {
id: string; // Unique event ID
type: string; // e.g., "scl.member.created"
version: string; // Schema version
timestamp: string; // ISO 8601
tenantId: string;
source: string; // Source service
identity: {
authUserId?: string;
email?: string;
phoneNumber?: string;
sclMemberId?: number;
teetimePlayerId?: string;
messagingContactId?: string;
};
payload: Record<string, unknown>;
}