Adds application design (awaiting approval)

This commit is contained in:
2026-06-17 20:15:54 +02:00
parent c7154e288f
commit 9e49489f7e
12 changed files with 1171 additions and 22 deletions
@@ -0,0 +1,151 @@
# 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 16).
**Tech decisions confirmed by user:**
- **State management**: React Context (auth) + TanStack Query (server state)
- **HTTP client**: TanStack Query (server state) using native fetch via `ApiClient` wrapper
- **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
```mermaid
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` |