Skip to main content

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)

StructureTypeDescription
sessionMapMap<operatorId, SmppSession>Live session objects; one per assigned operator
pendingPduMapMap<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.