# Notifications — 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](./notifications-routing.md), 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.
