Segmentation & Loyalty Service
Customer segmentation, loyalty-tier cashback and partner rebate configuration
Background
Each tenant wants to treat customers differently based on behaviour, for example by deposit volume, and to configure that itself. Segments have to be assigned the moment a user registers, re-evaluated regularly over every tenant and currency, and changed by hand with an audit trail.
Architecture
Admin API (gateway) → segmentation gRPC service → MySQL (config, assignment, history, strategy tables). Registration events from the identity service → Kafka consumer → default assignment. A daily Temporal workflow in the scheduled-jobs service → per-tenant/currency child workflows → classification results published to Kafka → applied by a consumer with retry and dead-letter topics.
Key Highlights
Customer segmentation from scratch: 9 tables, 28 gRPC and 16 HTTP endpoints, transactional config with an exclusive default, change history with snapshots
New users get their default segment from Kafka registration events; rule-based auto-classification on rolling-deposit thresholds
A daily Temporal workflow reclassifies every tenant and currency with per-tenant child workflows and heartbeated, paginated activities
Partner rebate configuration for unlimited-depth networks: per-level rates, Redis cache-aside with pipelined invalidation, and Kafka-driven defaults when products are enabled
Idempotent cashback-record consumer: deterministic key enforced by a unique index
Key Implementations
Default assignment from events
A Kafka consumer subscribes to user-registration and user-creation events and assigns the tenant's default segment, with retry and dead-letter topics.
Why: Assignment must not depend on the registration request succeeding at a second write; event-driven assignment keeps identity and segmentation decoupled.
Resumable reclassification
A daily workflow lists tenants and starts a child workflow per tenant and currency. Each child loads upgrade maps and downgrade strategies, pages through users with activity heartbeats, and publishes results.
Why: Re-evaluating every user is a long-running job; heartbeats and pagination let Temporal retry or resume a child without redoing the whole run.
Partner rebate configuration
Per-level rate rules for unlimited-depth partner networks, cached in Redis and invalidated tenant-wide; a lookup resolves the rates for a user's whole partner chain in parallel.
Why: Settlement jobs need the full chain for every user; caching and parallel lookups keep that cheap.
Technical Decisions
| Technical Decisions | Chosen | Alternative | Reason |
|---|---|---|---|
| Where classification runs | A Temporal workflow that publishes results to Kafka | Classify inside the segmentation service on a cron | Long, per-tenant runs need retries, visibility and resumability; publishing results keeps the write path in one consumer. |