From a4ba2dfe01e472f200fe95b735ddfff91225535f Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Mon, 18 May 2026 23:07:17 -0400 Subject: [PATCH] docs(notification-outbox): fix naming consistency and status-lifecycle clarity --- docs/requirements/Component-NotificationOutbox.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/requirements/Component-NotificationOutbox.md b/docs/requirements/Component-NotificationOutbox.md index 98913c5..bd26149 100644 --- a/docs/requirements/Component-NotificationOutbox.md +++ b/docs/requirements/Component-NotificationOutbox.md @@ -29,7 +29,7 @@ Site script: Notify.To("list").Send(subject, body) │ generate NotificationId (GUID) locally; return it to the script immediately ▼ Site Store-and-Forward Engine (notification category, target = central) - │ durably forwards to central via the Communication Layer (ClusterClient); + │ durably forwards to central via Central–Site Communication (ClusterClient); │ buffers/retries if central is unreachable ▼ Central ingest: insert-if-not-exists on NotificationId → Notifications table (Pending) @@ -58,7 +58,7 @@ The table is type-agnostic so it can record any notification type the system sup | `ListName` | Target notification list. | | `Subject`, `Body` | Plain-text content. | | `TypeData` | JSON — extensibility hook for future per-type fields. | -| `Status` | `Pending` → `Retrying` → `Delivered` / `Parked` / `Discarded`. | +| `Status` | Lifecycle state — one of `Pending`, `Retrying`, `Delivered`, `Parked`, `Discarded`. See Status Lifecycle below. | | `RetryCount` | Delivery attempts so far. | | `LastError` | Detail of the most recent failure. | | `ResolvedTargets` | Who the notification actually went to — snapshotted by central at delivery time, for audit. | @@ -84,11 +84,11 @@ Delivery retry reuses the central SMTP configuration's max-retry-count and fixed ### Retention -Terminal rows (`Delivered`, `Parked`, `Discarded`) are removed by a **daily purge job** after a configurable window (default ~1 year). This preserves a strong audit trail while bounding table growth. Non-terminal rows are never purged. +Terminal rows (`Delivered`, `Parked`, `Discarded`) are removed by a **daily purge job** after a configurable window (default 365 days). This preserves a strong audit trail while bounding table growth. Non-terminal rows are never purged. ## Ingest & Idempotency -The site→central handoff is **at-least-once**. Central ingests an inbound notification submission with an **insert-if-not-exists** on `NotificationId`, then acks the site; the site S&F engine clears the message only on that ack. Because central acks only after the row is persisted (ack-after-persist), a lost ack causes the site to resend, and the GUID `NotificationId` idempotency key makes the resend harmless — the duplicate insert is a no-op. +The site→central handoff is **at-least-once**. Central ingests an inbound notification submission with an insert-if-not-exists on `NotificationId`, then acks the site; the site S&F engine clears the message only on that ack. Because central acks only after the row is persisted (ack-after-persist), a lost ack causes the site to resend, and the GUID `NotificationId` idempotency key makes the resend harmless — the duplicate insert is a no-op. A rare central failover mid-delivery could re-send one already-`Delivered` notification. This is an accepted trade-off, consistent with the duplicate-delivery trade-off the Store-and-Forward Engine already accepts. @@ -129,7 +129,7 @@ KPIs are central-computed from the `Notifications` table — global, with a per- - **Delivered (last interval)** — count of `Delivered` since the previous sample. - **Oldest pending age** — age of the oldest non-terminal notification. -KPIs are point-in-time, computed on demand from the table. The ~1-year row retention answers historical questions directly, so no separate time-series store is added. +KPIs are point-in-time, computed on demand from the table. The configurable row retention (default 365 days) answers historical questions directly, so no separate time-series store is added. ### Stuck Detection @@ -146,7 +146,7 @@ The component is configured via `NotificationOutboxOptions`, bound from an `apps - **Dispatch interval** — how often the dispatcher loop polls for due rows. - **Stuck-age threshold** — age beyond which a non-terminal notification is counted as stuck (default 10 minutes). -- **Terminal-row retention window** — age after which terminal rows are removed by the daily purge job (default ~1 year). +- **Terminal-row retention window** — age after which terminal rows are removed by the daily purge job (default 365 days). Delivery max-retry-count and retry interval are not part of `NotificationOutboxOptions` — they are reused from the central SMTP configuration. @@ -160,7 +160,7 @@ Delivery max-retry-count and retry interval are not part of `NotificationOutboxO ## Interactions -- **Site Store-and-Forward Engine**: Forwards notifications to central via the Communication Layer; the outbox ingests them and acks once persisted. +- **Site Store-and-Forward Engine**: Forwards notifications to central via Central–Site Communication; the outbox ingests them and acks once persisted. - **Notification Service**: Supplies delivery adapters 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.