fix(frontend): Session-Timeout ausgeloggt statt in kaputtem Zustand stecken
CI / backend-tests (push) Successful in 3m18s
CI / frontend-build (push) Successful in 22s

401 bei abgelaufenem Token wurde nirgends erkannt - "eingeloggt" blieb true,
Hard-Reload half nicht, da der abgelaufene Token weiter in localStorage lag
und /auth/me erneut mit 401 scheiterte (gleicher Zustand auf derselben URL).
apiRequest ruft jetzt bei echtem Session-Timeout einen von AuthProvider
registrierten Handler auf, der korrekt auf logout() setzt - Router-Guard
leitet danach automatisch zu /login um.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VDMvneg6wKfXdXvTYNd3dN
This commit is contained in:
patrickandClaude Sonnet 5 committed 2026-09-12 22:33:20 +02:00
1 parent c8d9480cf9
commit 9312d6a17c
4 files changed
+117 -1

No files matched your search

+70
View File
@@ -14999,3 +14999,73 @@ Keine Commits in dieser Session.
- flutter_app/test/offline_queue_test.dart | 6 ++++
---
## 2026-09-12 22:21 – 22:23 (1m)
**Beschreibung:** Claude Code Session
**Projekt:** asb-material
### Commits
- c8d9480 perf(mangel): Foto-Kompression vor Upload in beiden Clients ergänzt
### Geänderte Dateien
- DEVLOG.md | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- flutter_app/lib/screens/mangel_melden_screen.dart | 12 +++-
- frontend/src/offline/fotoKomprimierung.ts | 34 ++++++++++++
- frontend/src/pages/MangelListePage.tsx | 6 +-
---
## 2026-09-12 22:23 – 22:24 (0m)
**Beschreibung:** Claude Code Session
**Projekt:** asb-material
### Commits
Keine Commits in dieser Session.
### Geänderte Dateien
- DEVLOG.md | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- flutter_app/lib/screens/mangel_melden_screen.dart | 12 +++-
- frontend/src/offline/fotoKomprimierung.ts | 34 ++++++++++++
- frontend/src/pages/MangelListePage.tsx | 6 +-
---
## 2026-09-12 22:24 – 22:24 (0m)
**Beschreibung:** Claude Code Session
**Projekt:** asb-material
### Commits
Keine Commits in dieser Session.
### Geänderte Dateien
- DEVLOG.md | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- flutter_app/lib/screens/mangel_melden_screen.dart | 12 +++-
- frontend/src/offline/fotoKomprimierung.ts | 34 ++++++++++++
- frontend/src/pages/MangelListePage.tsx | 6 +-
---
## 2026-09-12 22:28 – 22:28 (0m)
**Beschreibung:** Claude Code Session
**Projekt:** asb-material
### Commits
Keine Commits in dieser Session.
### Geänderte Dateien
- DEVLOG.md | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- flutter_app/lib/screens/mangel_melden_screen.dart | 12 +++-
- frontend/src/offline/fotoKomprimierung.ts | 34 ++++++++++++
- frontend/src/pages/MangelListePage.tsx | 6 +-
---
## 2026-09-12 22:32 – 22:33 (0m)
**Beschreibung:** Claude Code Session
**Projekt:** frontend
### Commits
Keine Commits in dieser Session.
### Geänderte Dateien
- DEVLOG.md | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- flutter_app/lib/screens/mangel_melden_screen.dart | 12 +++-
- frontend/src/offline/fotoKomprimierung.ts | 34 ++++++++++++
- frontend/src/pages/MangelListePage.tsx | 6 +-
---
+14
View File
@@ -1292,3 +1292,17 @@ Keine Commits in dieser Session.
- frontend/src/pages/admin/objektZeileTypen.ts | 43 ++++++++++++
---
## 2026-09-12 22:30 – 22:31 (1m)
**Beschreibung:** Claude Code Session
**Projekt:** asb-material
### Commits
Keine Commits in dieser Session.
### Geänderte Dateien
- DEVLOG.md | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- flutter_app/lib/screens/mangel_melden_screen.dart | 12 +++-
- frontend/src/offline/fotoKomprimierung.ts | 34 ++++++++++++
- frontend/src/pages/MangelListePage.tsx | 6 +-
---
+18
View File
@@ -15,6 +15,19 @@ export function getAuthToken(): string | null {
return authToken;
}
// Bug-Fund: Session-Timeout (Token abgelaufen) wurde bisher NIRGENDS erkannt -
// apiRequest warf zwar ApiError(401), aber "eingeloggt" im AuthContext blieb
// true, da niemand darauf reagierte. Ein Hard-Reload half nicht, weil der
// (abgelaufene) Token weiter in localStorage lag und /auth/me erneut mit 401
// scheiterte - derselbe kaputte Zustand auf derselben URL. AuthProvider trägt
// sich hier als Handler ein, um bei echtem Session-Timeout (nicht beim
// Login-Versuch selbst, siehe Ausschluss in apiRequest) auszuloggen.
let unauthorizedHandler: (() => void) | null = null;
export function setUnauthorizedHandler(handler: (() => void) | null): void {
unauthorizedHandler = handler;
}
export class ApiError extends Error {
status: number;
detail: unknown;
@@ -55,6 +68,11 @@ export async function apiRequest<T>(path: string, options: RequestOptions = {}):
} catch {
// Antwort ohne JSON-Body (z. B. 204) - detail bleibt null.
}
// Nur bei tatsächlich gesendetem Token auslösen - ein 401 ohne Token
// (z.B. noch vor dem Login) ist kein Session-Timeout.
if (response.status === 401 && authToken) {
unauthorizedHandler?.();
}
throw new ApiError(response.status, detail);
}
+15 -1
View File
@@ -1,6 +1,12 @@
import { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from "react";
import { apiRequest, getAuthToken, login as apiLogin, setAuthToken } from "../api/client";
import {
apiRequest,
getAuthToken,
login as apiLogin,
setAuthToken,
setUnauthorizedHandler,
} from "../api/client";
import type { Me } from "../api/types";
interface AuthContextValue {
@@ -69,6 +75,14 @@ export function AuthProvider({ children }: { children: ReactNode }) {
[eingeloggt, rollenGeladen, rollen]
);
// Bug-Fund: Session-Timeout wurde bisher nicht erkannt - siehe Kommentar in
// api/client.ts. Registrierung statt direktem Aufruf in apiRequest, da
// apiRequest außerhalb des React-Baums liegt und keinen Hook-Zugriff hat.
useEffect(() => {
setUnauthorizedHandler(value.logout);
return () => setUnauthorizedHandler(null);
}, [value.logout]);
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}