KI-AGENT: Entwirft den zentralen Push-Server für Selfhost-Instanzen, beschreibt API, Sicherheit, Datenschutz und Migrationspfad.
430 lines
14 KiB
Markdown
430 lines
14 KiB
Markdown
# Zentraler Push-Server für FEDEO
|
|
|
|
Dieser Entwurf beschreibt einen zentral betriebenen FEDEO-Push-Server, über den selbst gehostete FEDEO-Instanzen Push Notifications zustellen können. Ziel ist, dass Selfhost-Betreiber keine eigenen Apple-, Google- oder Web-Push-Zugangsdaten verwalten müssen und FEDEO trotzdem mandantenfähig, datensparsam und zuverlässig benachrichtigen kann.
|
|
|
|
## Zielbild
|
|
|
|
FEDEO erhält einen zentralen Zustelldienst unter einer FEDEO-kontrollierten Domain, zum Beispiel `https://push.fedeo.cloud`. Jede selbst gehostete Instanz registriert sich dort einmalig als Push-Client. Danach sendet die Instanz nur noch neutrale Zustellaufträge an den zentralen Server. Der zentrale Server übernimmt:
|
|
|
|
- Verwaltung öffentlicher Push-Konfigurationen für Web, iOS und Android
|
|
- Annahme signierter Zustellaufträge von Selfhost-Instanzen
|
|
- Zustellung über Web Push, APNs und FCM
|
|
- Retry, Rate Limits, Fehlerklassifizierung und Deaktivierung ungültiger Geräte
|
|
- technische Zustellmetriken ohne fachliche Inhaltsdaten
|
|
|
|
Die fachliche Entscheidung, wer welche Benachrichtigung erhält, bleibt in der jeweiligen FEDEO-Instanz. Der zentrale Server ist nur Transport- und Zustellkomponente.
|
|
|
|
## Grundprinzipien
|
|
|
|
- **Datenminimierung:** Der zentrale Server speichert keine FEDEO-Nutzerdaten, keine Mandantendaten und möglichst keine lesbaren Nachrichtentexte.
|
|
- **Instanzhoheit:** Selfhost-Instanzen behalten Nutzerverwaltung, Benachrichtigungseinstellungen und Eventlogik.
|
|
- **Zentrale Provider-Schlüssel:** APNs-, FCM- und VAPID-Schlüssel liegen ausschließlich im zentralen Push-Server.
|
|
- **Signierte Aufträge:** Jede Instanz authentifiziert sich per rotierbarem Instanzschlüssel.
|
|
- **Mandantentrennung:** Instanzen und deren Geräte werden strikt getrennt, auch wenn sie denselben zentralen Dienst nutzen.
|
|
- **Ausfallsicherheit:** Der lokale FEDEO-Betrieb darf nicht blockieren, wenn der Push-Server temporär nicht erreichbar ist.
|
|
|
|
## Architektur
|
|
|
|
```text
|
|
FEDEO Web / Mobile App
|
|
|
|
|
| registriert Gerät bei lokaler Selfhost-Instanz
|
|
v
|
|
Selfhost-FEDEO-Instanz
|
|
|
|
|
| signierte API-Aufrufe
|
|
v
|
|
Zentraler FEDEO Push-Server
|
|
|
|
|
+-- PostgreSQL für Instanzen, Geräte, Zustellaufträge, Audit-Metadaten
|
|
+-- Redis oder Queue für Retry und Backpressure
|
|
+-- Worker für Web Push, APNs und FCM
|
|
+-- Provider-Schlüsselverwaltung
|
|
|
|
|
+--> Web Push Endpoints
|
|
+--> Apple Push Notification service
|
|
+--> Firebase Cloud Messaging
|
|
```
|
|
|
|
### Komponenten
|
|
|
|
| Komponente | Aufgabe |
|
|
| --- | --- |
|
|
| Selfhost-FEDEO-Backend | entscheidet Empfänger, erzeugt Notification Items, übermittelt Push-Aufträge |
|
|
| Zentrale Push API | registriert Instanzen und Geräte, nimmt Push-Aufträge an |
|
|
| Push Worker | sendet an Web Push, APNs und FCM, verarbeitet Provider-Fehler |
|
|
| Geräte-Registry | speichert technische Push Tokens oder Web-Push-Subscriptions |
|
|
| Zustelljournal | speichert technische Statuswerte, keine fachliche Historie |
|
|
| Admin-Konsole | zeigt Instanzstatus, Fehlerquoten, Rate Limits und Schlüsselrotation |
|
|
|
|
## Rollenverteilung
|
|
|
|
### Lokale FEDEO-Instanz
|
|
|
|
Die Selfhost-Instanz bleibt führend für:
|
|
|
|
- Nutzer und Mandanten
|
|
- Benachrichtigungseinstellungen
|
|
- Event-Typen und Kanäle
|
|
- fachliche Nachrichtentexte
|
|
- In-App-Benachrichtigungen
|
|
- lokale Audit- und Lesestatusdaten
|
|
|
|
Sie speichert weiterhin `notifications_items` und entscheidet, ob für ein Ereignis der Kanal `push` aktiv ist. Statt selbst über `web-push` zu senden, ruft sie den zentralen Push-Server auf.
|
|
|
|
### Zentraler Push-Server
|
|
|
|
Der zentrale Server ist zuständig für:
|
|
|
|
- öffentliche Push-Konfiguration für Clients
|
|
- Entgegennahme von Geräte-Registrierungen
|
|
- Mapping von lokalen Geräte-IDs auf Provider Tokens
|
|
- Zustellung an externe Push-Netze
|
|
- technische Fehlerbehandlung
|
|
- Missbrauchsschutz, Quotas und Sperren
|
|
|
|
Er kennt keine FEDEO-Berechtigungen. Wenn eine lokale Instanz einen gültig signierten Push-Auftrag sendet, wird dieser technisch zugestellt.
|
|
|
|
## Datenschutzmodell
|
|
|
|
Für die erste Ausbaustufe sollte der Push-Server Push-Inhalte nur transitär verarbeiten und nicht dauerhaft speichern. Dauerhaft gespeichert werden:
|
|
|
|
- Instanz-ID
|
|
- Geräte-ID
|
|
- Plattform: `web`, `ios`, `android`
|
|
- Provider-Endpunkt oder Provider-Token, verschlüsselt gespeichert
|
|
- Zeitpunkte: erstellt, zuletzt gesehen, deaktiviert
|
|
- Zustellstatus pro Auftrag: angenommen, gesendet, fehlgeschlagen
|
|
- technische Fehlercodes
|
|
|
|
Nicht dauerhaft gespeichert werden:
|
|
|
|
- Name, E-Mail oder lokale Nutzer-ID
|
|
- Mandantenname
|
|
- fachliche Objekt-IDs, sofern nicht zwingend notwendig
|
|
- vollständige Nachrichtentexte
|
|
|
|
Für Benachrichtigungen mit sensiblen Inhalten empfiehlt sich ein Payload-Modell mit generischem Text:
|
|
|
|
```json
|
|
{
|
|
"title": "Neue FEDEO-Benachrichtigung",
|
|
"body": "Öffne FEDEO, um die Details anzusehen.",
|
|
"data": {
|
|
"notificationId": "lokale-notification-id",
|
|
"instanceBaseUrl": "https://app.example.com"
|
|
}
|
|
}
|
|
```
|
|
|
|
Die lokale App lädt Details anschließend authentifiziert von der Selfhost-Instanz.
|
|
|
|
## Instanzregistrierung
|
|
|
|
Jede Selfhost-Instanz erhält beim Setup eine zentrale Instanzidentität.
|
|
|
|
### Ablauf
|
|
|
|
1. Betreiber öffnet in FEDEO den Bereich `Administration > Push Notifications`.
|
|
2. FEDEO erzeugt eine lokale Instanz-ID, falls noch keine existiert.
|
|
3. Betreiber meldet die Instanz am zentralen Push-Portal an oder nutzt einen geführten Aktivierungscode.
|
|
4. Der zentrale Server erzeugt einen Client-Schlüssel.
|
|
5. Die Selfhost-Instanz speichert `FEDEO_PUSH_INSTANCE_ID` und `FEDEO_PUSH_CLIENT_SECRET`.
|
|
6. Die Instanz ruft regelmäßig einen Healthcheck auf.
|
|
|
|
### Benötigte Umgebungsvariablen
|
|
|
|
```env
|
|
FEDEO_PUSH_MODE=central
|
|
FEDEO_PUSH_GATEWAY_URL=https://push.fedeo.cloud
|
|
FEDEO_PUSH_INSTANCE_ID=inst_...
|
|
FEDEO_PUSH_CLIENT_SECRET=...
|
|
FEDEO_PUSH_PAYLOAD_MODE=minimal
|
|
```
|
|
|
|
`FEDEO_PUSH_MODE=local` bleibt für Entwickler und Betreiber möglich, die eigene VAPID-Schlüssel nutzen möchten.
|
|
|
|
## Geräte-Registrierung
|
|
|
|
Die lokale FEDEO-Instanz sollte weiterhin der erste Ansprechpartner für den Client bleiben. Dadurch kann sie Authentifizierung und Mandantenzuordnung prüfen.
|
|
|
|
### Web Push
|
|
|
|
1. FEDEO Web fragt lokal `/api/notifications/push/config` ab.
|
|
2. Die lokale Instanz liefert bei `central` die öffentliche VAPID-Konfiguration des zentralen Servers.
|
|
3. Der Browser erzeugt eine Web-Push-Subscription.
|
|
4. FEDEO Web sendet die Subscription an die lokale Instanz.
|
|
5. Die lokale Instanz registriert die Subscription beim zentralen Push-Server.
|
|
6. Der zentrale Server gibt eine `centralDeviceId` zurück.
|
|
7. Die lokale Instanz speichert diese ID in `notification_push_subscriptions.meta`.
|
|
|
|
### Mobile Push
|
|
|
|
Für iOS und Android registriert die FEDEO-App das Gerät über die native Push-Schicht und sendet den Provider Token an die lokale Instanz. Die lokale Instanz leitet ihn an den zentralen Push-Server weiter. Der zentrale Server speichert den Token verschlüsselt und liefert eine `centralDeviceId` zurück.
|
|
|
|
## API-Entwurf
|
|
|
|
Alle Instanz-API-Aufrufe nutzen HTTPS und eine HMAC-Signatur oder kurze JWTs mit rotierbarem Secret.
|
|
|
|
### `GET /v1/public-config`
|
|
|
|
Liefert öffentliche Push-Parameter.
|
|
|
|
```json
|
|
{
|
|
"webPushPublicKey": "...",
|
|
"iosBundleId": "cloud.fedeo.app",
|
|
"androidSenderId": "..."
|
|
}
|
|
```
|
|
|
|
### `POST /v1/instances/heartbeat`
|
|
|
|
Meldet Status und Version der Selfhost-Instanz.
|
|
|
|
```json
|
|
{
|
|
"instanceId": "inst_123",
|
|
"fedeoVersion": "2026.05.22",
|
|
"baseUrl": "https://app.example.com",
|
|
"capabilities": ["web_push", "minimal_payload"]
|
|
}
|
|
```
|
|
|
|
### `POST /v1/devices`
|
|
|
|
Registriert oder aktualisiert ein Gerät.
|
|
|
|
```json
|
|
{
|
|
"localDeviceId": "sub_456",
|
|
"platform": "web",
|
|
"subscription": {
|
|
"endpoint": "https://...",
|
|
"keys": {
|
|
"p256dh": "...",
|
|
"auth": "..."
|
|
}
|
|
},
|
|
"meta": {
|
|
"browser": "Firefox",
|
|
"os": "macOS"
|
|
}
|
|
}
|
|
```
|
|
|
|
Antwort:
|
|
|
|
```json
|
|
{
|
|
"centralDeviceId": "dev_789",
|
|
"status": "active"
|
|
}
|
|
```
|
|
|
|
### `DELETE /v1/devices/{centralDeviceId}`
|
|
|
|
Deaktiviert ein Gerät.
|
|
|
|
### `POST /v1/push`
|
|
|
|
Nimmt einen Zustellauftrag entgegen.
|
|
|
|
```json
|
|
{
|
|
"idempotencyKey": "notification-item-id:dev_789",
|
|
"devices": ["dev_789"],
|
|
"priority": "normal",
|
|
"ttlSeconds": 3600,
|
|
"collapseKey": "communication.message.new",
|
|
"notification": {
|
|
"title": "Neue FEDEO-Benachrichtigung",
|
|
"body": "Öffne FEDEO, um die Details anzusehen."
|
|
},
|
|
"data": {
|
|
"notificationId": "lokale-notification-id",
|
|
"link": "/communication"
|
|
}
|
|
}
|
|
```
|
|
|
|
Antwort:
|
|
|
|
```json
|
|
{
|
|
"accepted": 1,
|
|
"rejected": 0,
|
|
"deliveryJobId": "job_abc"
|
|
}
|
|
```
|
|
|
|
### `GET /v1/push/{deliveryJobId}`
|
|
|
|
Liefert technische Zustellinformationen für Debugging und Support.
|
|
|
|
```json
|
|
{
|
|
"status": "completed",
|
|
"sent": 1,
|
|
"failed": 0,
|
|
"disabledDevices": []
|
|
}
|
|
```
|
|
|
|
## Lokale Backend-Anpassung
|
|
|
|
Der bestehende `NotificationService` kann um einen Provider ergänzt werden:
|
|
|
|
```text
|
|
NotificationService
|
|
|
|
|
+-- InAppDeliveryProvider
|
|
+-- EmailDeliveryProvider
|
|
+-- LocalWebPushDeliveryProvider
|
|
+-- CentralPushDeliveryProvider
|
|
```
|
|
|
|
`CentralPushDeliveryProvider` nutzt die lokalen Einträge aus `notification_push_subscriptions`, sucht aktive Geräte mit `centralDeviceId` und sendet Zustellaufträge an den zentralen Push-Server. Ohne `centralDeviceId` versucht er eine Nachregistrierung oder markiert den lokalen Eintrag als fehlerhaft.
|
|
|
|
Für Kompatibilität sollte die lokale Tabelle erweitert oder die vorhandene `meta`-Spalte genutzt werden:
|
|
|
|
```json
|
|
{
|
|
"centralDeviceId": "dev_789",
|
|
"platform": "web",
|
|
"registeredVia": "central",
|
|
"lastGatewaySyncAt": "2026-05-22T10:00:00Z"
|
|
}
|
|
```
|
|
|
|
## Zustellverhalten
|
|
|
|
### Idempotenz
|
|
|
|
Jede lokale Instanz sendet pro Notification Item und Gerät einen stabilen `idempotencyKey`. Der zentrale Server verarbeitet denselben Key innerhalb eines konfigurierbaren Fensters nur einmal.
|
|
|
|
### Retry
|
|
|
|
Der zentrale Server unterscheidet:
|
|
|
|
- temporäre Fehler: Netzwerk, Provider-Timeout, Rate Limit
|
|
- dauerhafte Fehler: ungültiges Token, abgelaufene Web-Push-Subscription
|
|
- Konfigurationsfehler: gesperrte Instanz, ungültige Signatur, Quota überschritten
|
|
|
|
Temporäre Fehler werden mit exponentiellem Backoff wiederholt. Dauerhafte Gerätefehler deaktivieren das zentrale Gerät und werden an die lokale Instanz zurückgemeldet.
|
|
|
|
### Rückmeldung an lokale Instanzen
|
|
|
|
Für die erste Ausbaustufe reicht Pull-basiertes Debugging über `GET /v1/push/{deliveryJobId}`. Später kann ein Webhook ergänzt werden:
|
|
|
|
```text
|
|
POST <selfhost-base-url>/api/notifications/push/gateway-callback
|
|
```
|
|
|
|
Damit kann die lokale Instanz ungültige Geräte automatisch deaktivieren.
|
|
|
|
## Sicherheit
|
|
|
|
### Authentifizierung
|
|
|
|
Empfohlen ist ein HMAC-Schema:
|
|
|
|
```text
|
|
X-Fedeo-Instance-Id: inst_123
|
|
X-Fedeo-Timestamp: 2026-05-22T10:00:00Z
|
|
X-Fedeo-Signature: hmac-sha256(...)
|
|
```
|
|
|
|
Signiert werden Methode, Pfad, Timestamp, Body-Hash und Instanz-ID. Requests mit zu altem Timestamp werden abgelehnt.
|
|
|
|
### Secret-Rotation
|
|
|
|
Der zentrale Server sollte pro Instanz zwei aktive Secrets unterstützen:
|
|
|
|
- `currentSecret`
|
|
- `nextSecret`
|
|
|
|
Die Selfhost-Instanz kann dadurch ohne Ausfall rotieren. Nach erfolgreichem Wechsel wird das alte Secret deaktiviert.
|
|
|
|
### Missbrauchsschutz
|
|
|
|
- Rate Limit pro Instanz
|
|
- Tageskontingent pro Instanz
|
|
- Maximalgröße für Payloads
|
|
- Blocklist für kompromittierte Instanzen
|
|
- Audit-Log für Admin-Aktionen
|
|
- strikte Validierung von Links, damit Pushes nicht zu fremden Domains leiten
|
|
|
|
## Betriebsmodell
|
|
|
|
### Deployment
|
|
|
|
Der zentrale Push-Server sollte als eigener Dienst betrieben werden:
|
|
|
|
- `push-api`: HTTP API für Instanzen und Admin-Konsole
|
|
- `push-worker`: Queue-Verarbeitung und Provider-Zustellung
|
|
- `postgres`: Instanzen, Geräte, Jobs, Audit
|
|
- `redis`: Queue, Rate Limits, kurzlebige Idempotenzdaten
|
|
- `traefik` oder anderer Reverse Proxy mit TLS
|
|
|
|
### Monitoring
|
|
|
|
Wichtige Metriken:
|
|
|
|
- angenommene Push-Aufträge pro Instanz
|
|
- Zustellquote pro Plattform
|
|
- Provider-Latenz
|
|
- Fehlerrate nach Fehlerklasse
|
|
- deaktivierte Geräte
|
|
- Queue-Länge und Retry-Alter
|
|
- Signaturfehler und Rate-Limit-Treffer
|
|
|
|
### Verfügbarkeit
|
|
|
|
Wenn der zentrale Push-Server nicht erreichbar ist, markiert die lokale Instanz Push-Zustellungen als temporär fehlgeschlagen und versucht sie später erneut. In-App-Benachrichtigungen bleiben davon unberührt.
|
|
|
|
## Migrationspfad
|
|
|
|
### Phase 1: Web Push Gateway
|
|
|
|
- zentrale VAPID-Schlüssel bereitstellen
|
|
- Selfhost-Instanzen gegen Push-Server authentifizieren
|
|
- Web-Push-Subscriptions zentral registrieren
|
|
- bestehendes lokales Web-Push-Sending optional durch Gateway ersetzen
|
|
- minimale Payloads verwenden
|
|
|
|
### Phase 2: Mobile Push
|
|
|
|
- iOS und Android Tokens registrieren
|
|
- APNs und FCM im zentralen Worker anbinden
|
|
- Deep Links zur passenden Selfhost-Instanz öffnen
|
|
- Token-Rotation und App-Neuinstallation robust behandeln
|
|
|
|
### Phase 3: Rückmeldungen und Admin
|
|
|
|
- Zustellcallbacks an Selfhost-Instanzen
|
|
- Admin-Konsole für Instanzen, Sperren, Quotas und Fehleranalyse
|
|
- Secret-Rotation per Oberfläche
|
|
- Export technischer Logs für Supportfälle
|
|
|
|
### Phase 4: Erweiterte Kanäle
|
|
|
|
- mandantenweite Push-Richtlinien
|
|
- gebündelte Pushes
|
|
- stille Pushes für Synchronisation
|
|
- optional Webhook-Zustellung für Integrationen
|
|
|
|
## Offene Entscheidungen
|
|
|
|
- Sollen Push-Inhalte standardmäßig immer minimal sein oder darf eine Instanz explizit lesbare Titel und Texte erlauben?
|
|
- Wird die Instanzregistrierung über ein zentrales FEDEO-Konto oder über offline erzeugte Aktivierungscodes erfolgen?
|
|
- Soll der zentrale Push-Server Bestandteil eines größeren FEDEO-Cloud-Portals werden?
|
|
- Wie lange sollen technische Zustelllogs maximal aufbewahrt werden?
|
|
- Welche Quotas gelten für kostenlose, lizenzierte und interne Instanzen?
|
|
|
|
## Empfehlung für den ersten Schnitt
|
|
|
|
Für den ersten produktionsnahen Stand sollte FEDEO nur Web Push über den zentralen Server abwickeln. Das passt direkt zum vorhandenen Benachrichtigungssystem und reduziert den Betreiberaufwand für Selfhost-Instanzen deutlich. Die lokale Instanz bleibt fachlich führend, der zentrale Server sieht nur technische Geräte und minimale Zustellaufträge.
|
|
|
|
Die wichtigste Architekturentscheidung ist dabei, den zentralen Server nicht als Benachrichtigungslogik zu bauen, sondern als schlanken Push-Transport. Dadurch bleibt Selfhosting souverän, während FEDEO trotzdem die komplizierten Provider-Schlüssel und mobilen Push-Integrationen zentral beherrschen kann.
|