Skip to main content

DLR Processor — Data Model

Status: populated Owner: Platform Engineering Last updated: 2026-04-18 Companion: DOMAIN_MODEL · APPLICATION_LOGIC

1. Schema Ownership

SchemaOwner serviceAccess mode
dlrdlr-processorRead + Write
orchsms-orchestratorWrite limited to sms_messages columns only

2. dlr.delivery_receipts

CREATE TABLE dlr.delivery_receipts (
receipt_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
message_id UUID NOT NULL REFERENCES orch.sms_messages(message_id),
account_id UUID NOT NULL,
operator_id UUID NOT NULL,
operator_message_id VARCHAR(64) NOT NULL,
raw_stat VARCHAR(32) NOT NULL,
dlr_status VARCHAR(16) NOT NULL, -- DlrStatus enum
delivered_at TIMESTAMPTZ NOT NULL,
error_code VARCHAR(32),
correlated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE UNIQUE INDEX dlr_delivery_receipts_operator_msg_id_idx
ON dlr.delivery_receipts (operator_message_id);

CREATE INDEX dlr_delivery_receipts_message_id_idx
ON dlr.delivery_receipts (message_id);

CREATE INDEX dlr_delivery_receipts_account_id_idx
ON dlr.delivery_receipts (account_id, created_at DESC);

Idempotency Strategy

The unique index on operator_message_id is the dedup key. Inserts use ON CONFLICT (operator_message_id) DO NOTHING — a conflict means the DLR was already processed; the NATS message is ACKed immediately without further side effects.

3. dlr.orphaned_receipts

CREATE TABLE dlr.orphaned_receipts (
orphan_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
operator_message_id VARCHAR(64) NOT NULL,
operator_id UUID NOT NULL,
raw_stat VARCHAR(32) NOT NULL,
raw_payload JSONB NOT NULL,
received_at TIMESTAMPTZ NOT NULL,
resolved_at TIMESTAMPTZ,
resolved_receipt_id UUID REFERENCES dlr.delivery_receipts(receipt_id),
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX dlr_orphaned_receipts_operator_msg_id_idx
ON dlr.orphaned_receipts (operator_message_id);

CREATE INDEX dlr_orphaned_receipts_unresolved_idx
ON dlr.orphaned_receipts (received_at DESC)
WHERE resolved_at IS NULL;

4. orch.sms_messages — Updated Columns Only

dlr-processor performs a targeted UPDATE; it does not own this table.

-- Columns written by dlr-processor only:
UPDATE orch.sms_messages
SET
status = $1, -- 'DELIVERED' | 'FAILED' | 'UNDELIVERED' | 'EXPIRED' | 'REJECTED'
dlr_status = $2, -- mirrors DlrStatus canonical value
dlr_received_at = $3,
processed_at = now()
WHERE message_id = $4
AND status NOT IN ('DELIVERED','FAILED','UNDELIVERED','EXPIRED','REJECTED');
-- Guard: do not overwrite terminal state

5. Flyway Migration Naming

V1__create_dlr_schema.sql
V2__create_delivery_receipts.sql
V3__create_orphaned_receipts.sql
V4__add_dlr_status_check_constraint.sql
V5__add_delivered_at_index.sql

6. Retention Policy

TableRetentionMechanism
dlr.delivery_receipts90 dayspg_partman monthly partition + DROP
dlr.orphaned_receipts30 days (resolved) / indefinite (unresolved)Scheduled job