platform.notifications ist der In-App-Posteingang der Plattform. Tools nutzen ihn, um Ergebnisse zu melden, auf Probleme hinzuweisen und Nutzer:innen per Action-Button direkt an die richtige Stelle zu bringen.
Senden an eine Person
Der Service ist eine Factory (createNotificationsService(db)); Apps halten einen gecachten Handle. Für Standard-Läufe brauchst du ihn nicht: die Fertig- und Fehler-Notification schickt der Runs-Harness automatisch. Selbst senden ist für alles darüber hinaus:
import { createNotificationsService } from "@reosa/sdk";
const notifications = createNotificationsService(db);
const id = await notifications.send(ctx, {
toUserId: ownerId, // optional, Default: ctx.userId
source: "tool", // "platform" | "tool" | "team" | "billing"
category: "tool_results", // optional, sonst aus source abgeleitet (siehe unten)
toolId: "homestaging", // optional, ordnet die Nachricht deinem Tool zu
severity: "success", // "info" | "success" | "warning"
title: "Deine Bilder sind fertig.", // Pflicht, max 200 Zeichen
bodyMd: "3 Varianten liegen im Dateispeicher.", // Markdown-Subset, max 20000
actions: [ // max 4 Buttons
{ label: "Ansehen", href: "/tools/homestaging", variant: "primary" },
],
});
// id: Routing-ID wie "n_<uuid>", oder null, wenn die Person diese Kategorie abgeschaltet hatDie Regeln der Eingabe (notificationSendSchema, Zod-validiert):
title1 bis 200 Zeichen.bodyMdist ein Markdown-Subset (Überschriften, fett/kursiv, Links, Listen, Absätze).actions: maximal 4,labelbis 60 Zeichen,hrefmuss ein Pfad (/...) oder einehttps://-URL sein,variantoptionalprimaryoderghost. Action-Buttons sind das Mittel für Deep-Links in dein Tool.toUserIdmuss ein Mitglied des aktuellen Tenants sein; ohne Angabe geht die Nachricht an die auslösende Person.categoryist die Kategorie, unter der die Person die Nachricht unter Konto, Benachrichtigungen abschalten kann:tool_results,credits_low,team,billing,platformodersecurity. Ohne Angabe folgt sie der Quelle (toolwird zutool_results,team,billingundplatformbleiben).credits_lowundsecurityhaben keine Quelle und werden ausdrücklich genannt. Sicherheitswarnungen lassen sich nicht abschalten.
Die Präferenzen gelten beim Senden: Hat die Empfängerin die Kategorie für In-App abgeschaltet, entsteht keine Zeile, und send liefert null statt einer Routing-ID. Ein Tool muss damit rechnen und darf daraus keinen Fehler machen. Der E-Mail-Kanal ist noch nicht in Betrieb; die E-Mail-Wahl der Person wird gespeichert und gilt, sobald er live ist.
Fan-out an Rollen
Für "alle Admins informieren" gibt es sendToRole; es liefert die Anzahl der tatsächlich zugestellten Nachrichten zurück. Wer die Kategorie abgeschaltet hat, zählt nicht mit:
const count = await notifications.sendToRole(ctx, ["owner", "admin"], {
source: "tool",
toolId: "onoffice-sync",
severity: "warning",
title: "Speicherplatz voll: Foto-Import angehalten",
bodyMd: "Der Import wurde gestoppt, bis wieder Platz frei ist.",
actions: [{ label: "Speicher verwalten", href: "/settings/billing", variant: "primary" }],
});Rollen sind die vier Tenant-Rollen owner, admin, member, viewer.
Lesen und Lese-Status
Für eigene Inbox-Flächen existieren Lese-APIs: list(ctx, { limit, unreadOnly }) liefert den zusammengeführten Posteingang (eigene Notifications + Plattform-Ankündigungen, neueste zuerst), dazu get, unreadCount, markRead(ctx, id) und markAllRead(ctx). Die Routing-IDs unterscheiden die Quellen: n_<uuid> für Notifications, a_<uuid> für Ankündigungen.
PII-Regeln
- Keine Geheimnisse, keine sensiblen Nutzerdaten in
titleoderbodyMd. Die Nachricht liegt in der Datenbank und erscheint in jeder Inbox-Fläche der Empfänger:in. - Verweise statt Inhalte: schreibe "Dein Export liegt bereit" mit Action-Button, nicht den Inhalt des Exports in den Body.
- Fehler-Notifications nennen den Grund PII-frei ("Der Lauf wurde abgebrochen"), nie rohe Fehlertexte mit Nutzereingaben.
Weiterführend
Die automatischen Lauf-Notifications und den Rest des Modul-Vertrags beschreibt der Modul-Guide. Für Ereignisse, die externe Systeme erreichen sollen, nutzt du Webhooks und Events.