Skip to main content

routing-engine — Domain Model

Status: populated | Last updated: 2026-04-18

1. Aggregates & Entities

1.1 RoutingRule (Aggregate Root)

Represents a rule that maps a destination prefix + account context to an ordered set of operator candidates and a routing strategy.

AttributeTypeDescription
iduuidPrimary key
accountIduuid | nullScoped to account or global (null)
prefixIduuidFK → destination_prefixes
strategyRoutingStrategyCOST / PRIORITY / FAILOVER
isActivebooleanSoft-enable/disable without deletion
priorityintegerRule evaluation order when multiple rules match
createdAttimestampImmutable audit field
updatedAttimestampAudit field

1.2 RoutingRuleOperator (Entity within RoutingRule)

Junction entity linking a rule to one or more operators with per-operator cost and priority metadata.

AttributeTypeDescription
ruleIduuidFK → routing_rules
operatorIduuidFK → operators
costnumeric(10,6)Cost per message (used by COST strategy)
priorityintegerPriority rank (1 = highest, used by PRIORITY + FAILOVER)

1.3 DestinationPrefix (Entity)

A phone number prefix (E.164) used to match the to field in a routing request.

AttributeTypeDescription
iduuidPrimary key
prefixvarchar(20)E.164 prefix, e.g. +1, +447, +9375
countrychar(2)ISO 3166-1 alpha-2 country code
descriptiontextHuman-readable label

1.4 Operator (Entity — read from ops_routing.operators)

A projection of operator data needed by the routing engine. Full operator management is owned by operator-management-service.

AttributeTypeDescription
iduuidPrimary key (shared with operator-management-service)
namevarchar(100)Display name
hostvarchar(255)SMPP host
portintegerSMPP port
systemIdvarchar(64)SMPP bind credential
tpsLimitintegerMax transactions per second
messageTypestext[]Supported message types (SMS, FLASH, etc.)

2. Value Objects

Value ObjectFieldsDescription
RoutingDecisionoperatorId, host, port, systemId, tpsLimit, strategy, resolvedAtImmutable result of a routing evaluation; cached in Redis
OperatorHealthStateoperatorId, status: HealthStatus, updatedAtCurrent health snapshot; written to Redis from NATS events
PrefixMatchprefix, matchLengthResult of longest-prefix matching against to number

3. Enumerations

enum RoutingStrategy {
COST = 'COST', // select operator with lowest cost
PRIORITY = 'PRIORITY', // select operator with lowest priority number
FAILOVER = 'FAILOVER', // try operators in priority order; pick first healthy
}

enum HealthStatus {
BOUND = 'BOUND', // operator SMPP session is active
UNBOUND = 'UNBOUND', // operator SMPP session is down
FAILBACK = 'FAILBACK', // operator recovering from outage
}

enum MessageType {
SMS = 'SMS',
FLASH = 'FLASH',
WAP = 'WAP',
}

4. Routing Strategy State Machine

┌──────────────────────────────────────────────────────┐
│ SelectOperator called │
└──────────────────┬───────────────────────────────────┘

┌───────────────────────┐
│ Check Redis cache │
└────┬──────────────────┘
HIT ◄─────┘ └────► MISS
│ │
▼ ▼
Return Longest-prefix match
cached (destination_prefixes)
decision │
┌─────▼──────┐
│ Load rules │ (routing_rules + operators)
└─────┬──────┘

┌────────────▼────────────┐
│ Filter: healthy only │ (operator:health Redis)
└────────────┬────────────┘

┌──────────────┼──────────────┐
COST PRIORITY FAILOVER
│ │ │
min(cost) min(priority) first healthy
│ │ in priority order
└──────────────┴──────────────┘

┌──────▼───────┐
│ Write cache │ TTL 300s
└──────┬───────┘

Return OperatorConfig