Channels

/jabali-admin/notifications/channels. Configure the delivery endpoints that notification events fan out to (M14).

Available channels

Channel Configuration
In-app Always on. Renders as a bell-dropdown indicator in the panel header.
Email SMTP submission via the panel’s own Stalwart instance; uses mail-recovery-sender@<panel-hostname> as From by default.
Slack Incoming-webhook URL.
Telegram Bot token plus chat ID.
ntfy.sh Topic URL (works against the public ntfy.sh or a self-hosted ntfy server).
Web Push VAPID public/private keys; users subscribe per browser via the bell dropdown.

Per-channel test

Each row has a Send test button that emits a synthetic event through the channel. Receiving a test confirms the credentials and connectivity end-to-end.

Enabling and disabling

A channel may be globally enabled or disabled. A disabled channel skips dispatch even if a routing rule targets it; the queue depth does not grow because skipped channels are dropped at producer time.

Per-user opt-in

Tenants opt-in to receive certain notifications about their own account (cron failures, backup results, mail quarantine) via Profile → Notifications. The channel must be enabled here at the server level before any tenant may opt-in to it.

Web Push keys

VAPID keys are auto-generated by the installer. Rotating the keys (button on the Web Push row) invalidates every active subscription; users must re-subscribe from the bell dropdown.

Architecture

Producers emit a row into Redis Streams jabali:notifications. The in-process dispatcher (single consumer per panel instance) reads the stream, consults Routing, and calls each enabled sender. Each sender is a Go file under panel-api/internal/notifications/senders/.

ADR-0056 covers the data model; ADRs 0057–0059 cover the sender interface, Web Push, and the bell dropdown.