feat: F002 authentication & session layer
Add permission matrix, ProtectedRoute, RoleGuard, PermissionGate, DemoRoleSwitcher, OrganizationSwitcher, AccessDenied, SessionExpired, and institutional LoginScreen. Wire workspace-level route protection into App.tsx; sidebar filters tabs by allowedWorkspaces. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+34
-18
@@ -2,6 +2,10 @@ import { lazy, Suspense } from 'react'
|
||||
import { Routes, Route, Navigate } from 'react-router'
|
||||
import { LoadingPage, AppErrorBoundary } from './components/ui'
|
||||
import { AppShell } from './components/layout'
|
||||
import { ProtectedRoute } from './components/auth'
|
||||
import { WorkspaceType } from './domain/enums'
|
||||
|
||||
const LoginScreen = lazy(() => import('./pages/auth/LoginScreen'))
|
||||
|
||||
const SupplyDashboard = lazy(() => import('./pages/supply/SupplyDashboard'))
|
||||
const Properties = lazy(() => import('./pages/supply/Properties'))
|
||||
@@ -24,27 +28,39 @@ function App() {
|
||||
<AppErrorBoundary>
|
||||
<Suspense fallback={<LoadingPage />}>
|
||||
<Routes>
|
||||
<Route element={<AppShell />}>
|
||||
<Route path="/" element={<Navigate to="/supply/dashboard" replace />} />
|
||||
{/* Public */}
|
||||
<Route path="/auth/login" element={<LoginScreen />} />
|
||||
|
||||
{/* Supply Workspace */}
|
||||
<Route path="/supply/dashboard" element={<SupplyDashboard />} />
|
||||
<Route path="/supply/properties" element={<Properties />} />
|
||||
<Route path="/supply/match-center" element={<MatchCenter />} />
|
||||
<Route path="/supply/future-availability" element={<FutureAvailability />} />
|
||||
<Route path="/supply/data-quality" element={<DataQuality />} />
|
||||
{/* Protected: auth check only */}
|
||||
<Route element={<ProtectedRoute />}>
|
||||
<Route element={<AppShell />}>
|
||||
<Route path="/" element={<Navigate to="/supply/dashboard" replace />} />
|
||||
|
||||
{/* Demand Workspace */}
|
||||
<Route path="/demand/ai-search" element={<AISearch />} />
|
||||
<Route path="/demand/results" element={<Results />} />
|
||||
<Route path="/demand/compare" element={<Compare />} />
|
||||
<Route path="/demand/shortlists" element={<Shortlists />} />
|
||||
{/* Supply Workspace */}
|
||||
<Route element={<ProtectedRoute workspace={WorkspaceType.SUPPLY} />}>
|
||||
<Route path="/supply/dashboard" element={<SupplyDashboard />} />
|
||||
<Route path="/supply/properties" element={<Properties />} />
|
||||
<Route path="/supply/match-center" element={<MatchCenter />} />
|
||||
<Route path="/supply/future-availability" element={<FutureAvailability />} />
|
||||
<Route path="/supply/data-quality" element={<DataQuality />} />
|
||||
</Route>
|
||||
|
||||
{/* Operations Workspace */}
|
||||
<Route path="/ops/review-queue" element={<ReviewQueue />} />
|
||||
<Route path="/ops/ai-monitoring" element={<AIMonitoring />} />
|
||||
<Route path="/ops/governance" element={<Governance />} />
|
||||
<Route path="/ops/activity-timeline" element={<ActivityTimeline />} />
|
||||
{/* Demand Workspace */}
|
||||
<Route element={<ProtectedRoute workspace={WorkspaceType.DEMAND} />}>
|
||||
<Route path="/demand/ai-search" element={<AISearch />} />
|
||||
<Route path="/demand/results" element={<Results />} />
|
||||
<Route path="/demand/compare" element={<Compare />} />
|
||||
<Route path="/demand/shortlists" element={<Shortlists />} />
|
||||
</Route>
|
||||
|
||||
{/* Operations Workspace */}
|
||||
<Route element={<ProtectedRoute workspace={WorkspaceType.OPERATIONS} />}>
|
||||
<Route path="/ops/review-queue" element={<ReviewQueue />} />
|
||||
<Route path="/ops/ai-monitoring" element={<AIMonitoring />} />
|
||||
<Route path="/ops/governance" element={<Governance />} />
|
||||
<Route path="/ops/activity-timeline" element={<ActivityTimeline />} />
|
||||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
|
||||
<Route path="*" element={<Navigate to="/" replace />} />
|
||||
|
||||
Reference in New Issue
Block a user