Adds nfr requirements and design for unit 1
This commit is contained in:
@@ -0,0 +1,74 @@
|
|||||||
|
# NFR Design Plan — Unit 1: Project Scaffold & Infrastructure
|
||||||
|
|
||||||
|
**Status**: Completed — NFR design patterns and logical components generated based on answers.
|
||||||
|
|
||||||
|
## Plan Checklist
|
||||||
|
- [x] Analyze NFR requirements artifacts (nfr-requirements.md, tech-stack-decisions.md)
|
||||||
|
- [x] Identify design pattern decisions needed for performance, a11y, testing, i18n, config
|
||||||
|
- [x] Generate context-appropriate multiple-choice questions per question-format-guide.md
|
||||||
|
- [x] Store this plan file
|
||||||
|
- [x] Wait for user completion of [Answer] tags
|
||||||
|
- [x] Validate answers, resolve any ambiguities
|
||||||
|
- [x] Generate nfr-design-patterns.md and logical-components.md artifacts
|
||||||
|
|
||||||
|
## NFR Design Questions
|
||||||
|
|
||||||
|
## Question 1
|
||||||
|
How should TanStack Router file-based routes be organized to achieve optimal code-splitting and keep the initial JS bundle as small as possible?
|
||||||
|
|
||||||
|
A) One route file per major feature (auth, dashboard, users, cms) with lazy-loaded layouts and components
|
||||||
|
B) Flat structure under src/routes/ with all routes co-located, relying on Vite's automatic tree-shaking and code-splitting
|
||||||
|
C) Hybrid approach: core shell and auth routes eager-loaded; feature modules (dashboard, users, cms) lazy-loaded via dynamic imports inside authenticated layout
|
||||||
|
X) Other (please describe after [Answer]: tag below)
|
||||||
|
|
||||||
|
[Answer]: A
|
||||||
|
|
||||||
|
## Question 2
|
||||||
|
What focus management and keyboard navigation pattern should be implemented for the admin UI (sidebar navigation + main content area) to satisfy the basic a11y requirement?
|
||||||
|
|
||||||
|
A) Rely entirely on browser default Tab order + shadcn/ui :focus-visible styles; add focus trap only for modals and dialogs
|
||||||
|
B) Implement roving tabindex for sidebar nav items + visible focus ring; standard Tab for main content
|
||||||
|
C) Full custom arrow-key navigation and type-ahead search inside the sidebar (desktop-app style)
|
||||||
|
X) Other (please describe after [Answer]: tag below)
|
||||||
|
|
||||||
|
[Answer]: A
|
||||||
|
|
||||||
|
## Question 3
|
||||||
|
How should MSW request handlers be organized to support auth flows, 401-intercept testing, and future feature mocks while keeping tests maintainable?
|
||||||
|
|
||||||
|
A) Centralized `src/mocks/handlers.ts` exporting domain-specific arrays (authHandlers, userHandlers, cmsHandlers) re-exported from index
|
||||||
|
B) Feature-scoped folders under `src/mocks/` (e.g. `auth/handlers.ts`, `users/handlers.ts`) with barrel re-exports
|
||||||
|
C) Inline MSW handlers defined directly inside each test file for maximum isolation
|
||||||
|
X) Other (please describe after [Answer]: tag below)
|
||||||
|
|
||||||
|
[Answer]: B
|
||||||
|
|
||||||
|
## Question 4
|
||||||
|
What strategy should be used for loading and switching between English and Dutch translations with react-i18next?
|
||||||
|
|
||||||
|
A) Eager-load both language JSON files at app bootstrap (small total size) and keep them in memory
|
||||||
|
B) Lazy-load only the active language JSON; switch language by dynamic import of the new locale file
|
||||||
|
C) Use i18next-http-backend to fetch translations from `/locales/{lng}/{ns}.json` on demand (no bundling)
|
||||||
|
X) Other (please describe after [Answer]: tag below)
|
||||||
|
|
||||||
|
[Answer]: B
|
||||||
|
|
||||||
|
## Question 5
|
||||||
|
How should RFC 9457 ProblemDetails responses be transformed into user-facing feedback (toasts/banners) while keeping the implementation simple?
|
||||||
|
|
||||||
|
A) Global error interceptor in ApiClient that maps ProblemDetails to a single shadcn/ui toast (title = title or status, description = detail)
|
||||||
|
B) Per-page or per-component error handling that decides toast vs. inline message based on context
|
||||||
|
C) Only show toasts for network errors and 5xx; 4xx errors are handled by form validation or redirect only
|
||||||
|
X) Other (please describe after [Answer]: tag below)
|
||||||
|
|
||||||
|
[Answer]: B
|
||||||
|
|
||||||
|
## Question 6
|
||||||
|
How should Vite environment variables (VITE_API_BASE_URL and future feature flags) be typed and validated?
|
||||||
|
|
||||||
|
A) Extend `vite-env.d.ts` with a typed `import.meta.env` interface and add optional Zod validation at runtime startup
|
||||||
|
B) Use TypeScript module augmentation for `import.meta.env` only; no runtime validation (trust .env files)
|
||||||
|
C) Fetch a `config.json` at bootstrap for all non-Vite-exposed settings; keep VITE_* vars minimal
|
||||||
|
X) Other (please describe after [Answer]: tag below)
|
||||||
|
|
||||||
|
[Answer]: A
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
# NFR Requirements Plan — Unit 1: Project Scaffold & Infrastructure
|
# NFR Requirements Plan — Unit 1: Project Scaffold & Infrastructure
|
||||||
|
|
||||||
**Status**: Awaiting user answers to the questions below.
|
**Status**: Completed — NFR requirements and tech-stack decisions generated.
|
||||||
|
|
||||||
## Plan Checklist
|
## Plan Checklist
|
||||||
- [ ] Analyze functional design artifacts (domain-entities.md, business-rules.md, business-logic-model.md)
|
- [x] Analyze functional design artifacts (domain-entities.md, business-rules.md, business-logic-model.md)
|
||||||
- [ ] Identify NFR categories requiring clarification (performance, security, accessibility, maintainability, observability)
|
- [x] Identify NFR categories requiring clarification (performance, security, accessibility, maintainability, observability)
|
||||||
- [ ] Generate context-appropriate multiple-choice questions per question-format-guide.md
|
- [x] Generate context-appropriate multiple-choice questions per question-format-guide.md
|
||||||
- [ ] Store this plan file
|
- [x] Store this plan file
|
||||||
- [ ] Wait for user completion of [Answer] tags
|
- [x] Wait for user completion of [Answer] tags
|
||||||
- [ ] Validate answers, resolve any ambiguities
|
- [x] Validate answers, resolve any ambiguities
|
||||||
- [ ] Generate nfr-requirements.md and tech-stack-decisions.md artifacts
|
- [x] Generate nfr-requirements.md and tech-stack-decisions.md artifacts
|
||||||
|
|
||||||
## NFR Questions
|
## NFR Questions
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
# Logical Components — Unit 1: Project Scaffold & Infrastructure
|
||||||
|
|
||||||
|
## Component Overview
|
||||||
|
The frontend scaffold is composed of the following logical components that realize the NFR design patterns.
|
||||||
|
|
||||||
|
## Mermaid Diagram — Component Interaction (colored by layer)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
Root[Root App] --> Router[TanStack Router]
|
||||||
|
Router --> AuthLayout[Auth Layout]
|
||||||
|
Router --> PublicRoutes[Public Routes]
|
||||||
|
AuthLayout --> Dash[Dashboard]
|
||||||
|
AuthLayout --> Users[Users]
|
||||||
|
AuthLayout --> Cms[CMS Mgmt]
|
||||||
|
|
||||||
|
Root --> I18n[i18next Provider]
|
||||||
|
Root --> Toast[Toast Provider]
|
||||||
|
Root --> Api[ApiClient]
|
||||||
|
|
||||||
|
Api --> MSW[MSW Handlers]
|
||||||
|
Api --> AuthCtx[AuthContext]
|
||||||
|
|
||||||
|
classDef root fill:#e9d5ff,stroke:#6b21a8,stroke-width:2px,color:#6b21a8;
|
||||||
|
classDef provider fill:#bae6fd,stroke:#0369a1,stroke-width:2px,color:#0369a1;
|
||||||
|
classDef client fill:#fed7aa,stroke:#c2410c,stroke-width:2px,color:#c2410c;
|
||||||
|
classDef route fill:#c6f6d5,stroke:#22543d,stroke-width:2px,color:#22543d;
|
||||||
|
|
||||||
|
class Root root;
|
||||||
|
class I18n,Toast,AuthCtx provider;
|
||||||
|
class Api,MSW client;
|
||||||
|
class Router,AuthLayout,PublicRoutes,Dash,Users,Cms route;
|
||||||
|
```
|
||||||
|
|
||||||
|
Text alternative: Root bootstraps providers (i18n, toast, auth) and TanStack Router; authenticated routes live under a layout protected by AuthContext; API client is shared and uses MSW in tests.
|
||||||
|
|
||||||
|
## Key Logical Components
|
||||||
|
|
||||||
|
| Component | Responsibility | NFR / BR Link |
|
||||||
|
|-----------|----------------|---------------|
|
||||||
|
| `ApiClient` | fetch wrapper with credentials, throws `ProblemDetailsError` | BR-U1-03, BR-U1-04, NFR-U1-05 (error mapping) |
|
||||||
|
| `AuthContext` | in-memory token + user state, silent refresh on mount | BR-U1-01, BR-U1-02 |
|
||||||
|
| `I18nProvider` | react-i18next + detector + lazy locale loader | NFR-U1-05, Q4-B |
|
||||||
|
| `ToastProvider` | shadcn/ui toast primitive exposed via `useToast()` | NFR-U1-03, Q5-B |
|
||||||
|
| `MSW Handlers` | feature-scoped mock handlers under `src/mocks/` | NFR-U1-04, Q3-B |
|
||||||
|
| `Route Modules` | lazy-loaded per-feature route files | NFR-U1-01, Q1-A |
|
||||||
|
| `FocusTrap` | radix/shadcn dialog primitive for modals only | NFR-U1-02, Q2-A |
|
||||||
|
| `vite-env.d.ts` | typed `import.meta.env` + optional Zod config hook | NFR-U1-07, Q6-A |
|
||||||
|
|
||||||
|
## Integration Points
|
||||||
|
- All authenticated pages receive `AuthContext` via layout.
|
||||||
|
- Language switcher lives in the top-right user menu and updates both i18next and persisted preference.
|
||||||
|
- Error toasts are triggered from within pages or forms; 401 errors bubble to `AuthContext.logout()`.
|
||||||
|
- Tests import handlers from `src/mocks/index` and wrap the component tree with all providers.
|
||||||
|
|
||||||
|
These components form a minimal, maintainable foundation that satisfies all NFR-U1 requirements without introducing heavy dependencies.
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
# NFR Design Patterns — Unit 1: Project Scaffold & Infrastructure
|
||||||
|
|
||||||
|
## 1. Performance — Route-Based Code Splitting (Answer Q1-A)
|
||||||
|
**Pattern**: Per-feature route modules with lazy-loaded layouts and page components.
|
||||||
|
|
||||||
|
- TanStack Router `createLazyFileRoute` for dashboard, users, cms routes
|
||||||
|
- Auth and root shell remain eager for fast initial paint and login
|
||||||
|
- Vite automatically emits separate chunks per lazy route
|
||||||
|
- Aligns with NFR-U1-01 (smallest possible bundle) and BR-U1-05 (TanStack Router)
|
||||||
|
|
||||||
|
## 2. Accessibility — Keyboard & Focus Trap (Answer Q2-A)
|
||||||
|
**Pattern**: Browser-native Tab order + shadcn/ui focus-visible + modal focus trap only.
|
||||||
|
|
||||||
|
- All interactive elements use native `<button>`, `<a>`, form controls
|
||||||
|
- `focus-visible` ring provided by shadcn/ui theme (Tailwind ring-2 ring-offset-2)
|
||||||
|
- `FocusTrap` component (from `@radix-ui/react-focus-trap` or shadcn/ui dialog primitive) applied exclusively to modals and confirmation dialogs
|
||||||
|
- No custom roving tabindex or arrow-key navigation unless explicitly required later
|
||||||
|
|
||||||
|
## 3. Testing — Feature-Scoped MSW Handlers (Answer Q3-B)
|
||||||
|
**Pattern**: Feature folders under `src/mocks/` with barrel exports.
|
||||||
|
|
||||||
|
```
|
||||||
|
src/mocks/
|
||||||
|
auth/
|
||||||
|
handlers.ts
|
||||||
|
fixtures.ts
|
||||||
|
users/
|
||||||
|
handlers.ts
|
||||||
|
index.ts
|
||||||
|
```
|
||||||
|
- `auth/handlers.ts` exports `authHandlers` array used in login, refresh, 401-retry tests
|
||||||
|
- Easy to extend per future feature without central file bloat
|
||||||
|
- Supports NFR-U1-04 (>70% coverage on auth components)
|
||||||
|
|
||||||
|
## 4. Internationalization — Lazy Language Loading (Answer Q4-B)
|
||||||
|
**Pattern**: Dynamic import of active locale only.
|
||||||
|
|
||||||
|
- `i18next` initialized with `react-i18next` and `i18next-browser-languagedetector`
|
||||||
|
- On language change: `i18next.changeLanguage(lng)` triggers `import(`../../public/locales/${lng}/translation.json`)`
|
||||||
|
- Fallback to English; no eager bundling of both languages
|
||||||
|
- Language switcher in user menu triggers the dynamic load + persists choice in localStorage via detector
|
||||||
|
|
||||||
|
## 5. Error Handling — Per-Component ProblemDetails Mapping (Answer Q5-B)
|
||||||
|
**Pattern**: Context-aware error presentation instead of global interceptor.
|
||||||
|
|
||||||
|
- `ApiClient` throws typed `ProblemDetailsError` (extends Error)
|
||||||
|
- Each page/form catches and decides:
|
||||||
|
- 401/403 → redirect or global AuthContext logout
|
||||||
|
- Validation errors (400) → inline field errors via react-hook-form
|
||||||
|
- Transient errors → shadcn/ui toast via `useToast()`
|
||||||
|
- Keeps UI responsive and avoids one-size-fits-all toasts
|
||||||
|
|
||||||
|
## 6. Configuration — Typed Vite Env + Optional Zod (Answer Q6-A)
|
||||||
|
**Pattern**: Strong typing in `vite-env.d.ts` + runtime validation hook.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// vite-env.d.ts
|
||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly VITE_API_BASE_URL: string;
|
||||||
|
// future flags...
|
||||||
|
}
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- Optional `useAppConfig()` hook runs Zod parse once at bootstrap (development warning only)
|
||||||
|
- Production trusts `.env` values (no runtime overhead)
|
||||||
|
|
||||||
|
All patterns respect the "minimal viable" constraints from NFR Requirements (no Sentry, no pre-commit, basic a11y).
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
# NFR Requirements — Unit 1: Project Scaffold & Infrastructure
|
||||||
|
|
||||||
|
## NFR-U1-01: Performance — Bundle Size
|
||||||
|
- Target: Keep initial JS bundle (gzipped) as small as possible
|
||||||
|
- Vite must be configured for aggressive tree-shaking and code-splitting via TanStack Router file-based routes
|
||||||
|
- No hard numeric budget; continuous monitoring via `vite build --analyze` recommended in CI later
|
||||||
|
- See BR-U1-01, BR-U1-05 for lazy loading expectations
|
||||||
|
|
||||||
|
## NFR-U1-02: Accessibility — Keyboard & Focus (A11Y)
|
||||||
|
- Minimum requirement: Basic keyboard navigation and visible focus indicators on all interactive elements
|
||||||
|
- All form controls, buttons, and links must be reachable via Tab and operable with Enter/Space
|
||||||
|
- No full WCAG 2.2 AA/AAA compliance required for v1 (internal admin tool)
|
||||||
|
- shadcn/ui components must expose proper ARIA attributes by default
|
||||||
|
|
||||||
|
## NFR-U1-03: Observability — Client-side Error Reporting
|
||||||
|
- No external error monitoring (Sentry, OpenTelemetry) in initial scaffold
|
||||||
|
- Errors are logged to console + shown via user-friendly toast/banner (using existing shadcn/ui toast primitives)
|
||||||
|
- Future extension point: add observability library later without changing API client contract
|
||||||
|
|
||||||
|
## NFR-U1-04: Testing — Component & Integration Tests
|
||||||
|
- Vitest + React Testing Library + MSW MUST be included in the scaffold
|
||||||
|
- Example tests required for: login form submission, 401-intercept + retry flow, and authenticated route guard
|
||||||
|
- Tests must run with `pnpm test` and achieve >70% coverage on auth-related components
|
||||||
|
- MSW handlers must mock the real backend endpoints (`/api/v1/auth/*`)
|
||||||
|
|
||||||
|
## NFR-U1-05: Internationalization — i18n
|
||||||
|
- react-i18next + i18next-browser-languagedetector MUST be added
|
||||||
|
- Supported languages in v1: English (default) + Dutch
|
||||||
|
- Language switcher component must be present in the top bar / user menu
|
||||||
|
- All user-facing strings in the scaffold (login, dashboard shell, error messages) must be wrapped in `t()` calls
|
||||||
|
- Translation files: `public/locales/en/*.json` and `public/locales/nl/*.json`
|
||||||
|
|
||||||
|
## NFR-U1-06: Maintainability — Pre-commit Hooks
|
||||||
|
- No husky + lint-staged in the initial scaffold
|
||||||
|
- Rely on editor integration (ESLint/Prettier on save) and CI pipeline only
|
||||||
|
- Pre-commit enforcement can be added in a later NFR iteration if desired
|
||||||
|
|
||||||
|
## NFR-U1-07: Maintainability — Configuration
|
||||||
|
- All environment-specific values (API base URL, feature flags) stored in `.env` / `.env.example` following Vite conventions
|
||||||
|
- No magic strings for route paths or API endpoints — use constants / TanStack Router file naming
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
# Tech Stack Decisions — Unit 1: Project Scaffold & Infrastructure
|
||||||
|
|
||||||
|
## Existing Stack (from ZIP example + requirements)
|
||||||
|
All prior choices retained:
|
||||||
|
- **Vite 6** — Build tool
|
||||||
|
- **React 18** — UI library
|
||||||
|
- **TypeScript 5** — Type safety
|
||||||
|
- **TanStack Router v1** — File-based routing (replaces React Router)
|
||||||
|
- **Tailwind CSS v4** + **shadcn/ui** — Styling & components (primary color `#ac0000`)
|
||||||
|
- **pnpm** — Package manager
|
||||||
|
- **ESLint + Prettier** (4-space indent) — Formatting
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## New: Testing Framework
|
||||||
|
|
||||||
|
| Decision | Choice | Rationale |
|
||||||
|
|----------|--------|-----------|
|
||||||
|
| Test runner | Vitest | Native ESM, fast, Vite-native, excellent TypeScript support |
|
||||||
|
| Component testing | React Testing Library | Industry standard for React; focuses on user behavior |
|
||||||
|
| API mocking | MSW (Mock Service Worker) | Works in browser + Node; realistic network layer for auth flows |
|
||||||
|
| Test command | `pnpm test` | Consistent with existing pnpm scripts |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## New: Internationalization
|
||||||
|
|
||||||
|
| Decision | Choice | Rationale |
|
||||||
|
|----------|--------|-----------|
|
||||||
|
| i18n library | react-i18next + i18next-browser-languagedetector | Most popular React i18n solution; automatic language detection |
|
||||||
|
| Translation files | JSON under `public/locales/{en,nl}/` | Standard, easy to edit, works with Vite static assets |
|
||||||
|
| Language switcher | Custom component in user menu | Keeps UI consistent with shadcn/ui |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## New: Environment Configuration
|
||||||
|
|
||||||
|
| Decision | Choice | Rationale |
|
||||||
|
|----------|--------|-----------|
|
||||||
|
| Env variables | Vite `import.meta.env.VITE_*` | Official, type-safe, exposed to client |
|
||||||
|
| Example file | `.env.example` (committed) | Documents required variables for new developers |
|
||||||
|
| Local overrides | `.env.local` (gitignored) | Follows Vite + dotenv conventions |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Explicitly NOT included (per answers)
|
||||||
|
|
||||||
|
- No Sentry / OpenTelemetry in scaffold
|
||||||
|
- No husky + lint-staged pre-commit hooks
|
||||||
|
- No WCAG 2.2 AA/AAA a11y requirements beyond basic keyboard support
|
||||||
|
- No hard bundle-size budget (optimize for smallest possible)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## appsettings / env additions (frontend only)
|
||||||
|
|
||||||
|
`.env.example` (committed):
|
||||||
|
```env
|
||||||
|
VITE_API_BASE_URL=http://localhost:5000
|
||||||
|
```
|
||||||
|
|
||||||
|
`.env.local` (developer only, gitignored):
|
||||||
|
```env
|
||||||
|
VITE_API_BASE_URL=http://localhost:5000
|
||||||
|
```
|
||||||
|
|
||||||
|
No changes needed to backend `appsettings.json` for Unit 1.
|
||||||
Reference in New Issue
Block a user