Notifications Digests

Imposed rule: Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.

Digests coalesce multiple matching events into a single notification when rules request batched delivery. They protect responders from alert storms while preserving a deterministic record of every input.

Scheduled digest cadence is currently configured on the worker through Notifier:DigestSchedule. Notify does not expose a live API for creating or editing digest schedules; the /digests routes below operate on open digest windows that already exist because rules and worker configuration caused them to be created. The Web console must therefore surface digest schedule CRUD as unavailable and must not emulate /api/v1/notify/digest-schedules with synthetic runtime data.


1. Digest lifecycle

  1. Window selection. Rule actions opt into a digest cadence by setting actions[].digest (instant, 5m, 15m, 1h, 1d). instant skips digest logic entirely.
  2. Aggregation. When an event matches, the worker appends it to the open digest window (tenantId + actionId + window). Events include the canonical scope, delta counts, and references.
  3. Flush. When the window expires or hits the worker’s safety cap (configurable), the worker renders a digest template and emits a single delivery with status Digested.
  4. Audit. The delivery ledger links back to the digest document so operators can inspect individual items and the aggregated summary.

2. Storage model

Digest state lives in PostgreSQL (notify.digests table) and mirrors the schema described in modules/notify/architecture.md:

{
  "id": "tenant-dev:act-email-compliance:1h",
  "tenantId": "tenant-dev",
  "actionKey": "act-email-compliance",
  "window": "1h",
  "openedAt": "2025-10-24T08:00:00Z",
  "status": "open",
  "items": [
    {
      "eventId": "00000000-0000-0000-0000-000000000001",
      "scope": {
        "namespace": "prod-payments",
        "repo": "ghcr.io/acme/api",
        "digest": "sha256:…"
      },
      "delta": {
        "newCritical": 1,
        "kev": 1
      }
    }
  ]
}

3. Rendering and templates


4. API surface

EndpointDescriptionNotes
POST /digestsIssues administrative commands (e.g., force flush, reopen) for a specific action/window.Request body specifies the command target; requires notify.admin.
GET /digests/{actionKey}Returns the currently open window (if any) for the referenced action.Supports operators/CLI inspecting pending digests; requires notify.viewer.
DELETE /digests/{actionKey}Drops the open window without notifying (emergency stop).Emits an audit record; use sparingly.

All routes honour the tenant header and reuse the standard Notify rate limits.

There is intentionally no POST /digest-schedules or equivalent schedule CRUD endpoint in the live API today. If product requirements later need operator-managed schedules, that work must introduce a persisted contract, docs, and startup/runtime wiring explicitly.


5. Worker behaviour and safety nets


6. Operator guidance


Imposed rule reminder: Work of this type or tasks of this type on this component must also be applied everywhere else it should be applied.