Files
slp-modular-cms/aidlc-docs/features/cms-frontend/construction/plans/unit-1-code-generation-plan.md
T
2026-06-20 17:04:17 +02:00

8.2 KiB

Code Generation Plan — Unit 1: Project Scaffold & Infrastructure

Status: Generation complete 2026-06-20 — all steps executed and verified (build, lint, tests green). Awaiting user review.

Plan Context

  • Unit: Unit 1 — Frontend Project Scaffold & Infrastructure
  • Type: Greenfield (new Vite + React + TypeScript application)
  • Workspace Root: K:\Development\Projects\SlpModularCms (frontend placed in frontend/ subfolder to keep .NET solution clean)
  • Stories Covered: US-01 (Login), US-02 (Silent Refresh), US-03 (Protected Routes), US-04 (Dashboard Shell), US-05 (User Menu + Language Switcher), US-06 (401 Intercept), US-07 (Error Handling), US-13 (Password rules alignment already done in backend), US-18/US-20 (CMS Management Owner-only — out of scope for Unit 1)
  • Dependencies: Backend Unit 0 (CORS, httpOnly refresh cookie, ProblemDetails) must be complete and running on localhost:5000
  • NFR Traceability: NFR-U1-01 to NFR-U1-07 fully addressed via chosen patterns (Q1-A, Q2-A, Q3-B, Q4-B, Q5-B, Q6-A)

Generation Steps

Step 1: Bootstrap Vite + React + TypeScript Project

  • Run pnpm create vite@latest frontend --template react-ts in repo root
  • cd frontend && pnpm install
  • Verify dev server works on http://localhost:5173 (boots in ~267ms, HTTP 200)
  • Initial Vite scaffold in place

Step 2: Install Core Dependencies

  • Install TanStack Router: @tanstack/react-router
  • Install Tailwind v4: tailwindcss @tailwindcss/vite (v4 Vite plugin, not postcss/autoprefixer)
  • Install react-i18next + detector: react-i18next i18next i18next-browser-languagedetector
  • Install testing stack: vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event msw jsdom @vitest/coverage-v8
  • Install UI primitives: lucide-react sonner class-variance-authority clsx tailwind-merge @radix-ui/react-dropdown-menu @radix-ui/react-slot @radix-ui/react-label react-hook-form zod @hookform/resolvers
  • shadcn primitives hand-authored for Tailwind v4 (CSS variables, primary #ac0000) — see Deviations re: shadcn init

Step 3: Configure Tooling (ESLint, Prettier, 4-space indent)

  • ESLint flat config + .prettierrc enforcing 4-space indentation
  • Added pnpm format and pnpm lint scripts (+ format:check, test, test:coverage)
  • Configured tsconfig.app.json paths (@/*src/*) and Vite alias

Step 4: Environment Configuration

  • Created .env.example with VITE_API_BASE_URL=http://localhost:5000
  • Created .env.local (gitignored via *.local)
  • Extended src/vite-env.d.ts with typed ImportMetaEnv (per Q6-A)
  • Added useAppConfig/getAppConfig with Zod (dev-only validation) in src/lib/config.ts

Step 5: Project Folder Structure

  • Created src/components/ui/, src/components/layout/, src/lib/, src/contexts/, src/i18n/, src/mocks/{auth,users,setup}/, src/pages/, src/test/, src/api/, src/i18n/locales/{en,nl}/
  • Note: route components live in src/pages/ + central src/router.tsx (code-based routing — see Deviations); locales in src/i18n/locales/ (see Deviations)

Step 6: Implement ApiClient (fetch wrapper)

  • src/lib/api-client.ts with credentials: 'include', JSON handling, ProblemDetailsError + NetworkError classes (BR-U1-03, BR-U1-08)
  • 401 intercept + single retry via refresh handler (BR-U1-04)
  • Exported typed singleton api

Step 7: Implement AuthContext + Silent Refresh

  • src/contexts/auth-context.ts (context + useAuth) and src/contexts/AuthProvider.tsx with user, accessToken (memory only), expiresAt, login, logout, refresh
  • Silent refresh on mount using httpOnly cookie (BR-U1-01)
  • useAuth() hook provided

Step 8: Setup i18n with Lazy Loading

  • src/i18n/config.ts using react-i18next + detector; English eager (fallback), other locales lazy via dynamic import (Q4-B)
  • LanguageSwitcher component (shadcn dropdown) wired into the topbar
  • en/translation.json and nl/translation.json with initial keys (common, nav, login, dashboard, userMenu, errors)

Step 9: Setup MSW for Development & Tests

  • src/mocks/browser.ts and src/mocks/server.ts; worker generated at public/mockServiceWorker.js
  • Feature-scoped authHandlers (login, refresh, revoke), userHandlers, setupHandlers (per Q3-B) — aligned to real backend (no /me; user comes from login/refresh)
  • src/mocks/index.ts barrel

Step 10: TanStack Router Setup + Guards

  • Router configured in src/router.tsx (createRouter + RouterProvider in main.tsx)
  • _authenticated layout route with beforeLoad guard (redirect to /login) (BR-U1-05)
  • Public routes: /login, /setup
  • Protected routes under _authenticated: /dashboard, /users, /cms

Step 11: Core UI Components & Pages (Automation-Friendly)

  • Login page with form, data-testid="login-form-submit-button", email/password fields, error banner
  • AppLayout with Sidebar (nav links), Topbar (user menu + LanguageSwitcher)
  • Dashboard shell (placeholder)
  • Stable data-testid attributes on interactive elements (BR-U1-11)

Step 12: Example Tests (Vitest + RTL + MSW)

  • src/test/setup.ts with MSW server + jsdom polyfills; src/test/utils.tsx providers wrapper
  • LoginPage.test.tsx — successful login, validation errors, invalid credentials
  • AuthContext.test.tsx — silent refresh success/failure, 401 retry flow, refresh-failure clears session
  • RouteGuard.test.tsx — guest redirect, authenticated access, authed-from-login redirect
  • Coverage on auth-related code >70% (AuthProvider 92.7%, api-client 84.8%, auth-context 80%, LoginPage 84.2%) (NFR-U1-04)
  • pnpm test script

Step 13: shadcn Theme & Styling

  • Tailwind v4 with primary #ac0000 (CSS variables, light + dark tokens)
  • Consistent spacing, typography, and focus-visible rings (Q2-A)
  • Responsive sidebar (hidden < md) + main content area

Step 14: Documentation & README

  • Root README.md "Frontend Development (CMS Admin UI)" section (Dutch, matching the file)
  • .env.example explained + required backend (localhost:5000, CORS, httpOnly cookies)

Step 15: Final Verification

  • pnpm build succeeds (tsc + vite, only non-fatal vendor chunk-size + cosmetic glob warnings)
  • All tests pass (pnpm test → 10/10)
  • pnpm lint clean, pnpm format:check clean
  • Dev server smoke: boots (267ms), serves HTTP 200, login/guard/401/language covered by integration tests

Deviations from the Original Plan (with rationale)

  1. React 19 instead of React 18: the current Vite react-ts template scaffolds React 19.2 (stable). All chosen libraries support it; downgrading would fight the ecosystem. No business-rule impact.
  2. Code-based TanStack Router (src/router.tsx) instead of file-based routes: avoids the route-tree codegen plugin, making build/test deterministic with no generated routeTree.gen.ts. All routing business rules (BR-U1-05/06, guard, _authenticated layer) are fully satisfied. Per-feature pages are lazy-loaded (Q1-A / NFR-U1-01) via React.lazy boundaries.
  3. Hand-authored shadcn primitives instead of npx shadcn init: the CLI is interactive and Tailwind-v4 setup is config-driven; primitives (Button, Input, Label, Card, DropdownMenu, Toaster) were authored directly with the #ac0000 theme. Same end result, no interactive prompt.
  4. Locales in src/i18n/locales/ instead of public/locales/: enables real per-language code-split chunks via dynamic import() and works in Vitest without network mocking. English (fallback) is eager; nl is a separate chunk. Files under public/ are static assets not meant to be imported.
  5. MSW handlers aligned to the real backend: no /me endpoint exists; the user object is returned by login/refresh. Setup status mocked at /Setup/status to match the backend route.

Notes

  • No pre-commit hooks (NFR-U1-06)
  • No Sentry/OpenTelemetry (NFR-U1-03)
  • Basic a11y only (NFR-U1-02)
  • Bundle optimized via lazy per-feature routes (NFR-U1-01); remaining ~573 kB chunk is vendor code (React/TanStack/Radix/i18next/zod) — acceptable for a scaffold, revisit with vendor chunking if it grows
  • All patterns from NFR Design (Unit 1) are followed