ACK Lifecycle
NotificationDelivery sent to company user
|
|-- [Web dashboard button]
| POST /api/v1/notifications/{id}/ack
| AckIngestionService::ackByUser(notification, user, AckSource::Web)
|
|-- [Inbound transport reply (SMS, email, webhook)]
| POST /api/v1/inbound/sms or /api/v1/inbound/email
| Validate inbound signature → AckIngestionService::ackByTransport(...)
|
v
AckIngestionService (sole ACK writer)
├── notification.ack_status = AckStatus::Acked
├── notification.acked_at = now()
├── notification.ack_source = <triggering stream>
├── notification.escalation_cancelled_at = now()
├── Mark ALL NotificationDeliveries for this notification as acknowledged
├── Dispatch EscalationCancelMessage
└── CommunicationLogger::log(
type: AckReceived,
content: "ACK received via sms_reply — all 3 delivery streams marked acknowledged"
)
Cross-Stream Rule
When any one delivery stream ACKs a notification, all delivery streams for that notification are immediately marked acknowledged. The AckIngestionService logs a single AckReceived event naming the triggering stream and total stream count.
Partial acknowledgement does not exist in this system.
ACK Routing Back to PSAP
After ACK, Cloud routes the confirmation back to the originating PSAPLink PSAP instance:
| Mode | Mechanism |
|---|---|
| poll | PSAPLink PSAP polls GET /api/v1/core/ack-queue/{psapId}?after=<cursor>. Cursor stored in var/ack_poll_cursor.txt. |
| callback | Cloud POSTs to PSAPLink PSAP's POST /api/v1/core/callback/ack (HMAC-signed). Requires PSAP to be reachable. |
ACK Sources
| Source | ack_source value |
|---|---|
| Web dashboard button | web |
| Inbound SMS reply | sms_reply |
| Inbound email reply | email_reply |
| Inbound webhook | webhook |