244 lines
9.1 KiB
Markdown
244 lines
9.1 KiB
Markdown
# 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
|
||
- [ ] 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
|