Notify Runbook

Last updated: 2026-09-08 (NTF-10 — the Notifier predecessor retired; this runbook now targets the consolidated hosts). The filename is unchanged so existing operator bookmarks resolve.

Purpose

Operational steps to deploy, monitor, and recover the Notify service — the Notifications Studio. It owns the PostgreSQL stellaops_notify database and the Valkey/Redis (or NATS JetStream) notification queue.

Audience: operators and on-call engineers who deploy, monitor, and troubleshoot Notify in a Stella Ops deployment.

Predecessor retired. notifier-web merged into notify-web in 2026-04 and was commented out of compose from then on; the notifier-worker deployable was retired on 2026-09-04 after a constructed forcing function proved notify-worker delivering, and the whole src/Notifier/ tree was frozen at src/__Obsoleted/Notifier/ on 2026-09-08 (SPRINT_20260722_015 NTF-10). stellaops/notifier-web and stellaops/notifier-worker are no longer built; notifier.stella-ops.local survives only as a DNS alias on the notify-web container. (The legacy split-container monolith compose was deleted 2026-09-01, SPRINT_20260824_010 P8-12.)

Pre-flight

Deploy

  1. Apply the supported Compose or Offline Kit profile with image digests pinned. The images are stellaops/notify-web and stellaops/notify-worker. Both are declared in devops/docker/services-matrix.env and devops/docker/build-service-publish.sh under slot 29; slot 28 carries only a do-not-re-enable note for the retired predecessor.
  2. Set config (__ maps to config section nesting; neither host applies an env-var prefix):
    • STELLAOPS_POSTGRES_NOTIFY_CONNECTION — the family’s own database. Both hosts resolve this variable and only this one, and fail closed without it (CoC §8.2).
    • Queue transport and connection under the Notify__Queue__* section.
    • Authority/Router auth wiring via the standard Router / Authority sections.
    • ASPNETCORE_URLS for the listener (default container port 8080).
  3. Verify liveness/readiness: WebService GET /healthz returns 200 Healthy (ASP.NET health-check format, not a JSON ready flag). For the companion notify-web host, GET /readyz returns 503 with missing base connector names when the InApp/InAppInbox base plug-ins are absent or mounted at the wrong notify:plugins:directory. The Worker exposes its own worker health endpoints via MapWorkerHealthEndpoints (includes the queue health check).

NOT IMPLEMENTED: there is no warm-cache admin endpoint (POST .../admin/warm); rules and templates are loaded lazily/per-request and from durable storage.

Monitor

The delivery host emits OpenTelemetry instruments via the StellaOps.Notifier meter — the METER name is unchanged by the host retirement, because renaming it would break every existing dashboard and alert rule. Instrument names (dot-notation as emitted; a Prometheus exporter renders these with _/_total suffix conventions):

SLO alerting rules ship in docs/notifications/operations/alerts/notify-slo-alerts.yaml and reference the exporter metric names notify_delivery_success_total, notify_delivery_total, notify_backlog_depth, and notify_delivery_duration_seconds_bucket. CAVEAT: those alert-rule names do NOT map 1:1 onto the instruments the worker actually emits — the code emits notify.delivery.attempts (tagged by status, not a separate success counter), notify.delivery.duration, and notify.queue.depth (per-channel gauge), with no instrument literally named notify.delivery.success, notify.delivery (total), or notify.backlog.depth. Wiring the alerts to live data therefore requires recording rules / relabeling that derive the alert-rule series from the emitted instruments; the shipped rules are not satisfiable directly against the raw exporter output.

Common operations

All management routes are under /api/v2/notify (v1 routes are deprecated and emit Deprecation/Sunset headers, sunset 2026-03-31). Tenant scoping is via the validated stellaops:tenant claim; gateway-forwarded tenant headers are envelope context, not the Notify data-isolation source.

NOT IMPLEMENTED as described in earlier drafts: there is no :replay delivery verb (use /retry), no channels/{id}:refresh-secret (use security/webhook/{id}/rotate), and no per-tenant pause admin flag in the WebService surface.

Failure recovery

Auditing

Determinism safeguards

On-call checklist