diff --git a/DEVLOG.md b/DEVLOG.md
index c891b1c..02b6a82 100644
--- a/DEVLOG.md
+++ b/DEVLOG.md
@@ -6658,3 +6658,17 @@ Keine Commits in dieser Session.
- frontend/src/styles/global.css | 2 ++
---
+## 2026-09-07 14:03 – 14:07 (4m)
+**Beschreibung:** Claude Code Session
+**Projekt:** frontend
+
+### Commits
+- 6db571f fix(dashboard): Resize-Griff war unsichtbar - children-Injection landete in falscher Ebene
+
+### Geänderte Dateien
+- DEVLOG.md | 14 ++++++++++++++
+- frontend/DEVLOG.md | 14 ++++++++++++++
+- frontend/src/pages/dashboard/DashboardPage.tsx | 5 ++---
+- frontend/src/pages/dashboard/TileFrame.tsx | 13 ++++++++++---
+
+---
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 70ac7fc..1a13883 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -21,16 +21,25 @@ function GeschuetzteRoute({ children }: { children: ReactNode }) {
}
function Startseite() {
- const { eingeloggt, istVerantwortlich } = useAuth();
+ const { eingeloggt, istVerantwortlich, rollenGeladen } = useAuth();
if (!eingeloggt) return ;
+ // Ohne dieses Warten würde bei bereits eingeloggter Session (Reload/Direktaufruf)
+ // kurz mit rollen=[] entschieden und fälschlich auf /objekte redirected, bevor
+ // /auth/me durch ist.
+ if (!rollenGeladen) return null;
return ;
}
function AdminRoute({ children }: { children: ReactNode }) {
- const { eingeloggt, istVerantwortlich } = useAuth();
+ const { eingeloggt, istVerantwortlich, rollenGeladen } = useAuth();
if (!eingeloggt) {
return ;
}
+ // Gleiches Race wie in Startseite: bei Direktaufruf/Reload noch nicht auf
+ // rollen=[] entscheiden, sonst kurzzeitig fälschlicher Redirect.
+ if (!rollenGeladen) {
+ return null;
+ }
// Nicht mehr admin-exklusiv: Materialverantwortliche/Leitungsverantwortliche
// dürfen rein, sehen dort aber nur die für sie freigeschalteten Tabs
// (AdminPage filtert selbst nach Rolle, Backend erzwingt es ohnehin je Endpunkt).
diff --git a/frontend/src/auth/AuthContext.tsx b/frontend/src/auth/AuthContext.tsx
index 676b592..5424de1 100644
--- a/frontend/src/auth/AuthContext.tsx
+++ b/frontend/src/auth/AuthContext.tsx
@@ -5,6 +5,12 @@ import type { Me } from "../api/types";
interface AuthContextValue {
eingeloggt: boolean;
+ // Beim Direktladen/Reload einer bereits eingeloggten Session ist "eingeloggt"
+ // sofort true (Token liegt im Storage), "rollen" aber noch [] bis /auth/me
+ // durch ist - ohne dieses Flag würden Startseite/AdminRoute in genau diesem
+ // Fenster fälschlich "istVerantwortlich=false" annehmen und auf /objekte
+ // redirecten, obwohl die echten Rollen kurz danach eintreffen.
+ rollenGeladen: boolean;
rollen: string[];
istAdmin: boolean;
// Rollen-Vorgabe: Materialverantwortliche/Leitungsverantwortliche sahen bisher
@@ -23,20 +29,25 @@ const AuthContext = createContext(null);
export function AuthProvider({ children }: { children: ReactNode }) {
const [eingeloggt, setEingeloggt] = useState(getAuthToken() !== null);
const [rollen, setRollen] = useState([]);
+ const [rollenGeladen, setRollenGeladen] = useState(false);
useEffect(() => {
if (!eingeloggt) {
setRollen([]);
+ setRollenGeladen(true);
return;
}
+ setRollenGeladen(false);
apiRequest("/auth/me")
.then((me) => setRollen(me.rollen))
- .catch(() => setRollen([]));
+ .catch(() => setRollen([]))
+ .finally(() => setRollenGeladen(true));
}, [eingeloggt]);
const value = useMemo(
() => ({
eingeloggt,
+ rollenGeladen,
rollen,
istAdmin: rollen.includes("administration"),
istMaterialverantwortlich: rollen.includes("materialverantwortlicher"),
@@ -55,7 +66,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
setEingeloggt(false);
},
}),
- [eingeloggt, rollen]
+ [eingeloggt, rollenGeladen, rollen]
);
return {children};