smpp-connector — Data Model
Status: populated | Last updated: 2026-04-18
1. PostgreSQL Schema: smpp
smpp-connector has read-write access to this schema.
1.1 smpp.message_correlations
Maps the MNO-assigned operator_message_id (from submit_sm_resp) back to the internal message_id.
CREATE SCHEMA IF NOT EXISTS smpp;
CREATE TABLE smpp.message_correlations (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
message_id UUID NOT NULL, -- internal message UUID
operator_message_id VARCHAR(64) NOT NULL, -- MNO-assigned ID from submit_sm_resp
operator_id UUID NOT NULL,
destination VARCHAR(20) NOT NULL, -- E.164 destination (for audit)
submitted_at TIMESTAMPTZ NOT NULL DEFAULT now(),
expires_at TIMESTAMPTZ NOT NULL, -- default: submitted_at + 72 hours
dlr_received_at TIMESTAMPTZ, -- NULL until DLR arrives
status VARCHAR(20) NOT NULL DEFAULT 'SUBMITTED',
-- SUBMITTED / DLR_RECEIVED / EXPIRED
CONSTRAINT uq_operator_msg UNIQUE (operator_id, operator_message_id)
);
CREATE INDEX idx_mc_message_id ON smpp.message_correlations (message_id);
CREATE INDEX idx_mc_operator_msg ON smpp.message_correlations (operator_id, operator_message_id);
CREATE INDEX idx_mc_expires_at ON smpp.message_correlations (expires_at)
WHERE status = 'SUBMITTED'; -- partial index for TTL sweep
TTL sweep: A background job runs every 15 minutes:
UPDATE smpp.message_correlations
SET status = 'EXPIRED'
WHERE status = 'SUBMITTED' AND expires_at < now();
2. Redis Key Schemas
2.1 TPS Sliding-Window Counter
Key: tps:{operatorId}:{windowStart}
Type: String (integer)
TTL: 2 seconds (auto-expire stale windows)
where windowStart = Math.floor(Date.now() / 1000) (Unix second)
Example:
tps:550e8400-e29b-41d4-a716-446655440001:1713436800 → "47"
Operations:
INCR tps:{operatorId}:{windowStart}
EXPIRE tps:{operatorId}:{windowStart} 2
If the returned INCR value exceeds tpsLimit, the NATS message is NAKed.
3. In-Memory State (Process-Level)
| Structure | Type | Description |
|---|---|---|
sessionMap | Map<operatorId, SmppSession> | Live session objects; one per assigned operator |
pendingPduMap | Map<sequenceNumber, PendingPdu> | In-flight PDUs awaiting _resp; keyed by SMPP sequence number |
pendingPduMap entries expire after 30 s (configurable) to prevent memory leaks from lost responses.