DLR Processor — Sync Contract
Status: populated
Owner: Platform Engineering
Last updated: 2026-04-18
Companion: API_CONTRACTS · EVENT_SCHEMAS
1. Purpose
This document defines the synchronisation contracts between the DLR Processor and each of its dependencies, covering ownership, schema stability guarantees, and backward compatibility commitments.
2. Upstream Dependencies
smpp-connector → sms.dlr.inbound
| Aspect | Detail |
|---|
| Owner | smpp-connector team |
| Schema version | 1.0 |
| Stability | Additive changes allowed without notice; breaking changes require 30-day notice + parallel stream |
| Required fields | eventId, operatorMessageId, operatorId, stat, deliveredAt |
| DLR Processor commitment | Ignores unknown fields (tolerant reader); logs schema version mismatches |
orch.sms_messages (PostgreSQL)
| Aspect | Detail |
|---|
| Owner | sms-orchestrator team |
| Contract | Column operator_message_id indexed and populated before SENT state |
| Breaking changes | Column renames or removal require coordinated migration with dlr-processor |
| Write scope | dlr-processor writes ONLY: status, dlr_status, dlr_received_at, processed_at |
3. Downstream Dependencies
billing-service ← billing.events
| Aspect | Detail |
|---|
| Owner | dlr-processor (publisher) |
| Consumer | billing-service |
| Guarantee | At-least-once delivery via outbox + NATS |
| Idempotency key | eventId (UUID) — billing-service must dedup on this |
| Breaking changes | 30-day parallel publish on new schema version before retiring old |
webhook-dispatcher ← webhook.dispatch
| Aspect | Detail |
|---|
| Owner | dlr-processor (publisher) |
| Consumer | webhook-dispatcher |
| Guarantee | At-least-once delivery |
| Idempotency key | eventId |
| Breaking changes | Same policy as billing.events |
reconciliation-job ← sms.dlr.unmatched
| Aspect | Detail |
|---|
| Owner | dlr-processor (publisher) |
| Consumer | reconciliation-job (async batch) |
| Guarantee | Best-effort; reconciliation-job must also poll dlr.orphaned_receipts table directly |
4. Schema Change Protocol
- Non-breaking (additive) change: deploy producer, then consumers; no coordination required.
- Breaking change:
a. Create new stream/subject version (
sms.dlr.inbound.v2).
b. Publish to both v1 and v2 for 30 days.
c. Consumers migrate to v2.
d. Retire v1.
- Emergency breaking change: coordinate with all teams; minimum 48-hour notice; rollback plan required.