diff --git a/frontend/src/components/common/ProtectedRoute.tsx b/frontend/src/components/common/ProtectedRoute.tsx
index 0016ed9..c8afa17 100644
--- a/frontend/src/components/common/ProtectedRoute.tsx
+++ b/frontend/src/components/common/ProtectedRoute.tsx
@@ -1,6 +1,7 @@
import React from 'react';
import { Navigate } from 'react-router-dom';
import { usePermission } from '@/hooks/usePermission';
+import { useAuthStore } from '@/store/authStore';
interface ProtectedRouteProps {
permission: string;
@@ -9,6 +10,19 @@ interface ProtectedRouteProps {
export function ProtectedRoute({ permission, children }: ProtectedRouteProps) {
const { hasPermission } = usePermission();
+ const user = useAuthStore((state) => state.user);
+
+ // If user is system admin, always allow
+ if (user?.is_system_admin) {
+ return <>{children}>;
+ }
+
+ // If permissions array is empty or not loaded yet, allow access
+ // (better to show page and let backend 403 handle it than block everything)
+ const perms = user?.permissions || [];
+ if (perms.length === 0) {
+ return <>{children}>;
+ }
if (!hasPermission(permission)) {
return ;
diff --git a/frontend/src/pages/NoAccessPage.tsx b/frontend/src/pages/NoAccessPage.tsx
new file mode 100644
index 0000000..e457b32
--- /dev/null
+++ b/frontend/src/pages/NoAccessPage.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { ShieldX } from 'lucide-react';
+
+export default function NoAccessPage() {
+ return (
+
+
+
Kein Zugriff
+
+ Sie haben keine Berechtigung, auf diese Seite zuzugreifen.
+ Bitte wenden Sie sich an einen Administrator, falls Sie Zugriff benötigen.
+
+
+ Zum Dashboard
+
+
+ );
+}
diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx
index 267ab02..67cacbb 100644
--- a/frontend/src/routes/index.tsx
+++ b/frontend/src/routes/index.tsx
@@ -64,6 +64,7 @@ const ActivityTimelinePage = React.lazy(() => import('@/pages/ActivityTimeline')
const SettingsWebhooksPage = React.lazy(() => import('@/pages/SettingsWebhooks').then(m => ({ default: m.SettingsWebhooksPage })));
const SettingsBackupPage = React.lazy(() => import('@/pages/SettingsBackup').then(m => ({ default: m.SettingsBackupPage })));
const SettingsRechtePage = React.lazy(() => import('@/pages/SettingsRechte').then(m => ({ default: m.SettingsRechtePage })));
+const NoAccessPage = React.lazy(() => import('@/pages/NoAccessPage').then(m => ({ default: m.NoAccessPage })));
/** Centered spinner fallback for lazy-loaded routes */
function PageLoader() {
@@ -120,6 +121,10 @@ const router = createBrowserRouter([
path: '/guest/contacts',
element: ,
},
+ {
+ path: '/kein-zugriff',
+ element: {withSuspense()},
+ },
{
element: (