Routing
The Cloud Frontend uses React Router 6 with nested routes. The root route tree is defined in Frontend/src/App.tsx.
Route guard components
Section titled “Route guard components”| Component | File | Purpose |
|---|---|---|
ProtectedRoute | src/routes/ProtectedRoute.tsx | Requires authenticated user. Waits for Zustand persistence hydration before redirecting. |
PublicOnlyRoute | src/routes/PublicOnlyRoute.tsx | Redirects authenticated users away from login/register. |
PlatformAdminRoute | src/routes/PlatformAdminRoute.tsx | Requires user email domain to match VITE_PLATFORM_ADMIN_EMAIL_DOMAIN. |
PermissionGuard | src/routes/PermissionGuard.tsx | Wraps individual routes that require a specific RBAC permission. |
SessionRestore | src/components/SessionRestore.tsx | Runs POST /api/v1/auth/refresh on reload if user is known but access token is missing. Blocks <Outlet /> until token is restored. |
Route tree (simplified)
Section titled “Route tree (simplified)”/ → Dashboard (ProtectedRoute)│├── /login → PublicOnlyRoute → Login page├── /register → PublicOnlyRoute → Registration├── /auth/callback → OAuth callback handler (stores token, redirects)├── /invite/:token → Invitation acceptance│├── /assets/* → ProtectedRoute + PermissionGuard(assets:read)├── /sites/* → ProtectedRoute + PermissionGuard(sites:read)├── /zones/* → ProtectedRoute + PermissionGuard(assets:read)├── /vlans/* → ProtectedRoute + PermissionGuard(assets:read)│├── /incidents/* → ProtectedRoute + PermissionGuard(incidents:read)├── /problems/* → ProtectedRoute + PermissionGuard(problems:read)├── /changes/* → ProtectedRoute + PermissionGuard(changes:read)├── /releases/* → ProtectedRoute + PermissionGuard(releases:read)├── /service-requests/* → ProtectedRoute + PermissionGuard(service-requests:read)├── /maintenance/* → ProtectedRoute + PermissionGuard(maintenance:read)│├── /knowledge/* → ProtectedRoute + PermissionGuard(knowledge:read)├── /diagrams/* → ProtectedRoute + PermissionGuard(diagrams:read)├── /vulnerabilities/* → ProtectedRoute + PermissionGuard(vulnerabilities:read)├── /vendors/* → ProtectedRoute + PermissionGuard(vendors:read)│├── /security/* → ProtectedRoute + FeatureGuard(security) + PermissionGuard(security:read)├── /vpn/* → ProtectedRoute + FeatureGuard(vpn) + PermissionGuard(vpn:read)├── /backup/* → ProtectedRoute + FeatureGuard(backup) + PermissionGuard(backup:read)│├── /settings/* → ProtectedRoute + PermissionGuard(settings:read)├── /admin/* → PlatformAdminRoute + VITE_ADMIN_PANEL_ENABLED│└── /public/vendor-assessments/:token → No auth (vendor portal)Session hydration on reload
Section titled “Session hydration on reload”React Router 6 renders routes synchronously on mount. Without guarding against hydration delay, protected routes redirect to /login on page reload before the Zustand store is populated from localStorage.
The fix: ProtectedRoute, PublicOnlyRoute, and PlatformAdminRoute all call useAuthStore.persist.hasHydrated() and render a loading spinner until hydration is complete. After hydration, if user exists but access_token is absent (common after F5), SessionRestore fires a refresh request before <Outlet /> renders.
Import alias
Section titled “Import alias”All internal imports use the ~/ alias, which maps to src/:
import { incidentsApi } from '~/lib/api/incidents';import { authStore } from '~/lib/stores/authStore';Configured in vite.config.ts and tsconfig.json.