# Code Generation Plan — Unit 2: Authentication Pages **Status**: 📋 Ready for approval ## Unit Context **Unit**: Unit 2 — Authentication Pages **Type**: Frontend (React/TypeScript with TanStack Router) **Depends on**: Unit 1 (ApiClient, AuthContext, router.tsx, MSW, shadcn primitives) **Stories Covered**: US-01, US-02, US-03, US-04, US-05, US-06, US-07, US-13, US-14 (9 user stories) **Key Deliverables**: - SetupPage component (first Owner account creation with language preference) - InviteCompletePage component (user invitation completion with token validation) - InitGuard hook (system initialization status check before route access) - RoleGuard hook (role-based access control for protected routes) - API hooks: useSetup, useValidateInvitation, useCompleteInvitation - Shared password validation schema (src/lib/schemas/auth.ts) - Error handling components (FormErrorBanner, FieldError) - i18n translations (extend translation.json for setup/invite/errors) - MSW mock handlers (extend setupHandlers, new invitationHandlers) - Unit tests for all components, hooks, and API integration --- ## Code Generation Steps ### Step 1: Create Shared Password Validation Schema - [x] Create `src/lib/schemas/auth.ts` with: - `passwordSchema` — Zod validation (8+ chars, uppercase, digit, special) - `confirmPasswordSchema` — Confirm password field - Export both for use in SetupPage, InviteCompletePage, LoginPage - [ ] Validate schema with LoginPage password validation (ensure alignment) - [ ] **Story traceability**: US-01 (login), US-06 (setup), US-13 (invite complete) ### Step 2: Create FormErrorBanner Component - [ ] Create `src/components/ui/FormErrorBanner.tsx`: - Props: `error: FormError | null`, `onDismiss: () => void` - Red background with error message - Dismissible close button - Fade animation on dismiss - [ ] Add `data-testid="form-error-banner"` attribute - [ ] **Story traceability**: US-06, US-13 (error display) ### Step 3: Create FieldError Component - [ ] Create `src/components/ui/FieldError.tsx`: - Props: `message?: string` - Small red text below input field - Only render if message exists - [ ] Add `data-testid="field-error-[fieldname]"` attributes - [ ] **Story traceability**: US-06, US-13 (field validation) ### Step 4: Create API Hooks — Setup - [ ] Create `src/api/useSetup.ts`: - `useSetup()` hook for POST /Setup - Returns: `{ mutate, isLoading, error }` - Request: `{ name, email, password, language }` - Response: `SetupResponse` with user data - Error handling: ProblemDetails format - [ ] Add error logging for debugging - [ ] **Story traceability**: US-06 (initialize system) ### Step 5: Create API Hooks — Invitation - [ ] Create `src/api/useInvitation.ts`: - `useValidateInvitation(token: string)` — GET /Invitation/validate - Auto-runs on mount if token provided - Returns: `{ data, isLoading, error }` - `useCompleteInvitation()` — POST /Invitation/complete - Returns: `{ mutate, isLoading, error }` - Request: `{ token, name, password }` - Response: `InvitationCompletionResponse` with user data - Error handling: ProblemDetails format - [ ] Add loading/error state management - [ ] **Story traceability**: US-13, US-14 (complete invitation) ### Step 6: Extend Password Schema in LoginPage - [ ] Modify `src/pages/LoginPage.tsx`: - Update to use shared `passwordSchema` from `src/lib/schemas/auth.ts` - Ensure no duplicate definitions - Maintain existing LoginPage functionality - [ ] Run tests to ensure no regressions - [ ] **Story traceability**: US-01 (login) ### Step 7: Create SetupPage Component - [ ] Create `src/pages/SetupPage.tsx`: - Form fields: name, email, password, confirmPassword, language - Use react-hook-form + Zod (shared passwordSchema) - Form state: `{ isLoading, error }` - Submit: POST /Setup via useSetup hook - Validation: Real-time inline (onBlur) + banner (onSubmit) - Success: Show success message → redirect to /login after 2–3 sec - Error: Show error banner with backend message - [ ] Add data-testid attributes (form, fields, button) - [ ] Use shadcn primitives (Button, Input, Label, Card) - [ ] Use FormErrorBanner + FieldError for error display - [ ] Add i18n keys: `setup.*` - [ ] **Story traceability**: US-06 (initialize system), US-07 (redirect to setup) ### Step 8: Create InviteCompletePage Component - [ ] Create `src/pages/InviteCompletePage.tsx`: - Extract token from URL query param - On mount: validate token via useValidateInvitation - States: loading → form/error - If valid: Show form (email read-only, name, password, confirmPassword) - If invalid: Show error state with link for new invitation - Submit: POST /Invitation/complete - Validation: Real-time inline + banner - Success: Show success message → redirect to /login - Error: Show error banner - [ ] Add data-testid attributes - [ ] Use shadcn primitives - [ ] Use FormErrorBanner + FieldError - [ ] Add i18n keys: `inviteComplete.*` - [ ] **Story traceability**: US-13, US-14 ### Step 9: Create InitGuard Hook - [ ] Create `src/auth/InitGuard.tsx`: - Hook: `useInitGuard(): { initialized, isLoading, error }` - Calls `GET /Setup/status` on app mount - Caching: `staleTime: Infinity` (session-level) - Integrate into `src/router.tsx` — `__root.tsx` route `beforeLoad` - Bypass routes: `/setup`, `/login`, `/invite/complete` - [ ] **Story traceability**: US-07 ### Step 10: Create RoleGuard Integration - [ ] Implement RoleGuard logic in `src/router.tsx`: - `/users`: Owner or Admin role required - `/settings`: Owner role required - `/cms`: Owner role required - Page-level inline "Access Denied" message if denied - [ ] **Story traceability**: Role-restricted routes ### Step 11: Extend i18n Translations - [ ] Modify `src/i18n/locales/en/translation.json`: - Add `setup`, `inviteComplete`, extend `errors` sections - [ ] Modify `src/i18n/locales/nl/translation.json`: - Mirror structure in Dutch - [ ] Verify both locales are valid JSON - [ ] **Story traceability**: All UI strings ### Step 12: Extend MSW Mock Handlers — Setup - [ ] Modify `src/mocks/setup/`: - Extend `GET /Setup/status` - Add `POST /Setup` handler - After POST: mark `initialized: true` - [ ] **Story traceability**: US-06 ### Step 13: Create MSW Mock Handlers — Invitation - [ ] Create `src/mocks/invitation/index.ts`: - Export `invitationHandlers` - `GET /Invitation/validate?token=xxx` - `POST /Invitation/complete` - Add to `src/mocks/browser.ts` and `src/mocks/server.ts` - [ ] **Story traceability**: US-13, US-14 ### Step 14: Update MSW Handler Index - [ ] Modify `src/mocks/index.ts`: - Export `invitationHandlers` ### Step 15: Create Unit Tests — SetupPage - [ ] Create `src/pages/SetupPage.test.tsx`: - Successful setup flow - Validation errors (inline + banner) - Backend errors - Network error handling - Language selection - [ ] Target: >70% coverage - [ ] **Story traceability**: US-06 ### Step 16: Create Unit Tests — InviteCompletePage - [ ] Create `src/pages/InviteCompletePage.test.tsx`: - Token validation (valid/invalid) - Form fill and submission - Error handling - Read-only email field - [ ] Target: >70% coverage - [ ] **Story traceability**: US-13, US-14 ### Step 17: Create Unit Tests — InitGuard Hook - [ ] Create `src/auth/InitGuard.test.tsx`: - Initialized true/false scenarios - Loading/error states - Session cache behavior - [ ] Target: >80% coverage - [ ] **Story traceability**: US-07 ### Step 18: Create Unit Tests — RoleGuard - [ ] Create tests for RoleGuard logic: - Owner access to restricted routes - Non-Owner denied with inline message - Public routes bypass - [ ] Target: >80% coverage ### Step 19: Create Unit Tests — API Hooks - [ ] Create `src/api/useSetup.test.ts` and `src/api/useInvitation.test.ts`: - Success, error, loading states - Token validation - [ ] Target: >75% coverage ### Step 20: Create Integration Tests - [ ] Create `src/test/integration/unit-2-auth-flow.test.tsx`: - Setup flow end-to-end - Invitation flow end-to-end - Role guard integration - 401 refresh + retry - [ ] Target: Happy path coverage ### Step 21: Update Router Configuration - [ ] Modify `src/router.tsx`: - Add InitGuard to `__root.tsx` - Add `/setup` route (SetupPage) - Add `/invite/complete` route (InviteCompletePage) - Add RoleGuard checks for protected routes - [ ] **Story traceability**: All routing stories ### Step 22: Update README & Documentation - [ ] Update `frontend/README.md`: - New Unit 2 features section - Authentication flow documentation - Role-based access control - [ ] Add brief JSDoc comments to new hooks/components ### Step 23: Final Verification - [ ] [ ] `pnpm build` — no errors - [ ] [ ] `pnpm lint` — all checks pass - [ ] [ ] `pnpm format:check` — formatting correct - [ ] [ ] `pnpm test` — all tests pass - [ ] [ ] Dev server boots, test all flows - [ ] [ ] Coverage: auth-related >70%, core >80% - [ ] [ ] All data-testid attributes present ### Step 24: Commit Changes - [ ] Stage all files - [ ] Create commit with proper message - [ ] Reference stories: US-01–US-07, US-13–US-14 --- ## Total Steps: 24 **Estimated Scope**: 600–800 LOC, 4–6 hours, >70% coverage **Ready for Approval**: Yes