6.4 KiB
6.4 KiB
Application Design — CMS Frontend
Overview
This document consolidates the complete application design for the CMS frontend feature. It covers both the backend prerequisite changes (Unit 0) and the full frontend React SPA (Units 1–6).
Tech decisions confirmed by user:
- State management: React Context (auth) + TanStack Query (server state)
- HTTP client: TanStack Query (server state) using native fetch via
ApiClientwrapper - Form validation: react-hook-form + zod
- Routing: TanStack Router — file-based (
src/routes/) - Auth token storage: Access token in-memory (React context), refresh token in httpOnly cookie
- Cookie:
refreshToken, path/api/v1/auth, HttpOnly, Secure, SameSite=Strict - CORS origins: Configured via
appsettings.json → Cors:AllowedOrigins[](dotnet-appsettings pattern) - User data in context: Full user object
{ id, email, name, role, isActive } - Error boundaries: Global + per-page
Architecture at a Glance
graph LR
subgraph FE["Frontend (frontend/)"]
direction TB
Infra["Infrastructure\nApiClient · AuthContext · RouterConfig"]
Guards["Guards\nProtectedRoute · RoleGuard · InitGuard"]
Layout["Layout\nAppLayout · Sidebar · ThemeProvider"]
Hooks["TanStack Query Hooks\nuseAvailability · useUsers · useInvitation · useSetup"]
Pages["Pages\nLogin · Setup · InviteComplete\nDashboard · Users · Profile\nSettings · CMS · 403 · 404"]
end
subgraph BE["Backend (src/)"]
direction TB
CORS["CORS Policy\n(ServiceCollectionExtensions)"]
AuthCtrl["AuthController\n(httpOnly cookie)"]
AuthSvc["AuthService"]
end
Pages --> Hooks
Pages --> Infra
Layout --> Infra
Guards --> Infra
Hooks --> Infra
Infra -->|HTTP + cookie| AuthCtrl
AuthCtrl --> AuthSvc
style Infra fill:#FFC107,stroke:#F57F17,color:#000
style Guards fill:#FF5722,stroke:#BF360C,color:#fff
style Layout fill:#9C27B0,stroke:#4A148C,color:#fff
style Hooks fill:#009688,stroke:#004D40,color:#fff
style Pages fill:#2196F3,stroke:#0D47A1,color:#fff
style CORS fill:#4CAF50,stroke:#2E7D32,color:#fff
style AuthCtrl fill:#4CAF50,stroke:#2E7D32,color:#fff
style AuthSvc fill:#FFC107,stroke:#F57F17,color:#000
Unit Decomposition Summary
| Unit | Name | Primary Components |
|---|---|---|
| 0 | Backend Prerequisites | CorsPolicy, AuthController (cookie), appsettings updates |
| 1 | Project Scaffold | ApiClient, AuthContext, RouterConfig, ThemeProvider, ErrorBoundary, .env |
| 2 | Auth Pages | LoginPage, SetupPage, InviteCompletePage, ProtectedRoute, RoleGuard, InitGuard |
| 3 | Layout & Navigation | AppLayout, Sidebar |
| 4 | Dashboard | DashboardPage, AvailabilityStatusBadge, useAvailabilityStatus |
| 5 | User Management | UsersPage, InviteUserDialog, useUsers, useInviteUser, useValidateInvitation, useCompleteSetup |
| 6 | Remaining Pages | ProfilePage, SettingsPage, CmsPage, NotFoundPage, AccessDeniedPage, README.md |
Project Structure
frontend/
├── src/
│ ├── api/
│ │ ├── client.ts # ApiClient (fetch wrapper, 401 interceptor)
│ │ ├── types.ts # Shared TypeScript interfaces
│ │ ├── useAvailability.ts # TanStack Query hooks
│ │ ├── useUsers.ts
│ │ ├── useInvitation.ts
│ │ └── useSetup.ts
│ ├── auth/
│ │ ├── AuthContext.tsx # AuthContext + AuthProvider
│ │ ├── useAuth.ts # useAuth hook
│ │ ├── ProtectedRoute.tsx
│ │ ├── RoleGuard.tsx
│ │ └── InitGuard.tsx
│ ├── components/
│ │ ├── layout/
│ │ │ ├── AppLayout.tsx
│ │ │ ├── Sidebar.tsx
│ │ │ └── ThemeProvider.tsx
│ │ ├── users/
│ │ │ └── InviteUserDialog.tsx
│ │ ├── shared/
│ │ │ └── AvailabilityStatusBadge.tsx
│ │ └── error/
│ │ └── ErrorBoundary.tsx
│ ├── routes/ # TanStack Router file-based routes
│ │ ├── __root.tsx # Root route (InitGuard, ErrorBoundary)
│ │ ├── index.tsx # / → DashboardPage
│ │ ├── login.tsx # /login
│ │ ├── setup.tsx # /setup
│ │ ├── invite.complete.tsx # /invite/complete
│ │ ├── users.tsx # /users (Owner/Admin)
│ │ ├── profile.tsx # /profile
│ │ ├── settings.tsx # /settings (Owner)
│ │ ├── cms.tsx # /cms (Owner)
│ │ ├── 403.tsx # /403
│ │ └── $404.tsx # catch-all
│ ├── routeTree.gen.ts # Generated by TanStack Router CLI
│ ├── main.tsx # App entry point
│ └── app.tsx # QueryClientProvider + AuthProvider + RouterProvider
├── .env.example # Template for VITE_API_BASE_URL
├── .env # gitignored — developer local override
├── package.json
├── pnpm-lock.yaml
├── tsconfig.json
├── vite.config.ts
└── tailwind.config.ts
Security Design Summary
| Concern | Design Decision |
|---|---|
| Access token storage | In-memory only (React state in AuthContext) |
| Refresh token storage | httpOnly cookie — set/cleared by backend |
| CORS | Named policy "FrontendPolicy" with specific origins + AllowCredentials() |
| Role enforcement | RoleGuard (routing) + Sidebar (UX) + backend (authoritative) |
| HTTP calls | Centralised through ApiClient only |
| Form validation | zod schemas matching backend password rules |
| Error handling | Global + per-page ErrorBoundary; generic user-facing error messages |
Artifacts Index
| Artifact | Path |
|---|---|
| Component definitions | inception/application-design/components.md |
| Method signatures | inception/application-design/component-methods.md |
| Service layer | inception/application-design/services.md |
| Dependency diagram | inception/application-design/component-dependency.md |
| This document | inception/application-design/application-design.md |