feat(admin): operator-wide notification health panel

Surface the webhook + email cards on the notifications settings page, and
add an operator-wide delivery-health view the per-self diagnostic could
not give. A single groupBy(channel, result) over the trailing 24h of
push_attempts lets the operator answer "are anyone's pushes failing?"
across all users without DB shell, and a count of auto-disabled channels
(enabled=false with an automated disabledReason) flags a flapping upstream
that silently disabled a channel after five failures. The aggregate is
anonymous — it counts channel x result, never names a user. Admin-only by
construction (cookie auth, never Bearer); the window is clamped 1..168h.
The panel rides the existing admin Reminders section.
This commit is contained in:
Marc-André Bombeck committed 2026-06-15 00:46:21 +02:00
1 parent 909c2aa99e
commit 17dd10c3b9
5 files changed
+380 -3

No files matched your search

@@ -14,6 +14,8 @@ import { NotificationStatusCard } from "@/components/settings/notification-statu
import { NtfyCard } from "@/components/settings/ntfy-card";
import { TelegramCard } from "@/components/settings/telegram-card";
import { WebPushCard } from "@/components/settings/web-push-card";
import { WebhookCard } from "@/components/settings/webhook-card";
import { EmailCard } from "@/components/settings/email-card";
import { apiGet } from "@/lib/api/api-fetch";
interface GlobalServiceAvailability {
@@ -105,6 +107,16 @@ export function NotificationsSection() {
<WebPushCard />
</div>
)}
{/* v1.17.1 — generic outbound webhook (Gotify / Discord / Slack /
Matrix / Home Assistant in one channel). */}
<div id="webhook" className="scroll-mt-28">
<WebhookCard isAuthenticated={isAuthenticated} />
</div>
{/* v1.17.1 — SMTP / email. The card hides itself when the operator
hasn't configured SMTP_* env, so it never shows a dead toggle. */}
<div id="email" className="scroll-mt-28">
<EmailCard isAuthenticated={isAuthenticated} />
</div>
<div id="mood-reminder" className="scroll-mt-28">
<MoodReminderCard isAuthenticated={isAuthenticated} />
</div>