Files
slp-modular-cms/aidlc-docs/features/cms-frontend/inception/application-design/components.md
T

8.5 KiB
Raw Blame History

Component Definitions — CMS Frontend

Backend Components (Unit 0)

CorsPolicy

  • Purpose: Configure Cross-Origin Resource Sharing for the frontend SPA
  • Responsibilities:
    • Allow the configured frontend origin(s) from appsettings.json → AllowedOrigins
    • Allow credentials (AllowCredentials()) so the browser sends the httpOnly cookie
    • Allow required HTTP methods and headers
  • Location: src/SlpModularCms.Api/Extensions/ServiceCollectionExtensions.cs (extended)
  • Configuration: appsettings.json → Cors:AllowedOrigins[], appsettings.Development.json (dev origins), appsettings.local.json (developer override)

AuthController (updated)

  • Purpose: Authentication HTTP endpoints — updated to set/clear httpOnly cookie
  • Responsibilities:
    • Login: Call IAuthService.AuthenticateAsync(), set refreshToken httpOnly cookie, return access token + user info only in body
    • Refresh: Read refreshToken from cookie (not request body), call IAuthService.RefreshTokenAsync(), set new cookie, return new access token
    • Revoke: Call IAuthService.RevokeTokenAsync() with cookie value, clear the cookie
  • Location: src/SlpModularCms.Modules.Identity/Controllers/AuthController.cs

AuthService (updated)

  • Purpose: Core authentication business logic — updated for cookie-based refresh flow
  • Responsibilities:
    • RefreshTokenAsync(accessToken, refreshToken) — signature unchanged; cookie reading is the controller's responsibility
    • No other changes to service layer

Frontend Components (Units 16)

Infrastructure Layer

ApiClient

  • Purpose: Centralised HTTP client — all API calls go through this module
  • Responsibilities:
    • Base URL from import.meta.env.VITE_API_BASE_URL
    • Attach Authorization: Bearer {accessToken} header on authenticated requests
    • Intercept 401 responses — trigger token refresh via AuthContext.refresh(), retry original request once
    • Expose typed request functions used by TanStack Query
    • Send requests with credentials: 'include' so the browser includes the httpOnly cookie
  • Location: frontend/src/api/client.ts

AuthContext

  • Purpose: React Context providing authentication state to the entire app
  • Responsibilities:
    • Store in-memory accessToken (string | null) — never persisted to localStorage
    • Store authenticated user: { id, email, name, role, isActive }
    • Expose login(email, password), logout(), refresh() methods
    • On app mount: call /auth/refresh via httpOnly cookie to restore session
    • Provide isAuthenticated, isLoading, user, role derived state
  • Location: frontend/src/auth/AuthContext.tsx + frontend/src/auth/useAuth.ts

RouterConfig

  • Purpose: TanStack Router file-based route tree with integrated guards
  • Responsibilities:
    • File-based route structure under frontend/src/routes/
    • Root route checks InitGuard (setup status) before rendering any child
    • Authenticated routes wrapped with ProtectedRoute check
    • Role-specific routes wrapped with RoleGuard check
    • Redirect to /login with ?redirect= param on auth failure
  • Location: frontend/src/routes/ (file-based), frontend/src/routeTree.gen.ts (generated)

Auth & Guard Components

ProtectedRoute

  • Purpose: Redirect unauthenticated users to /login
  • Responsibilities:
    • Read isAuthenticated from AuthContext
    • If not authenticated: redirect to /login?redirect={currentPath}
    • If loading (session restore in progress): show loading spinner — no flash of content
    • If authenticated: render child route
  • Location: frontend/src/auth/ProtectedRoute.tsx

RoleGuard

  • Purpose: Restrict routes to specific roles
  • Responsibilities:
    • Accept allowedRoles: string[] prop
    • Read user.role from AuthContext
    • If role not in allowedRoles: redirect to /403
    • If role allowed: render child route
  • Location: frontend/src/auth/RoleGuard.tsx

InitGuard

  • Purpose: Redirect to /setup if the system is not initialized
  • Responsibilities:
    • On first app render: call GET /setup/status
    • If initialized: false: redirect all routes to /setup
    • If initialized: true: allow normal routing
    • Show loading state during check
    • Handle API failure with error page + retry
  • Location: frontend/src/auth/InitGuard.tsx

Layout Components

AppLayout

  • Purpose: Authenticated shell layout wrapping all protected pages
  • Responsibilities:
    • Render Sidebar on the left + <Outlet /> (page content) on the right
    • Responsive: full sidebar on desktop, collapsed/hamburger on mobile
  • Location: frontend/src/components/layout/AppLayout.tsx

Sidebar

  • Purpose: Navigation sidebar with role-filtered links
  • Responsibilities:
    • Read user.role from AuthContext to filter navigation items
    • Navigation items: Dashboard (all), User Management (Owner/Admin), System Settings (Owner), CMS (Owner), Profile (all)
    • Logout button: calls AuthContext.logout()
    • Theme toggle: calls ThemeProvider.toggle()
    • Highlight active route
    • Collapsible on mobile
  • Location: frontend/src/components/layout/Sidebar.tsx

ThemeProvider

  • Purpose: Dark/light theme management
  • Responsibilities:
    • Wrap app with next-themes provider
    • Persist theme preference in localStorage under key cms-theme
    • Default to system preference
    • Expose useTheme() hook via next-themes
  • Location: frontend/src/components/layout/ThemeProvider.tsx

Page Components

LoginPage (/login)

  • Purpose: Unauthenticated login form
  • Responsibilities: Email + password form, react-hook-form + zod validation, calls AuthContext.login()
  • Location: frontend/src/routes/login.tsx

SetupPage (/setup)

  • Purpose: First-time system initialization form
  • Responsibilities: Email + password form (owner creation), calls POST /setup/owner, redirects to /login on success
  • Location: frontend/src/routes/setup.tsx

InviteCompletePage (/invite/complete)

  • Purpose: Invitation token completion form
  • Responsibilities: Validate token via GET /users/validate-invitation, show display name + password form, call POST /users/complete-setup
  • Location: frontend/src/routes/invite.complete.tsx

DashboardPage (/)

  • Purpose: Authenticated home page
  • Responsibilities: Welcome widget (user name + role), availability status widget (TanStack Query)
  • Location: frontend/src/routes/index.tsx

UsersPage (/users)

  • Purpose: User management page (Owner/Admin only)
  • Responsibilities: User list (TanStack Query), InviteUserDialog (invite form + share link step)
  • Location: frontend/src/routes/users.tsx

ProfilePage (/profile)

  • Purpose: Read-only profile page
  • Responsibilities: Show user.name, user.email, user.role from AuthContext
  • Location: frontend/src/routes/profile.tsx

SettingsPage (/settings)

  • Purpose: System settings page (Owner only)
  • Responsibilities: Show availability status (TanStack Query), show initialized state, placeholder sections
  • Location: frontend/src/routes/settings.tsx

CmsPage (/cms)

  • Purpose: CMS management placeholder (Owner only)
  • Responsibilities: Work-in-progress placeholder with description of future multi-CMS management
  • Location: frontend/src/routes/cms.tsx

NotFoundPage (/404 or catch-all)

  • Purpose: 404 error page
  • Location: frontend/src/routes/$404.tsx

AccessDeniedPage (/403)

  • Purpose: 403 forbidden page shown when role guard fails
  • Location: frontend/src/routes/403.tsx

Shared UI Components

InviteUserDialog

  • Purpose: Modal dialog for inviting a new user
  • Responsibilities: Two-step: (1) invite form with email + role, (2) share invite link with copy button
  • Location: frontend/src/components/users/InviteUserDialog.tsx

AvailabilityStatusBadge

  • Purpose: Colour-coded availability status indicator
  • Responsibilities: Display Available (green) / Maintenance (yellow) / Unavailable (red) with reason
  • Location: frontend/src/components/shared/AvailabilityStatusBadge.tsx

ErrorBoundary (Global + Per-Page)

  • Purpose: Catch unexpected React errors
  • Responsibilities: Global boundary at app root; per-page boundaries for isolated page failures; show user-friendly fallback UI
  • Location: frontend/src/components/error/ErrorBoundary.tsx