Reklamationen der Fahrer: Meldungen verdeckten Buttons, und nach dem
Abschluss stand „Lieferung nicht in der Tour gefunden" ohne Ausweg da.
Meldungen:
- Erfolgs-SnackBars entfernt, bei Erfolg bleibt der Spinner
- einheitliche, schwebende Meldungen statt Stau über den Buttons
- Server-Rohtexte durch verständliche Texte ersetzt (api_failure_text)
Laden:
- fehlt eine geöffnete Lieferung, wird die Tour einmal neu geholt; die
Meldung kommt nur nach erfolgreichem Abruf ohne die Lieferung
- Endlos-Spinner auf Lieferdetail, Filial-Abholung und Beladen ersetzt
durch Kopfzeile, Fehlergrund und „Erneut versuchen"
- Tour wird nach einem Tageswechsel nachgeladen, offene Seiten bleiben
dabei unberührt
- Abschluss und Zuweisung überschreiben kein zwischenzeitliches Neuladen,
alte Antworten drehen einen Abschluss nicht mehr zurück
- leere Server-Antworten gelten als Fehler statt als „keine Daten"
Anmeldung:
- Token-Erneuerung wartet höchstens 12 s, der native Aufruf läuft weiter
- App-Start ohne Netz zeigt einen Hinweis mit „Erneut versuchen"
- Fehlerseite der Fahrzeugauswahl bietet „Abmelden"
Außerdem Podfile.lock an die Plugins angeglichen. Tests für die neuen
Fehlerpfade ergänzt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Umgebungen (Name, API-URL, Keycloak-Issuer) kommen aus
assets/hl_server_config.json statt hartcodiertem BackendConfig.prod;
Testumgebung 192.168.1.9:3001 ist dort hinterlegt
- AppBloc laedt die Config, aktiviert die gespeicherte Wahl (Fallback
Default) und registriert das Networking; Wechsel persistiert per
SharedPreferences und registriert neu
- Bloc-Baum ist pro Umgebung gekeyt: beim Wechsel entstehen alle Blocs
mit dem neuen API-Client neu
- Login-Screen: Zahnrad oben rechts oeffnet Einstellungen mit Umgebungs-
Cards (Name + IP:Port); Hinweis auf aktive Umgebung unter dem Button
- Fahrzeugauswahl pro Umgebung getrennt (eigene DB = eigene Car-IDs)
- Tests fuer Config-Parsing, Auswahl-Fallback, Card-Wechsel, Re-Registrierung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Haengt der interaktive Login (Browser-Tab/Token-Exchange) bei Verbindungsabbruch/Issuer-Hang, bricht er nach 10s ab; LoginPage zeigt 'Einloggen nicht moeglich. Spaeter erneut versuchen.' (Unauthenticated.loginTimedOut).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- AuthBootstrapping als neuer Initial-State im AuthBloc. Beim Cold-Start
bleibt die App im Splash, bis restoreSession entweder Authenticated
oder Unauthenticated emittiert — kein sichtbarer LoginPage-Flash mehr
für Nutzer mit gespeicherter Session.
- LoginEnforcer rendert für AuthBootstrapping ein eigenes Splash-Widget
mit Logo + Spinner, für Unauthenticated weiterhin die LoginPage.
- AuthBloc._handleRestore emittiert Unauthenticated explizit, wenn
restoreSession false liefert oder wirft — sonst bliebe der Bootstrap-
State hängen.
- HomeAppDrawer zeigt jetzt displayName + Personalnummer aus dem
Authenticated-State im Header und bekommt einen Abmelden-Eintrag
unten (rot, Confirm-Dialog), der LogoutRequested feuert. Der
Provider löscht den Refresh-Token aus der Secure Storage und der
LoginEnforcer routet automatisch zurück auf die LoginPage.
App-Code:
- KeycloakOidcTokenProvider: PKCE-Login via flutter_appauth, Refresh via
Refresh-Token aus flutter_secure_storage, Session-Restore beim
App-Start, Logout.
- AuthSessionEvent als Provider→Bloc-Brücke (LoggedIn/LoggedOut/
SessionExpired) auf einem Broadcast-Stream.
- AuthBloc komplett umgebaut: nimmt jetzt den KeycloakOidcTokenProvider
statt UserInfoService, mappt eingehende Provider-Events auf eigene
Zustände. Authenticated.fromClaims() liest personalnummer + Name aus
dem ID-Token-Payload.
- LoginPage: kein Browser+Deep-Link mehr — Button feuert
LoginRequested, der Provider übernimmt den restlichen Flow.
- network_locator: produktiver KeycloakOidcTokenProvider, doppelt
registriert (KeycloakOidcTokenProvider für AuthBloc,
AuthTokenProvider für Interceptor).
- Auth-State trägt zusätzlich personalnummer/displayName/email; das
Legacy-User-Objekt + sessionId bleiben temporär drin, damit die
alten ERPframe-Services (Phase D) noch kompilieren.
Plattform-Setup:
- Android: appAuthRedirectScheme=holzleitner in build.gradle.kts,
NetworkSecurityConfig erlaubt HTTP zu localhost/10.0.2.2/127.0.0.1.
- iOS: holzleitner als URL-Scheme im Info.plist, ATS-Ausnahme für
localhost (HTTP-Keycloak im Dev-Setup).
Out of scope:
- Keine echte App-Run-Smoke — kommt mit dem User-Test.
- iOS-pod-install läuft beim ersten 'flutter run ios' automatisch.
- Old ERPframe-Services bleiben aktiv und werfen ab jetzt 401 (kein
Cookie-Session-Token mehr) — wird in Phase D entfernt.