docs(sms): reconcile Component/CLAUDE/README docs for SMS notifications (S11)

This commit is contained in:
Joseph Doherty
2026-06-19 11:21:56 -04:00
parent 9558d98343
commit c5c8511379
4 changed files with 64 additions and 25 deletions
@@ -65,12 +65,12 @@ The site forwards only `(listName, subject, body)` plus provenance — recipient
## The `Notifications` Table
The table is type-agnostic so it can record any notification type the system supports — email today, Microsoft Teams and others later. One row per notification.
The table is type-agnostic so it can record any notification type the system supports — `Email` and `Sms` today; others can be added by registering a new `INotificationDeliveryAdapter`. One row per notification.
| Field | Notes |
|---|---|
| `NotificationId` | GUID, primary key. Generated at the **site**; used as the idempotency key. |
| `Type` | `Email` / `Teams` / … discriminator. |
| `Type` | `Email` / `Sms` / … discriminator. Stamped at ingest from the target list's `Type` (default `Email` if the list is not found — delivery parks on "list not found" regardless). |
| `ListName` | Target notification list. |
| `Subject`, `Body` | Plain-text content. |
| `TypeData` | JSON — extensibility hook for future per-type fields. |
@@ -99,7 +99,7 @@ The Notification Outbox and the central [`Site Call Audit`](Component-SiteCallAu
### Retry Policy
Delivery retry reuses the central SMTP configuration's max-retry-count and fixed retry interval. The interval is fixed (no exponential backoff), consistent with the existing fixed-interval store-and-forward convention.
Delivery retry reuses the central SMTP configuration's max-retry-count and fixed retry interval for Email notifications. SMS notifications reuse the `SmsConfiguration`'s retry settings. The interval is fixed (no exponential backoff), consistent with the existing fixed-interval store-and-forward convention.
### Retention
@@ -133,10 +133,12 @@ The operational `Notifications` table remains the **source of truth** for the di
A delivery adapter implementing `INotificationDeliveryAdapter` is registered per `Type`. Each `Deliver(...)` call returns one of `success | transient failure | permanent failure`, mirroring the External System Gateway error-classification pattern.
- **Email adapter — implemented now.** The existing SMTP composition/send logic, relocated to the central cluster.
- **Teams and other adapters — future.** The `Type` discriminator and the adapter interface are the seam; no Teams code exists in this design. Teams auth and targeting (Incoming Webhooks vs Graph API) is a separate design conversation.
- **Email adapter.** The existing SMTP composition/send logic, relocated to the central cluster. Sends a single BCC email to all list recipients.
- **SMS adapter (Twilio REST).** Added in T9/T10 (2026-06-19). Sends one Twilio REST request per recipient phone number. Per-recipient results are rolled up: all-accepted → `Success`; any-transient → retry/park; mix of accepted + permanent-bad → `Success` with bad numbers noted in `LastError`; all-permanent → `Permanent` (Park). See [Component-NotificationService.md](Component-NotificationService.md), SMS Delivery Adapter.
Delivery adapters are provided by the Notification Service, which manages notification-list and SMTP definitions and supplies the stateless per-type "deliver one notification" implementations.
The outbox dispatches by looking up the adapter registered for the notification's `Type`. If no adapter is registered for a given `Type`, the notification is parked with a "no adapter" error — the seam is open for future delivery channels.
Delivery adapters are provided by the Notification Service, which manages notification-list, SMTP, and SMS definitions and supplies the stateless per-type "deliver one notification" implementations. The SMS `SmsConfiguration` (including encrypted Auth Token) travels in Transport bundles alongside SMTP config.
## Active/Standby Behavior
@@ -177,7 +179,7 @@ Delivery max-retry-count and retry interval are not part of `NotificationOutboxO
## Dependencies
- **Notification Service**: Provides notification-list and SMTP definitions, and the per-type delivery adapters the outbox invokes.
- **Notification Service**: Provides notification-list, SMTP, and SMS definitions, and the per-type delivery adapters the outbox invokes (Email + Twilio SMS).
- **Configuration Database**: Hosts the `Notifications` table; provides the entity POCO, repository, and EF migration for outbox persistence.
- **CentralSite Communication**: Carries inbound notification submissions and acks between sites and central.
- **Audit Log (#23)**: The dispatcher direct-writes `Notification.Attempt` and `Notification.Terminal` rows to the central `AuditLog` via `ICentralAuditWriter` (insert-if-not-exists on `EventId`); the site-emitted `Notification.Enqueued` row arrives via the standard audit telemetry channel. See [Component-AuditLog.md](Component-AuditLog.md), Central direct-write (central-originated events).
@@ -187,7 +189,7 @@ Delivery max-retry-count and retry interval are not part of `NotificationOutboxO
## Interactions
- **Site Store-and-Forward Engine**: Forwards notifications to central via CentralSite Communication; the outbox ingests them and acks once persisted.
- **Notification Service**: Supplies delivery adapters and resolves notification lists at delivery time.
- **Notification Service**: Supplies delivery adapters (Email + SMS) and resolves notification lists at delivery time.
- **Central UI**: Queries the `Notifications` table for the Notification Outbox page and issues operator Retry/Discard actions on parked notifications.
- **Health Monitoring**: Polls the outbox for KPI tiles on the health dashboard.
- **KPI History (#26)**: Emits `IKpiSampleSource` (`NotificationOutboxKpiSampleSource`, Global + per-Site + per-Node) consumed by the KpiHistory recorder (#26), reusing the existing `Compute…KpisAsync` reads; the resulting `queueDepth` / `stuckCount` / `parkedCount` / `deliveredLastInterval` / `oldestPendingAgeSeconds` series render as trends on the Notification Outbox page via `KpiTrendChart`. See [Component-KpiHistory.md](Component-KpiHistory.md).