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

113 lines
4.6 KiB
Markdown

# Services — CMS Frontend
## Service Architecture Overview
The frontend uses **TanStack Query** as the server-state service layer. All API interactions are encapsulated in typed query/mutation hooks. The `ApiClient` handles transport concerns (headers, 401 retry). `AuthContext` manages session state. There is no additional service abstraction layer needed.
---
## Backend Services (Unit 0 changes)
### CORS Service (new)
- **Service**: `ServiceCollectionExtensions.AddCorsFrontendPolicy()`
- **Purpose**: Register named CORS policy `"FrontendPolicy"` for frontend SPA
- **Configuration source**: `IConfiguration``Cors:AllowedOrigins` array
- **Key settings**:
- `WithOrigins(allowedOrigins)` — from config
- `AllowAnyHeader()` + `AllowAnyMethod()`
- `AllowCredentials()` — required for httpOnly cookie
- **dotnet-appsettings pattern**: `AllowedOrigins` stored in `appsettings.json` (production) and `appsettings.Development.json` (dev, e.g. `["http://localhost:5173"]`); `appsettings.local.json` for developer-specific overrides
---
## Frontend Services (TanStack Query hooks)
### Auth Service (`frontend/src/auth/`)
**AuthContext** functions as the auth service — it is the single source of truth for authentication state.
| Operation | Implementation | Notes |
|-----------|----------------|-------|
| Login | `POST /api/v1/auth/login` → stores `accessToken` in memory | httpOnly cookie set by server |
| Session restore | `POST /api/v1/auth/refresh` on app mount → stores new `accessToken` | Reads cookie automatically |
| Logout | `POST /api/v1/auth/revoke` → clears in-memory token | Server clears cookie |
| Token refresh (interceptor) | `POST /api/v1/auth/refresh` on 401 → retry original request | Centralised in ApiClient |
### Availability Service (`frontend/src/api/useAvailability.ts`)
| Hook | Query key | Endpoint | Stale time |
|------|-----------|----------|-----------|
| `useAvailabilityStatus()` | `['availability', 'status']` | `GET /api/v1/availability/status` | 30s |
### Users Service (`frontend/src/api/useUsers.ts`)
| Hook | Query key | Endpoint | Notes |
|------|-----------|----------|-------|
| `useUsers()` | `['users']` | `GET /api/v1/users` | Owner/Admin only |
| `useInviteUser()` | mutation | `POST /api/v1/users/invite` | Invalidates `['users']` on success |
### Invitation Service (`frontend/src/api/useInvitation.ts`)
| Hook | Query key | Endpoint | Notes |
|------|-----------|----------|-------|
| `useValidateInvitation(token)` | `['invitation', token]` | `GET /api/v1/users/validate-invitation?token=` | Public, no auth |
| `useCompleteSetup()` | mutation | `POST /api/v1/users/complete-setup` | Public, no auth |
### Setup Service (`frontend/src/api/useSetup.ts`)
| Hook | Query key | Endpoint | Notes |
|------|-----------|----------|-------|
| `useSetupStatus()` | `['setup', 'status']` | `GET /api/v1/setup/status` | Used by `InitGuard` |
| `useCreateOwner()` | mutation | `POST /api/v1/setup/owner` | Used on `/setup` page |
---
## Service Interaction Diagram
```mermaid
graph TD
App["App Entry\n(main.tsx)"]
InitGuard["InitGuard\n(useSetupStatus)"]
AuthCtx["AuthContext\n(session state)"]
ApiClient["ApiClient\n(fetch + 401 retry)"]
Router["TanStack Router\n(ProtectedRoute + RoleGuard)"]
subgraph Pages["Page Components"]
Login["LoginPage"]
Dashboard["DashboardPage\n(useAvailabilityStatus)"]
Users["UsersPage\n(useUsers, useInviteUser)"]
Invite["InviteCompletePage\n(useValidateInvitation\nuseCompleteSetup)"]
Settings["SettingsPage\n(useAvailabilityStatus)"]
Profile["ProfilePage"]
end
App --> InitGuard
App --> AuthCtx
InitGuard -->|initialized| Router
Router --> Login
Router --> Dashboard
Router --> Users
Router --> Invite
Router --> Settings
Router --> Profile
AuthCtx -->|getAccessToken| ApiClient
AuthCtx -->|refresh| ApiClient
Dashboard --> ApiClient
Users --> ApiClient
Invite --> ApiClient
Settings --> ApiClient
style App fill:#CE93D8,stroke:#6A1B9A,color:#000
style InitGuard fill:#FFC107,stroke:#F57F17,color:#000
style AuthCtx fill:#FFC107,stroke:#F57F17,color:#000
style ApiClient fill:#FFC107,stroke:#F57F17,color:#000
style Router fill:#4CAF50,stroke:#2E7D32,color:#fff
style Login fill:#2196F3,stroke:#0D47A1,color:#fff
style Dashboard fill:#2196F3,stroke:#0D47A1,color:#fff
style Users fill:#2196F3,stroke:#0D47A1,color:#fff
style Invite fill:#2196F3,stroke:#0D47A1,color:#fff
style Settings fill:#2196F3,stroke:#0D47A1,color:#fff
style Profile fill:#2196F3,stroke:#0D47A1,color:#fff
```