feat(ui): Benachrichtigungsziele unter "Mein Konto"

Beliebig viele Ziele je Konto, jedes mit eigenen Anlaessen. Jedes laesst sich
einzeln testen und pausieren; Ergebnis und Zeitpunkt der letzten Zustellung
stehen an der Karte.

Der Weg laesst sich nach dem Anlegen nicht mehr aendern - ein Webhook-Ziel zu
einer E-Mail-Adresse umzubiegen ergaebe keinen Sinn und muesste das
Geheimnis mitwandern lassen. Ist kein SMTP hinterlegt, ist die Auswahl
"E-Mail" gesperrt und erklaert, warum.

targetSafeSelect liegt in lib/notify/types statt in der Route: Next laesst in
route.ts nur bestimmte Exporte zu und bricht den Bau bei allem anderen ab.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-26 10:22:50 +02:00
co-authored by Claude Opus 5
parent 3bfed6d9f6
commit f1e4271488
5 changed files with 758 additions and 1 deletions
+27 -1
View File
@@ -1,5 +1,10 @@
import type { Metadata } from "next";
import { AccountManager, type AccountData } from "@/components/account/AccountManager";
import {
NotificationSection,
type NotificationTargetEntry,
} from "@/components/account/NotificationSection";
import { emailAvailable } from "@/lib/notify";
import { requireUserPage } from "@/lib/auth/guard";
import { WEBAUTHN_AVAILABLE } from "@/lib/config";
import { prisma } from "@/lib/db";
@@ -13,7 +18,7 @@ export async function generateMetadata(): Promise<Metadata> {
export default async function AccountPage() {
const user = await requireUserPage();
const [passkeys, sessions] = await Promise.all([
const [passkeys, sessions, targets] = await Promise.all([
prisma.credential.findMany({
where: { userId: user.id },
select: {
@@ -37,6 +42,22 @@ export default async function AccountPage() {
},
orderBy: { lastSeenAt: "desc" },
}),
prisma.notificationTarget.findMany({
where: { userId: user.id },
select: {
id: true,
name: true,
channel: true,
target: true,
secretHint: true,
events: true,
isActive: true,
lastSentAt: true,
lastOk: true,
lastMessage: true,
},
orderBy: { name: "asc" },
}),
]);
const data: AccountData = {
@@ -60,6 +81,11 @@ export default async function AccountPage() {
</header>
<AccountManager data={data} />
<NotificationSection
targets={targets as unknown as NotificationTargetEntry[]}
emailAvailable={emailAvailable()}
/>
</div>
);
}