Adds unit 1 functional design and answered nfr requirements questions and plan
This commit is contained in:
+86
@@ -0,0 +1,86 @@
|
||||
# Business Logic Model — Unit 1: Project Scaffold & Infrastructure
|
||||
|
||||
This model describes the core application flows for the frontend scaffold based on your choices:
|
||||
- Package manager: pnpm
|
||||
- Router: TanStack Router
|
||||
- UI: Tailwind v4 + shadcn/ui (primary color #ac0000)
|
||||
- HTTP: Fetch-based ApiClient with `credentials: 'include'`
|
||||
- Session: Silent refresh on app mount (httpOnly cookie), access token in memory
|
||||
- Lint/format: ESLint + Prettier (4 spaces indentation)
|
||||
|
||||
## 1) App Initialization + Silent Refresh (Session Bootstrap)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant A as App (main.tsx)
|
||||
participant R as Router (TanStack)
|
||||
participant C as AuthContext
|
||||
participant H as ApiClient (fetch)
|
||||
participant B as Backend API
|
||||
|
||||
A->>R: Create Router + Providers
|
||||
A->>H: silentRefresh() with credentials: include
|
||||
H->>B: POST /api/v1/auth/refresh (cookie only)
|
||||
alt 200 OK
|
||||
B-->>H: { accessToken, expiresAt, user }
|
||||
H-->>C: setAuth(user, accessToken, expiresAt)
|
||||
C-->>R: set state: authenticated
|
||||
else 401 Unauthorized
|
||||
B-->>H: 401
|
||||
H-->>C: clearAuth()
|
||||
C-->>R: set state: guest
|
||||
end
|
||||
```
|
||||
|
||||
Text alternative: Bij het starten vraagt de app een silent refresh via cookie; bij succes wordt de gebruiker/auth-state gezet, anders blijft de app in guest-modus.
|
||||
|
||||
## 2) Protected Request Flow with 401 Intercept + Retry
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
UI[UI Component<br/>useAuth/useQuery] -->|call ApiClient| API[ApiClient fetch<br/>Authorization: Bearer]
|
||||
API -->|200 OK| OK[Resolve Promise]
|
||||
API -->|401| RFR[Try Refresh via Cookie]
|
||||
RFR -->|200 OK| TOK[Update in-memory token]
|
||||
TOK --> RETRY[Retry original request]
|
||||
RFR -->|401| OUT[Clear auth + Redirect /login]
|
||||
|
||||
classDef ui fill:#c6f6d5,stroke:#22543d,stroke-width:2px,color:#22543d;
|
||||
classDef infra fill:#cbd5e0,stroke:#1a202c,stroke-width:2px,color:#1a202c;
|
||||
classDef ok fill:#9ae6b4,stroke:#22543d,stroke-width:2px,color:#22543d;
|
||||
classDef warn fill:#fde68a,stroke:#92400e,stroke-width:2px,color:#92400e;
|
||||
classDef err fill:#feb2b2,stroke:#742a2a,stroke-width:2px,color:#742a2a;
|
||||
|
||||
class UI ui;
|
||||
class API infra;
|
||||
class OK ok;
|
||||
class RFR warn;
|
||||
class TOK ok;
|
||||
class RETRY infra;
|
||||
class OUT err;
|
||||
```
|
||||
|
||||
Text alternative: Een beveiligd verzoek gebruikt het in-memory access token; bij 401 wordt een refresh via cookie geprobeerd en vervolgens herhaald; als dat faalt volgt een logout/redirect.
|
||||
|
||||
## 3) Routing Shell (Layouts + Guards)
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
Root[__root.tsx<br/>Providers: QueryClient + AuthContext] --> Guard[Init/Silent Refresh]
|
||||
Guard -->|guest| Pub[Public routes: /login, /setup]
|
||||
Guard -->|auth| Auth[_authenticated.tsx<br/>AppLayout + Sidebar]
|
||||
Auth --> Dash[Dashboard]
|
||||
Auth --> Users[Users]
|
||||
Auth --> Profile[Profile]
|
||||
|
||||
|
||||
classDef rootElement fill:#e9d5ff,stroke:#6b21a8,stroke-width:2px,color:#6b21a8;
|
||||
classDef guard fill:#fde68a,stroke:#92400e,stroke-width:2px,color:#92400e;
|
||||
classDef route fill:#c6f6d5,stroke:#22543d,stroke-width:2px,color:#22543d;
|
||||
|
||||
class Root rootElement;
|
||||
class Guard guard;
|
||||
class Pub,Auth,Dash,Users,Profile route;
|
||||
```
|
||||
|
||||
Text alternative: De root route initialiseert providers; een guard bepaalt guest vs authenticated en leidt naar publieke of beschermde routes (AppLayout met Sidebar).
|
||||
Reference in New Issue
Block a user