diff --git a/aidlc-docs/features/cms-frontend/construction/plans/unit-1-functional-design-plan.md b/aidlc-docs/features/cms-frontend/construction/plans/unit-1-functional-design-plan.md index 6a808ce..146e483 100644 --- a/aidlc-docs/features/cms-frontend/construction/plans/unit-1-functional-design-plan.md +++ b/aidlc-docs/features/cms-frontend/construction/plans/unit-1-functional-design-plan.md @@ -10,7 +10,7 @@ - Provide `ApiClient` and `AuthContext` foundations aligned with cookie-based auth (httpOnly refresh cookie, access token in memory) ## Plan Checklist -- [ ] Confirm scaffold strategy and tools via questions below +- [x] Confirm scaffold strategy and tools via questions below - [ ] Generate folder structure (`src/api`, `src/auth`, `src/components`, `src/routes`) - [ ] Install and configure dependencies (TanStack Router, @tanstack/react-query, Tailwind v4, shadcn/ui) - [ ] Configure Tailwind theme with primary color `#ac0000` @@ -30,49 +30,49 @@ B) npm C) yarn X) Other (please describe after the [Answer]: tag below) -[Answer]: +[Answer]: A ## Question 2: Router choice A) TanStack Router (required by NFR-01) B) React Router X) Other (please describe after the [Answer]: tag below) -[Answer]: +[Answer]: A ## Question 3: UI foundation A) Tailwind v4 + shadcn/ui (recommended) B) Tailwind v4 only (no shadcn/ui) X) Other (please describe after the [Answer]: tag below) -[Answer]: +[Answer]: A ## Question 4: Primary color integration (`#ac0000`) A) Tailwind theme config (extend colors + use via utility classes) B) CSS variables (root-level var, consumed by components) X) Other (please describe after the [Answer]: tag below) -[Answer]: +[Answer]: A ## Question 5: HTTP client layer A) Fetch wrapper (`ApiClient`) with `credentials: 'include'` + JSON helpers (recommended) B) Axios instance with `withCredentials: true` X) Other (please describe after the [Answer]: tag below) -[Answer]: +[Answer]: A ## Question 6: API base URL source A) `import.meta.env.VITE_API_BASE_URL` (from `.env`) B) Derive from `window.location.origin` + `/api` X) Other (please describe after the [Answer]: tag below) -[Answer]: +[Answer]: A ## Question 7: Session bootstrap behavior A) On app mount, attempt silent refresh (uses httpOnly cookie) to hydrate `AuthContext` (recommended) B) Do not auto-refresh on mount; rely on login flow and 401 handling X) Other (please describe after the [Answer]: tag below) -[Answer]: +[Answer]: A ## Question 8: Linting/formatting baseline A) ESLint (recommended) + Prettier with sensible defaults @@ -80,4 +80,4 @@ B) ESLint only C) None for now X) Other (please describe after the [Answer]: tag below) -[Answer]: +[Answer]: A, but indentation with 4 spaces diff --git a/aidlc-docs/features/cms-frontend/construction/plans/unit-1-nfr-requirements-plan.md b/aidlc-docs/features/cms-frontend/construction/plans/unit-1-nfr-requirements-plan.md new file mode 100644 index 0000000..78f53a1 --- /dev/null +++ b/aidlc-docs/features/cms-frontend/construction/plans/unit-1-nfr-requirements-plan.md @@ -0,0 +1,71 @@ +# NFR Requirements Plan — Unit 1: Project Scaffold & Infrastructure + +**Status**: Awaiting user answers to the questions below. + +## Plan Checklist +- [ ] Analyze functional design artifacts (domain-entities.md, business-rules.md, business-logic-model.md) +- [ ] Identify NFR categories requiring clarification (performance, security, accessibility, maintainability, observability) +- [ ] Generate context-appropriate multiple-choice questions per question-format-guide.md +- [ ] Store this plan file +- [ ] Wait for user completion of [Answer] tags +- [ ] Validate answers, resolve any ambiguities +- [ ] Generate nfr-requirements.md and tech-stack-decisions.md artifacts + +## NFR Questions + +## Question 1 +What is the target initial JavaScript bundle size budget (gzipped) for the production build of the CMS frontend? + +A) < 200 KB (strict, requires aggressive code-splitting and tree-shaking) +B) < 300 KB (balanced for shadcn/ui + TanStack Router + React 18) +C) < 500 KB (lenient, acceptable for admin panel with multiple pages) +X) Other (please describe after [Answer]: tag below) + +[Answer]: X, as small as possible to reduce initial bundle size, but no exact number. + +## Question 2 +What accessibility (a11y) compliance level must the admin UI components and pages meet? + +A) WCAG 2.2 AA (standard for most admin interfaces; keyboard navigation + screen reader support) +B) WCAG 2.2 AAA (highest level; includes enhanced contrast, cognitive accessibility) +C) Basic keyboard navigation and focus management only (minimal viable for internal tool) +X) Other (please describe after [Answer]: tag below) + +[Answer]: C + +## Question 3 +Should the scaffold include a client-side error monitoring / observability solution from day one? + +A) No observability in scaffold (console + toast only; add later) +B) Sentry (error tracking + performance monitoring) +C) OpenTelemetry / custom lightweight solution +X) Other (please describe after [Answer]: tag below) + +[Answer]: A + +## Question 4 +Should Vitest + React Testing Library + MSW (mock service worker) be included in the initial project scaffold for component and integration tests? + +A) Yes — full test setup with example tests for login flow and auth guard +B) No — only Playwright E2E later; keep scaffold minimal +X) Other (please describe after [Answer]: tag below) + +[Answer]: A + +## Question 5 +Is internationalization (i18n) support required in the initial scaffold, or can labels remain hard-coded for now? + +A) Yes — add react-i18next + language switcher (English + Dutch) +B) No — English only for v1; Dutch translations can be added later without i18n framework +X) Other (please describe after [Answer]: tag below) + +[Answer]: A + +## Question 6 +Should pre-commit hooks (husky + lint-staged) enforcing ESLint + Prettier + TypeScript checks be part of the scaffold? + +A) Yes — enforce formatting and type safety on every commit +B) No — rely on editor integration and CI only +X) Other (please describe after [Answer]: tag below) + +[Answer]: B diff --git a/aidlc-docs/features/cms-frontend/construction/unit-1/functional-design/business-logic-model.md b/aidlc-docs/features/cms-frontend/construction/unit-1/functional-design/business-logic-model.md new file mode 100644 index 0000000..4c9ebc4 --- /dev/null +++ b/aidlc-docs/features/cms-frontend/construction/unit-1/functional-design/business-logic-model.md @@ -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
useAuth/useQuery] -->|call ApiClient| API[ApiClient fetch
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
Providers: QueryClient + AuthContext] --> Guard[Init/Silent Refresh] + Guard -->|guest| Pub[Public routes: /login, /setup] + Guard -->|auth| Auth[_authenticated.tsx
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). diff --git a/aidlc-docs/features/cms-frontend/construction/unit-1/functional-design/business-rules.md b/aidlc-docs/features/cms-frontend/construction/unit-1/functional-design/business-rules.md new file mode 100644 index 0000000..722db8b --- /dev/null +++ b/aidlc-docs/features/cms-frontend/construction/unit-1/functional-design/business-rules.md @@ -0,0 +1,66 @@ +# Business Rules — Unit 1: Project Scaffold & Infrastructure + +These rules define the expected behavior and guardrails for the frontend scaffold. They are binding for subsequent design and implementation steps. + +## BR-U1-01: Session Bootstrap +- On app mount, attempt a silent refresh using the httpOnly cookie +- If successful, hydrate `AuthContext` with `{ user, accessToken, expiresAt }` +- On failure (401), ensure `guest` state + +## BR-U1-02: Access Token Handling +- Store the `accessToken` only in memory (React state/context) +- Never persist it in `localStorage`, `sessionStorage`, or cookies + +## BR-U1-03: HTTP Defaults +- All API calls use `fetch` with `credentials: 'include'` +- `Content-Type: application/json` when a body is present + +## BR-U1-04: 401 Intercept + Retry +- On a `401 Unauthorized`, the `ApiClient` must first try `POST /api/v1/auth/refresh` (cookie-based) +- If it succeeds, update the in-memory token and retry the original request once +- If refresh fails, clear auth and redirect to `/login` + +## BR-U1-05: Router & Guards +- Use TanStack Router +- Protected routes live under `_authenticated.tsx` layout +- Use a `beforeLoad` guard (or equivalent hook) to block unauthorized access and redirect to `/login` + +## BR-U1-06: Public Routes +- `/login`, `/setup`, and invitation completion pages remain publicly accessible +- When authenticated users hit `/login`, redirect to the dashboard + +## BR-U1-07: Theme & UI +- Configure Tailwind v4 with primary color `#ac0000` +- shadcn/ui components must use this primary color in the theme configuration + +## BR-U1-08: Error Handling +- Parse API errors as RFC 9457 `ProblemDetails` +- Show a user-friendly toast/banner +- Do not display raw stack traces + +## BR-U1-09: API Base URL +- Read the API base URL from `import.meta.env.VITE_API_BASE_URL` +- Provide `.env.example` and document setup in README + +## BR-U1-10: Typing & Naming +- Use TypeScript types that align with backend payloads +- The user property is named `name` (not `naam`) + +## BR-U1-11: Testing Readiness +- Add stable `data-testid` attributes to interactive elements (e.g., `login-form-submit-button`) to support automation + +## BR-U1-12: Formatting +- Use ESLint + Prettier +- Enforce 4-space indentation (printWidth and other defaults as sensible) + +## BR-U1-13: Security +- Never echo refresh tokens +- Ensure all cross-origin calls rely on CORS allowlist and credentialed requests only + +## BR-U1-14: State Consistency +- When auth state changes (login, refresh, logout), notify dependents via context +- UI updates immediately without hard reloads + +## BR-U1-15: Network Robustness +- The `ApiClient` must gracefully handle network timeouts and show non-blocking toasts +- Background refetches should not break the UI diff --git a/aidlc-docs/features/cms-frontend/construction/unit-1/functional-design/domain-entities.md b/aidlc-docs/features/cms-frontend/construction/unit-1/functional-design/domain-entities.md new file mode 100644 index 0000000..d7ba10a --- /dev/null +++ b/aidlc-docs/features/cms-frontend/construction/unit-1/functional-design/domain-entities.md @@ -0,0 +1,53 @@ +# Domain Entities — Unit 1: Project Scaffold & Infrastructure + +TypeScript interfaces to be used in the frontend scaffold. Indentation shown with 4 spaces to match ESLint/Prettier baseline. + +```ts +// src/api/types.ts + +// Roles aligned with backend authorization +export type UserRole = 'Owner' | 'Administrator' | 'User'; + +export interface User { + id: string; // UUID + email: string; + name: string; + role: UserRole; + isActive: boolean; +} + +export interface AuthResponse { + accessToken: string; // JWT access token + expiresAt: string; // ISO timestamp + user: User; +} + +// RFC 9457 ProblemDetails for standardized error handling +export interface ProblemDetails { + type?: string; + title?: string; + status?: number; + detail?: string; + instance?: string; + [extension: string]: unknown; // includes traceId +} + +// Convenience wrapper for API results (optional usage) +export type ApiResult = { + ok: true; + data: T; +} | { + ok: false; + error: ProblemDetails; +}; + +// Setup status (used by guards during bootstrap) +export interface SetupStatus { + initialized: boolean; +} +``` + +Notes: +- Names align with backend payloads: property is `name` (English), never `naam`. +- `accessToken` lives only in memory (AuthContext), not persisted. +- `ProblemDetails` maps 1:1 to backend RFC 9457 responses and includes `traceId` as an extension.