bump
This commit is contained in:
121
docs/admin.md
Normal file
121
docs/admin.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# Adminbereich
|
||||
|
||||
Der Adminbereich liegt im Frontend unter `/admin` und verwendet dieselbe
|
||||
serverseitige Authentifizierung, CSRF-Pruefung und Permission-Logik wie die
|
||||
restliche Anwendung. Angular blendet Navigation und Aktionen nur fuer passende
|
||||
Permissions ein; verbindlich prueft immer das Backend.
|
||||
|
||||
## Permissions
|
||||
|
||||
Die administrativen Permissions sind fest in
|
||||
`apps/backend/src/roles/permissions.ts` definiert:
|
||||
|
||||
- `users.read`: Benutzer anzeigen, suchen und filtern
|
||||
- `users.manage`: Benutzer aktivieren, deaktivieren und Rollen zuweisen
|
||||
- `roles.read`: Rollen und Permissions anzeigen
|
||||
- `roles.manage`: Rollen anlegen, bearbeiten und loeschen
|
||||
- `sessions.manage`: Sessions anderer Benutzer anzeigen und beenden
|
||||
- `audit.read`: administratives Audit-Log anzeigen
|
||||
|
||||
Benutzer haben keine direkten Permissions. Effektive Permissions werden aus
|
||||
allen Rollen abgeleitet. Rollen- und Benutzerverwaltung laufen ueber Services;
|
||||
Controller greifen nicht direkt auf TypeORM-Repositories zu.
|
||||
|
||||
## Systemrollen
|
||||
|
||||
Es gibt mindestens die Systemrollen `admin` und `user`.
|
||||
|
||||
- `admin` ist geschuetzt, nicht loeschbar und muss administrative Permissions
|
||||
behalten.
|
||||
- `user` ist geschuetzt, nicht loeschbar und Standardrolle fuer neue Benutzer.
|
||||
- Eigene Rollen koennen angelegt, umbenannt, geloescht und mit bekannten
|
||||
Permissions versehen werden.
|
||||
|
||||
Eine Rolle kann nur geloescht werden, wenn sie keinem Benutzer mehr zugewiesen
|
||||
ist. Andernfalls antwortet die API mit `ROLE_STILL_ASSIGNED`.
|
||||
|
||||
## Letzter aktiver Administrator
|
||||
|
||||
Die Anwendung darf nie ohne aktiven Administrator enden. Sicherheitskritische
|
||||
Aktionen laufen transaktional und halten einen MySQL-Lock
|
||||
`business_app_admin_integrity`:
|
||||
|
||||
- Benutzer deaktivieren
|
||||
- Rollen eines Benutzers aendern
|
||||
- Adminrolle entfernen
|
||||
- Adminrolle in ihren Permissions veraendern
|
||||
- Rolle loeschen
|
||||
|
||||
Wenn eine Aktion den letzten aktiven Administrator entfernen wuerde, antwortet
|
||||
die API mit HTTP 409 und `LAST_ACTIVE_ADMIN_REQUIRED`.
|
||||
|
||||
## Benutzerstatus und Sessions
|
||||
|
||||
Benutzer werden weiterhin ausschliesslich ueber OIDC angelegt. Name und E-Mail
|
||||
kommen vom Identity Provider und sind im Adminbereich nicht editierbar.
|
||||
|
||||
Beim Deaktivieren wird der Benutzer sofort inaktiv gesetzt und alle aktiven
|
||||
Sessions des Benutzers werden widerrufen. Neue OIDC-Logins deaktivierter Benutzer
|
||||
werden trotz erfolgreicher IdP-Authentifizierung abgewiesen. Beim erneuten
|
||||
Aktivieren darf sich der Benutzer wieder anmelden; alte Sessions werden nicht
|
||||
wiederhergestellt.
|
||||
|
||||
Admin-Session-Endpunkte geben nur eine sichere, gekuerzte Session-Referenz,
|
||||
Zeitpunkte, User-Agent, IP-Annaeherung und Status zurueck. Tokens und rohe
|
||||
Session-Secrets werden nie ausgegeben.
|
||||
|
||||
## API-Endpunkte
|
||||
|
||||
Benutzer:
|
||||
|
||||
- `GET /api/admin/users`
|
||||
- `GET /api/admin/users/:id`
|
||||
- `PATCH /api/admin/users/:id/deactivate`
|
||||
- `PATCH /api/admin/users/:id/activate`
|
||||
- `POST /api/admin/users/:id/roles/:roleId`
|
||||
- `DELETE /api/admin/users/:id/roles/:roleId`
|
||||
- `GET /api/admin/users/:id/sessions`
|
||||
- `DELETE /api/admin/users/:userId/sessions/:sessionId`
|
||||
- `DELETE /api/admin/users/:id/sessions`
|
||||
|
||||
Rollen:
|
||||
|
||||
- `GET /api/admin/roles`
|
||||
- `GET /api/admin/roles/:id`
|
||||
- `POST /api/admin/roles`
|
||||
- `PUT /api/admin/roles/:id`
|
||||
- `DELETE /api/admin/roles/:id`
|
||||
|
||||
Audit:
|
||||
|
||||
- `GET /api/audit-log`
|
||||
|
||||
## Audit-Log
|
||||
|
||||
Administrative Aenderungen werden auditierbar protokolliert, darunter:
|
||||
|
||||
- `USER_ACTIVATED`
|
||||
- `USER_DEACTIVATED`
|
||||
- `USER_ROLE_ASSIGNED`
|
||||
- `USER_ROLE_REMOVED`
|
||||
- `ROLE_CREATED`
|
||||
- `ROLE_UPDATED`
|
||||
- `ROLE_DELETED`
|
||||
- `ROLE_PERMISSIONS_UPDATED`
|
||||
- `SESSION_REVOKED`
|
||||
- `ALL_USER_SESSIONS_REVOKED`
|
||||
|
||||
Gespeichert werden fachliche IDs, Request-ID und minimale Metadaten. Tokens,
|
||||
Secrets und vollstaendige Sessiondaten werden nicht geloggt.
|
||||
|
||||
## Migration
|
||||
|
||||
Die Admin-Erweiterung fuegt `roles.description` hinzu. Vor dem Deployment muss
|
||||
die Migration ausgefuehrt werden:
|
||||
|
||||
```bash
|
||||
npm run migration:run
|
||||
```
|
||||
|
||||
Der normale App-Start fuehrt Migrationen weiterhin nicht automatisch aus,
|
||||
sondern meldet fehlende Migrationen ueber die Readiness-Pruefung.
|
||||
@@ -24,7 +24,9 @@ geschnitten:
|
||||
- `sessions`: serverseitige Sessions, CSRF-Token und Session-Listen
|
||||
- `roles`: Code-definierte Permissions und rollenbasierte Rechteverwaltung
|
||||
- `users`: lokale Benutzerprofile und Einstellungen
|
||||
- `admin`: Angular-Routen unter `/admin` fuer Benutzer-, Rollen-, Session- und Audit-Verwaltung
|
||||
- `items`: Beispiel-Fachmodul
|
||||
- `notifications`: persoenliche In-App-Benachrichtigungen, Admin-Erzeugung und interner Service
|
||||
- `audit`: Audit-Log fuer administrative Nachvollziehbarkeit
|
||||
- `health`: Liveness- und Readiness-Endpunkte
|
||||
- `database`: TypeORM-Konfiguration, Entities und Migrationen
|
||||
@@ -116,5 +118,12 @@ Systemrollen:
|
||||
- `admin`: alle Permissions
|
||||
- `user`: Basisrechte fuer Items-Lesen und eigene Sessions
|
||||
|
||||
Die Standardrolle `user` enthaelt ausserdem
|
||||
`notifications.readOwn` und `notifications.updateOwn`, damit angemeldete
|
||||
Benutzer ihre eigenen In-App-Benachrichtigungen verwalten koennen.
|
||||
|
||||
Der erste erfolgreich angemeldete Benutzer wird automatisch Admin. Danach
|
||||
erhalten neue Benutzer initial die Rolle `user`.
|
||||
|
||||
Details zu Admin-Endpunkten, Systemrollen und dem transaktionalen Schutz des
|
||||
letzten aktiven Administrators stehen in [Adminbereich](admin.md).
|
||||
|
||||
@@ -30,14 +30,15 @@ separat ausgefuehrt.
|
||||
|
||||
## OIDC
|
||||
|
||||
| Variable | Bedeutung |
|
||||
| ------------------------- | ---------------------------------------------------- |
|
||||
| `OIDC_ISSUER` | Exakter Issuer des Providers |
|
||||
| `OIDC_CLIENT_ID` | Client ID |
|
||||
| `OIDC_CLIENT_SECRET` | Client Secret |
|
||||
| `OIDC_SCOPES` | Scopes, typischerweise `openid profile email` |
|
||||
| `OIDC_ALLOWED_ALGORITHMS` | Erlaubte ID-Token-Signaturalgorithmen, z. B. `RS256` |
|
||||
| `OIDC_HTTP_TIMEOUT_MS` | Timeout fuer IdP-HTTP-Requests |
|
||||
| Variable | Bedeutung |
|
||||
| ------------------------- | ------------------------------------------------------- |
|
||||
| `OIDC_ISSUER` | Exakter Issuer des Providers |
|
||||
| `OIDC_CLIENT_ID` | Client ID |
|
||||
| `OIDC_CLIENT_SECRET` | Client Secret |
|
||||
| `OIDC_SCOPES` | Scopes, typischerweise `openid profile email` |
|
||||
| `OIDC_LOGOUT_URL` | Optionale IdP-Logout-URL, falls Discovery keine liefert |
|
||||
| `OIDC_ALLOWED_ALGORITHMS` | Erlaubte ID-Token-Signaturalgorithmen, z. B. `RS256` |
|
||||
| `OIDC_HTTP_TIMEOUT_MS` | Timeout fuer IdP-HTTP-Requests |
|
||||
|
||||
Der Callback ist immer:
|
||||
|
||||
@@ -45,6 +46,11 @@ Der Callback ist immer:
|
||||
<APP_BASE_URL>/api/auth/callback
|
||||
```
|
||||
|
||||
Beim App-Logout wird zuerst die lokale Session widerrufen. Danach leitet die App
|
||||
zum OIDC `end_session_endpoint` aus Discovery weiter. Wenn der Provider diesen
|
||||
Endpoint nicht publiziert, kann `OIDC_LOGOUT_URL` gesetzt werden. Die App sendet
|
||||
`client_id`, `post_logout_redirect_uri` und, falls vorhanden, `id_token_hint`.
|
||||
|
||||
## Sessions und CSRF
|
||||
|
||||
| Variable | Bedeutung |
|
||||
@@ -93,6 +99,7 @@ OIDC_ISSUER=https://idp.example.com/realms/internal
|
||||
OIDC_CLIENT_ID=business-app
|
||||
OIDC_CLIENT_SECRET=<secret>
|
||||
OIDC_SCOPES=openid profile email
|
||||
OIDC_LOGOUT_URL=https://idp.example.com/realms/internal/protocol/openid-connect/logout
|
||||
OIDC_ALLOWED_ALGORITHMS=RS256
|
||||
OIDC_HTTP_TIMEOUT_MS=5000
|
||||
SESSION_COOKIE_NAME=app_session
|
||||
|
||||
114
docs/design-system.md
Normal file
114
docs/design-system.md
Normal file
@@ -0,0 +1,114 @@
|
||||
# Designsystem
|
||||
|
||||
Das Frontend verwendet ein eigenes, schlankes Designsystem ohne externe
|
||||
UI-Library. Es besteht aus zentralen CSS Custom Properties, globalen
|
||||
Grundklassen und wenigen Angular-UI-Komponenten unter
|
||||
`apps/frontend/src/app/shared/ui`.
|
||||
|
||||
## Prinzipien
|
||||
|
||||
- sachliche Business-Oberflaeche statt Marketing-Optik
|
||||
- mobile first, keine globale Mindestbreite
|
||||
- klare Hierarchie durch Typografie, Abstand und Rahmen
|
||||
- Farben immer semantisch ueber Tokens
|
||||
- sichtbare Fokuszustaende und grosse Touch-Flaechen
|
||||
- Komponenten nur dort, wo sie Verhalten oder Wiederverwendung bringen
|
||||
|
||||
## Tokens
|
||||
|
||||
Die Tokens liegen in `apps/frontend/src/styles/_tokens.scss` und werden ueber
|
||||
`apps/frontend/src/styles.scss` eingebunden.
|
||||
|
||||
Wichtige Gruppen:
|
||||
|
||||
- Farben: `--color-primary`, `--color-danger`, `--color-surface`,
|
||||
`--color-text-primary`, `--color-border`, `--color-focus`
|
||||
- Abstaende: `--space-1` bis `--space-9`
|
||||
- Typografie: `--font-size-xs` bis `--font-size-2xl`, `--line-height-*`,
|
||||
`--font-weight-*`
|
||||
- Layout: `--container-width`, `--sidebar-width`, `--header-height`,
|
||||
`--touch-target`, `--input-height`, `--button-height`
|
||||
- Oberflaeche: `--radius-*`, `--shadow-*`, `--z-*`, `--transition-*`
|
||||
|
||||
Feature-Komponenten duerfen keine direkten Hex-Farben enthalten. Neue Farben
|
||||
werden zuerst als semantische Tokens angelegt.
|
||||
|
||||
## Globale Klassen
|
||||
|
||||
Globale Klassen sind bewusst begrenzt:
|
||||
|
||||
- Layout: `.ui-page`, `.ui-page-header`, `.ui-grid`, `.ui-card`,
|
||||
`.ui-toolbar`, `.ui-actions`
|
||||
- Formulare: `.ui-form`, `.ui-form-field`, `.ui-control`, `.ui-checkbox`,
|
||||
`.ui-field-error`
|
||||
- Buttons: `.ui-button`, `.ui-icon-button`
|
||||
- Tabellen: `.ui-table-wrap`, `.ui-table`
|
||||
- Status: `.ui-badge`, `.ui-badge--success`, `.ui-badge--warning`,
|
||||
`.ui-badge--danger`, `.ui-badge--info`
|
||||
- Utilities: `.visually-hidden`, `.truncate`, `.stack`, `.cluster`,
|
||||
`.full-width`, `.text-muted`
|
||||
|
||||
Keine neuen Utility-Klassen einfuehren, wenn eine lokale Klasse oder bestehende
|
||||
UI-Komponente ausreicht.
|
||||
|
||||
## Angular-Komponenten
|
||||
|
||||
Wiederverwendbare UI-Bausteine:
|
||||
|
||||
- `UiButtonComponent`
|
||||
- `UiIconComponent`
|
||||
- `UiIconButtonComponent`
|
||||
- `UiFormFieldComponent`
|
||||
- `UiStatusBadgeComponent`
|
||||
- `UiConfirmDialogComponent`
|
||||
- `ToastService` und `UiToastHostComponent`
|
||||
- `UiEmptyStateComponent`
|
||||
- `UiLoadingStateComponent`
|
||||
- `UiPaginationComponent`
|
||||
- `UiPageHeaderComponent`
|
||||
|
||||
Neue Feature-Seiten sollen diese Bausteine bevorzugen, wenn sie Button-, Badge-,
|
||||
Dialog-, Toast-, Empty-, Loading- oder Pagination-Verhalten brauchen.
|
||||
|
||||
## Responsive Regeln
|
||||
|
||||
- Mobile Layouts sind einspaltig.
|
||||
- Aktionen duerfen mobil untereinander stehen und volle Breite nutzen.
|
||||
- Business-Listen werden mobil als Karten dargestellt.
|
||||
- Tabellen liegen in `.ui-table-wrap`, wenn eine echte Tabelle sinnvoll bleibt.
|
||||
- Touch-Ziele orientieren sich an `--touch-target`.
|
||||
- Breakpoints werden in rem formuliert und nicht nach Geraetetyp benannt.
|
||||
|
||||
## Accessibility
|
||||
|
||||
- native HTML-Elemente vor ARIA verwenden
|
||||
- interaktive Elemente sind Buttons oder Links
|
||||
- sichtbare Fokuszustaende nicht entfernen
|
||||
- Labels ersetzen Placeholder nicht
|
||||
- Fehlertexte stehen direkt am Feld
|
||||
- Status ist nicht nur Farbe, sondern auch Text/Marker
|
||||
- Dialoge setzen Fokus, schliessen per Escape und geben Fokus zurueck
|
||||
- Navigation und Drawer sind per Tastatur bedienbar
|
||||
- Animationen respektieren `prefers-reduced-motion`
|
||||
|
||||
## Entwicklungsseite
|
||||
|
||||
Die interne Referenzseite liegt unter:
|
||||
|
||||
```text
|
||||
/dev/design-system
|
||||
```
|
||||
|
||||
Sie ist mit `devOnlyGuard` geschuetzt und im Production-Modus nicht matchbar.
|
||||
Sie ersetzt kein Storybook, sondern zeigt die vorhandenen Tokens und Komponenten
|
||||
innerhalb der echten Anwendung.
|
||||
|
||||
## Regeln fuer neue UI
|
||||
|
||||
1. Bestehende UI-Komponenten oder globale Klassen wiederverwenden.
|
||||
2. Keine direkte Hex-Farbe in Feature-Komponenten.
|
||||
3. Keine neue UI-Library einfuehren.
|
||||
4. Keine tiefen Selektoren, kein `::ng-deep`, kein unkontrolliertes
|
||||
`!important`.
|
||||
5. Keine klickbaren `div`-Elemente als Ersatz fuer Buttons oder Links.
|
||||
6. Verhalten mit Vitest testen, insbesondere Accessibility-relevante Zustaende.
|
||||
@@ -38,6 +38,11 @@ Der OIDC Provider muss als Redirect URI diese URL erlauben:
|
||||
http://localhost:3000/api/auth/callback
|
||||
```
|
||||
|
||||
Falls der Provider RP-Initiated Logout validiert, muss ausserdem
|
||||
`http://localhost:4200` beziehungsweise die konfigurierte `FRONTEND_BASE_URL` als
|
||||
Post-Logout-Redirect erlaubt sein. Wenn Discovery keinen `end_session_endpoint`
|
||||
liefert, setze `OIDC_LOGOUT_URL`.
|
||||
|
||||
## Datenbank vorbereiten
|
||||
|
||||
Die Anwendung fuehrt Migrationen beim normalen Start nicht automatisch aus.
|
||||
|
||||
146
docs/notifications.md
Normal file
146
docs/notifications.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# Benachrichtigungen
|
||||
|
||||
Das Modul `apps/backend/src/notifications` stellt persoenliche In-App-
|
||||
Benachrichtigungen bereit. Es gibt bewusst keinen E-Mail-Versand, keine Push
|
||||
Notifications, keine WebSockets, keine Server-Sent Events, keine Queue, kein
|
||||
Redis und keine Hintergrundjobs. Neue Benachrichtigungen werden beim Laden der
|
||||
Anwendung und per Frontend-Polling abgerufen.
|
||||
|
||||
## Datenmodell
|
||||
|
||||
Die Entity `NotificationEntity` wird in der Tabelle `notifications` gespeichert.
|
||||
Jede Benachrichtigung gehoert genau einem Benutzer.
|
||||
|
||||
Felder:
|
||||
|
||||
- `id`: UUID
|
||||
- `userId`: Foreign Key auf `users.id`
|
||||
- `type`: technischer Typ aus `NotificationType`
|
||||
- `title`: kurzer Plain-Text-Titel, maximal 150 Zeichen
|
||||
- `message`: Plain-Text-Nachricht, maximal 1000 Zeichen
|
||||
- `link`: optionale interne Angular-Route, maximal 500 Zeichen
|
||||
- `metadata`: optionale JSON-Metadaten, maximal 4096 Bytes serialisiert
|
||||
- `readAt`: `null`, solange ungelesen
|
||||
- `createdAt`: UTC-Erstellungszeit
|
||||
- `deletedAt`: Soft Delete
|
||||
|
||||
Indizes:
|
||||
|
||||
- `user_id, created_at`
|
||||
- `user_id, read_at`
|
||||
- `user_id, deleted_at`
|
||||
|
||||
Die Migration liegt unter
|
||||
`apps/backend/src/database/migrations/1720000001000-AddNotifications.ts` und wird
|
||||
nicht automatisch beim App-Start ausgefuehrt.
|
||||
|
||||
## Typen
|
||||
|
||||
Benachrichtigungstypen sind Code, keine Datenbankdaten:
|
||||
|
||||
- `system`
|
||||
- `item.created`
|
||||
- `item.updated`
|
||||
- `user.role-changed`
|
||||
|
||||
Neue Module erweitern `apps/backend/src/notifications/notification-types.ts`
|
||||
und nutzen anschliessend `NotificationsService`.
|
||||
|
||||
## Permissions
|
||||
|
||||
- `notifications.readOwn`: eigene Benachrichtigungen lesen
|
||||
- `notifications.updateOwn`: eigene Benachrichtigungen markieren oder loeschen
|
||||
- `notifications.manage`: administrativ Benachrichtigungen erzeugen
|
||||
|
||||
Die Systemrolle `user` erhaelt `notifications.readOwn` und
|
||||
`notifications.updateOwn`. Die Rolle `admin` erhaelt ueber `allPermissions`
|
||||
zusaetzlich `notifications.manage`.
|
||||
|
||||
## API
|
||||
|
||||
Alle Endpunkte liegen unter dem bestehenden API-Praefix `/api`.
|
||||
|
||||
- `GET /notifications`: eigene Benachrichtigungen, mit `page`, `pageSize` und
|
||||
`status=all|read|unread`
|
||||
- `GET /notifications/unread-count`: Anzahl ungelesener eigener
|
||||
Benachrichtigungen
|
||||
- `PATCH /notifications/:id/read`: idempotent als gelesen markieren
|
||||
- `PATCH /notifications/:id/unread`: idempotent als ungelesen markieren
|
||||
- `PATCH /notifications/read-all`: alle eigenen Benachrichtigungen als gelesen
|
||||
markieren
|
||||
- `DELETE /notifications/:id`: Soft Delete einer eigenen Benachrichtigung
|
||||
- `POST /admin/notifications`: administrative Erzeugung mit
|
||||
`notifications.manage`
|
||||
|
||||
Normale Benutzer koennen keine fremde `userId` uebergeben. Der aktuelle Benutzer
|
||||
wird serverseitig aus der Session bestimmt.
|
||||
|
||||
## Interner Service
|
||||
|
||||
Andere Backend-Module erzeugen Benachrichtigungen ueber
|
||||
`NotificationsService`, nicht direkt ueber ein Repository:
|
||||
|
||||
```ts
|
||||
await notifications.createForUser({
|
||||
userId,
|
||||
type: NotificationType.ItemCreated,
|
||||
title: 'Neuer Eintrag',
|
||||
message: 'Der Eintrag "Beispiel" wurde erstellt.',
|
||||
link: '/items/123',
|
||||
metadata: { itemId: '123' },
|
||||
});
|
||||
```
|
||||
|
||||
Verfuegbare Methoden:
|
||||
|
||||
- `createForUser`
|
||||
- `createForUsers`
|
||||
- `getForCurrentUser`
|
||||
- `getUnreadCount`
|
||||
- `markAsRead`
|
||||
- `markAsUnread`
|
||||
- `markAllAsRead`
|
||||
- `softDelete`
|
||||
|
||||
`createForUsers` begrenzt Bulk-Erzeugung auf 100 Zielbenutzer.
|
||||
|
||||
## Integrationen
|
||||
|
||||
`ItemsService` benachrichtigt beim Erstellen eines Items den ersten aktiven
|
||||
Administrator, sofern dieser nicht der Ersteller ist. Das ist eine bewusst kleine
|
||||
Beispielregel und keine vollstaendige fachliche Eskalationslogik.
|
||||
|
||||
`UsersService` benachrichtigt betroffene Benutzer nach erfolgreicher
|
||||
Rollenaenderung. Fehler beim Erzeugen werden geloggt; die bereits erfolgreiche
|
||||
sicherheitsrelevante Rollenaenderung wird dadurch nicht unkontrolliert
|
||||
zurueckgerollt.
|
||||
|
||||
Administrative Erzeugung wird im Audit-Log als `NOTIFICATION_CREATED`
|
||||
protokolliert. Geloggt werden Actor, Zielbenutzer, Notification-ID, Typ und
|
||||
Request-ID, nicht die vollstaendige Nachricht oder Metadata.
|
||||
|
||||
## Frontend
|
||||
|
||||
`NotificationStore` verwendet Angular Signals fuer lokalen State und RxJS fuer
|
||||
HTTP und Polling. Header-Panel und Seite `/notifications` verwenden denselben
|
||||
Store, damit keine doppelten Requests fuer dieselben Daten entstehen.
|
||||
|
||||
Polling:
|
||||
|
||||
- Standardintervall: 60 Sekunden ueber `NOTIFICATION_POLL_INTERVAL_MS`
|
||||
- nur bei angemeldetem Benutzer
|
||||
- pausiert bei unsichtbarem Tab
|
||||
- aktualisiert sofort beim Sichtbarwerden
|
||||
- verhindert ueberlappende Count-Requests
|
||||
- stoppt und leert State beim Logout
|
||||
|
||||
Links werden im Frontend nur navigiert, wenn sie interne relative Routen sind.
|
||||
Titel und Nachricht werden normal interpoliert und nicht per `innerHTML`
|
||||
gerendert.
|
||||
|
||||
## Spaetere Echtzeitkommunikation
|
||||
|
||||
Wenn spaeter echte Echtzeitkommunikation noetig wird, sollte das als separate
|
||||
Architekturentscheidung erfolgen. Dann waeren Transport, Skalierung,
|
||||
Authentifizierung, Backpressure und Betrieb gemeinsam zu entscheiden, statt
|
||||
WebSockets oder Queues nebenbei in das In-App-Modul einzubauen.
|
||||
@@ -20,6 +20,12 @@ Der Login nutzt Authorization Code Flow mit PKCE:
|
||||
Erlaubte Signaturalgorithmen werden ueber `OIDC_ALLOWED_ALGORITHMS` gesetzt.
|
||||
`none` ist explizit verboten.
|
||||
|
||||
Beim Logout wird zuerst die lokale Session widerrufen und das Session-/CSRF-Cookie
|
||||
geloescht. Anschliessend redirectet das Backend zum OIDC
|
||||
`end_session_endpoint` aus Discovery oder zur optionalen `OIDC_LOGOUT_URL`. Wenn
|
||||
die Session ein ID-Token enthaelt, wird es nur als `id_token_hint` an den IdP
|
||||
gegeben und nicht an das Frontend ausgeliefert.
|
||||
|
||||
## Sessions
|
||||
|
||||
Sessions liegen in MySQL. Das Session-Cookie enthaelt keine Tokens oder
|
||||
@@ -60,6 +66,18 @@ Backend-Controller schuetzen Endpunkte mit:
|
||||
Angular nutzt Permissions nur fuer Navigation und Darstellung. Eine versteckte
|
||||
Schaltflaeche ist keine Sicherheitsgrenze.
|
||||
|
||||
Administrative Benutzer-, Rollen- und Session-Aktionen sind unter `/api/admin/*`
|
||||
mit `users.read`, `users.manage`, `roles.read`, `roles.manage`,
|
||||
`sessions.manage` und `audit.read` geschuetzt. Aktionen, die den letzten aktiven
|
||||
Administrator entfernen koennten, laufen transaktional und antworten bei Verstoss
|
||||
mit `LAST_ACTIVE_ADMIN_REQUIRED`.
|
||||
|
||||
Benachrichtigungen sind benutzerbezogene Daten. Normale Notification-Endpunkte
|
||||
bestimmen den Benutzer ausschliesslich aus der serverseitig aufgeloesten Session.
|
||||
Benutzer-IDs werden fuer eigene Benachrichtigungen nicht als Query-Parameter oder
|
||||
Body-Feld akzeptiert. Fremde oder geloeschte Notification-IDs werden als nicht
|
||||
gefunden behandelt.
|
||||
|
||||
## Benutzerstatus
|
||||
|
||||
Deaktivierte Benutzer werden trotz erfolgreichem IdP-Login abgewiesen. Aktive
|
||||
|
||||
Reference in New Issue
Block a user