← Zur Uebersicht

novaris-policy-web-modern-spa

React/TypeScript-SPA fuer novaris-policy-core-modern - Umsetzung der zuvor nur als Ziel benannten novaris-policy-web-modern-spa-Luecke (siehe docs/70-migration/02-component-mapping.md, Zeile zum JSF-Portal). Kein Legacy-Gegenstueck 1:1 (das Legacy-JSF-Portal ist server-seitig gerendert, hier: reines REST-Client-SPA) - fachlich aber derselbe Anwendungsfall wie novaris-policy-web-legacy-jsf.

Stack

Warum Authorization-Code-Flow + PKCE statt Password-Grant

Der Password-Grant (grant_type=password), den dieses Projekt an anderer Stelle fuer automatisierte Tests/curl-Verifikation nutzt (siehe 11-oidc-keycloak.md), ist fuer eine echte Browser-Anwendung ungeeignet - er wuerde bedeuten, dass die SPA selbst Benutzername/Passwort entgegennimmt und an Keycloak weiterreicht, statt dass die Authentifizierung komplett bei Keycloak stattfindet (Redirect zur Keycloak-Login-Seite). PKCE (code_challenge/code_verifier) ersetzt dabei den sonst fuer den Authorization-Code- Flow noetigen Client-Secret - ein Browser-Client kann kein Geheimnis verstecken (der komplette Quellcode liegt offen), PKCE macht den abgefangenen Code allein wertlos ohne den nur clientseitig gehaltenen Verifier.

Warum kein eigener Backend-Endpunkt fuer Produktcodes

CreatePolicyPage.tsx haelt die drei gueltigen Produktcodes (KFZ-HAFTPFLICHT/KFZ-KASKO/LEBEN) als schmale, bewusst redundante Konstante - PremiumCalculationService.buildRateTable im Backend exponiert diese nicht ueber einen eigenen Endpunkt. Fuer drei feste, seltenaenderliche Werte war ein eigener GET /api/products-Endpunkt nur fuer diesen einen Zweck nicht gerechtfertigt.

CORS

novaris-policy-core-moderns SecurityConfig.corsConfigurationSource() erlaubt bewusst nur http://localhost:5173 (Vite-Dev-Server-Standardport) - kein Wildcard-Origin, siehe dessen Javadoc.

Bauen, testen, lokal starten

# aus novaris-modern-parent/novaris-policy-web-modern-spa/:
npm install
cp .env.example .env.local   # ggf. Ports anpassen
npm run dev                  # http://localhost:5173
npm run build                # tsc -b && vite build, Produktions-Bundle nach dist/
npm run lint                 # oxlint
npm test                     # Vitest: Routing-/Auth-Schutztests

Voraussetzung fuer einen echten Login: novaris-policy-core-modern (Port 8080) und ein Keycloak mit importiertem novaris-realm.json (Port 8081, siehe novaris-policy-core-modern/README.md) muessen erreichbar sein.

Real verifiziert

Ohne Browser-Automatisierungswerkzeug in dieser Umgebung wurde die UI nicht durch echtes Klicken getestet - stattdessen wurde der komplette Protokoll-/Integrationspfad, den die SPA zur Laufzeit durchlaeuft, per Skript nachgebildet und gegen echte, laufende Instanzen verifiziert (kein Mock):

  1. npm test, npm run build und npm run lint laufen fehlerfrei durch.
  2. CORS-Preflight (OPTIONS) gegen das echte Backend: http://localhost:5173 wird erlaubt (Access-Control-Allow-Origin korrekt gesetzt), ein fremder Origin wird mit 403 abgelehnt (kein Wildcard-Leck).
  3. Kompletter Authorization-Code-+-PKCE-Flow gegen einen echten Keycloak-Container nachgebildet: Autorisierungsanfrage mit echtem PKCE-Code-Challenge, echter Login-Formular-POST, Redirect landet exakt auf der konfigurierten VITE_OIDC_REDIRECT_URI (http://localhost:5173/callback), Code-Tausch am Token-Endpunkt mit dem passenden Code-Verifier liefert ein echtes JWT - derselbe Ablauf, den oidc-client-tss signinRedirect()/signinRedirectCallback() intern durchfuehren.
  4. Mit diesem echten Token (inkl. Origin-Header wie bei einem Browser-fetch()): echte Police ueber POST /api/policies angelegt (wie CreatePolicyPage.tsx), und die Rollenpruefung real bestaetigt - ein underwriter-Token bekommt bei cancelPolicy (nur PolicyAdmin) korrekt 403, deckungsgleich mit canCancelPolicy(roles) in src/auth/roles.ts, das denselben Button in der UI ausblendet.

Ehrliche Grenze

Kein Klick-Test in einem echten Browser (kein Playwright/Selenium in dieser Umgebung verfuegbar) - die oben beschriebene Protokoll-Verifikation deckt die Backend-Integration vollstaendig ab, nicht aber tatsaechliches Rendering/Interaktionsverhalten der React-Komponenten selbst.

⌂ Cockpit