Notification & CRM Service
Announcements, in-app inbox and a call-centre CRM back end
Background
Call-centre staff work through lists of customers sorted by when they were last contacted. Aggregating call history for every list view does not scale, and the customer data itself lives in the identity service.
Architecture
Back office → gateway (outreach API + provider client) → outreach gRPC service → MySQL. Identity-service events (registered, phone changed, status changed) → Kafka consumer → transactional update of the latest-contact row. Announcements: publish → Kafka → WebSocket service → connected clients.
Key Highlights
Rebuilt announcements and inbox: multi-language content, group targeting, per-user read state and unread counts, real-time delivery through Kafka and WebSocket
Customer-outreach back end from scratch: 15 gRPC endpoints over 8 tables (seats, call and SMS records, settings)
23 admin endpoints and a signed REST client for a cloud contact-centre and SMS provider, with automatic seat-group provisioning
A "latest contact per customer" read model kept in sync from Kafka user events, with retry and dead-letter topics and transactional writes
Online backfill of the read model: temporary index → INSERT … SELECT … ON DUPLICATE KEY UPDATE → drop index
Key Implementations
Event-driven read model
One row per customer with their latest call and SMS, created on registration and reset when the phone number or status changes, updated in the same transaction as each call record.
Why: List screens read one row per customer instead of aggregating history, and the data follows the identity service without synchronous calls.
Provider integration
A generic signed REST client for the provider, provider error codes mapped to localised platform errors, and seat groups created automatically when the current one is full.
Why: Staff shouldn't see raw vendor errors, and onboarding new staff shouldn't need manual provider setup.
Technical Decisions
| Technical Decisions | Chosen | Alternative | Reason |
|---|---|---|---|
| Latest-contact lists | Denormalised read model maintained from events | Aggregate call history at query time | Reads are far more frequent than calls, and the list needs filters that span identity data. |
Related
Segmentation & Loyalty Service
Customer segmentation, loyalty-tier cashback and partner rebate configuration
Configuration & Access-Control Service
Tenant configuration, domain management and a priority-based allow/deny engine
Audit Log Service
A platform-wide audit trail published from 12 microservices