# Functional Design Plan — Unit 2: Authentication Pages **Status**: ✅ Complete — awaiting approval ## Plan Context - **Unit**: Unit 2 — Authentication Pages - **Depends on**: Unit 1 (ApiClient, AuthContext, router.tsx, shadcn primitives, MSW handlers) - **Stories Covered**: US-01, US-02, US-03, US-04, US-05, US-06, US-07, US-13, US-14 - **Stages to Execute**: Functional Design → Code Generation (NFR + Infrastructure skipped for this unit) ## Unit 1 Context (Already Delivered) Unit 1 already provided the following that Unit 2 builds on: - `src/contexts/AuthProvider.tsx` + `src/contexts/auth-context.ts` — `user`, `accessToken` (memory), `login`, `logout`, `refresh` - `src/lib/api-client.ts` — fetch wrapper with 401 intercept + refresh retry - `src/router.tsx` — `_authenticated` layout route with `beforeLoad` guard (redirects to `/login`); public routes: `/login`, `/setup`; protected routes: `/dashboard`, `/users`, `/cms` - `src/pages/LoginPage.tsx` — fully implemented with react-hook-form + zod, MSW-tested, `data-testid` attributes - `src/mocks/` — `authHandlers` (login, refresh, revoke), `setupHandlers` (setup status at `/Setup/status`), `userHandlers` - Tailwind v4 + shadcn primitives (Button, Input, Label, Card, DropdownMenu, Toaster) - Deviations: code-based routing in `router.tsx`; pages in `src/pages/`; locales in `src/i18n/locales/` ## Functional Design Steps - [x] Step 1: Analyze unit stories and responsibilities - [x] Step 2: Identify open questions (this document) - [x] Step 3: Collect answers from user - [x] Step 4: Generate functional design artifacts --- ## Questions Answer each question by filling in the `[Answer]:` tag below it. --- ### Q1 — SetupPage: Fields to collect The SetupPage is shown when the system is not yet initialized (`initialized: false` from `GET /Setup/status`). The backend `POST /Setup` endpoint creates the first Owner account. Which fields should the SetupPage form collect? A) Email + Password + Confirm Password (name comes from the email prefix or can be set later in Profile) B) Name + Email + Password + Confirm Password C) Name + Email + Password + Confirm Password + a "language/locale" preference D) Other [Answer]: C --- ### Q2 — SetupPage: Action after successful setup When `POST /Setup` succeeds and the first Owner account is created, what should happen? A) Automatically log in the user (call `AuthContext.login()`) and redirect to `/dashboard` B) Show a success message and redirect to `/login` so the user can log in manually C) Show a success message on the same page with a "Go to login" button D) Other [Answer]: B --- ### Q3 — InviteCompletePage: Fields to collect The InviteCompletePage is reached via a link like `/invite/complete?token=xxx`. The backend validates the token and completes account setup. Which fields should the form collect? A) Name + Password + Confirm Password (email is known from the invitation and shown read-only) B) Password + Confirm Password only (name can be set later in Profile) C) Name + Password + Confirm Password + email shown read-only as informational D) Other [Answer]: C --- ### Q4 — InviteCompletePage: Token validation timing When should the invitation token be validated? A) On page mount (GET request to validate token), then show form only if valid — show error page directly if invalid/expired B) On form submit only — show validation errors after the user tries to submit C) On page mount with a loading state, then switch to form (valid) or error state (invalid/expired) D) Other [Answer]: C --- ### Q5 — InviteCompletePage: Action after successful completion When `POST /Invitation/complete` succeeds, what should happen? A) Automatically log in the user and redirect to `/dashboard` B) Show a success message and redirect to `/login` C) Show a success message with a "Go to login" button D) Other [Answer]: B --- ### Q6 — InitGuard: Caching strategy The `InitGuard` checks `GET /Setup/status` and redirects to `/setup` if `initialized: false`. It must run before every route renders (in the root route). How should setup status be cached? A) Cache for the session (once loaded, never re-fetch — a setup operation redirects back to login anyway) B) Refresh every time the app is loaded/refreshed (staleTime: 0 — always re-fetch on mount) C) Short stale time, e.g., 60 seconds (balance between freshness and extra requests) D) Other [Answer]: A --- ### Q7 — InitGuard: Routes that bypass the guard Which routes should bypass the `InitGuard` (i.e., be accessible even when `initialized: false`)? A) Only `/setup` bypasses the guard (all other routes redirect to `/setup` if not initialized) B) `/setup` and `/invite/complete` bypass the guard C) `/setup`, `/invite/complete`, and `/login` bypass the guard D) Other [Answer]: A --- ### Q8 — RoleGuard: Role model The application has user roles. The backend returns a `role` field on the authenticated user. What roles exist in the system? A) Two roles: `Owner` and `User` B) Three roles: `Owner`, `Admin`, and `User` C) The roles match what's already defined in the backend (check `ApplicationUser` or `UserRole` enum in the existing code) D) Other [Answer]: D, This should already be defined in the back-end, but it should be `Owner`, `Admin` and `User` --- ### Q9 — RoleGuard: Which routes are role-restricted? Which routes require a specific minimum role? A) Only `/settings` and `/cms` require `Owner` role; `/users` requires `Owner` or `Admin`; `/dashboard` and `/profile` are accessible to all authenticated users B) `/users`, `/settings`, and `/cms` all require `Owner` role; `/dashboard` and `/profile` for all roles C) `/cms` requires `Owner`; `/settings` requires `Owner`; `/users` is open to all authenticated users D) Other [Answer]: A --- ### Q10 — RoleGuard: Unauthorized behavior When an authenticated user tries to access a route they don't have the role for, what should happen? A) Redirect to `/403` (Access Denied page — already in Unit 6 scope but can be a simple inline message for now) B) Redirect to `/dashboard` with a toast notification C) Show an inline "Access Denied" message on the page itself (no separate route needed) D) Other [Answer]: C --- ### Q11 — Password validation rules The backend enforces specific password rules. Unit 1 already has Zod schemas. Where should the shared password Zod schema live? A) In `src/lib/validation.ts` — a shared module imported by both LoginPage and the new pages B) In each page file separately (duplicated for isolation) C) In `src/lib/schemas/auth.ts` — a dedicated auth schemas file D) Other [Answer]: C --- ### Q12 — i18n: Translation keys for Unit 2 Unit 1 already added `login` namespace keys. For Unit 2 pages, how should translation keys be organized? A) Add `setup` and `inviteComplete` keys to the existing `translation.json` files (single namespace per locale) B) Separate namespace files: `setup.json` and `inviteComplete.json` lazy-loaded per page C) Extend existing `translation.json` with a `setup` section and `inviteComplete` section D) Other [Answer]: C --- ### Q13 — MSW handler scope for Unit 2 Unit 1 has `setupHandlers` for `GET /Setup/status`. Unit 2 needs handlers for `POST /Setup` (create owner) and invitation endpoints. Where should the new handlers be added? A) Extend existing `setupHandlers` in `src/mocks/setup/` with `POST /Setup` and add `invitationHandlers` in `src/mocks/invitation/` B) Add everything to the existing `setupHandlers` file C) New file `src/mocks/invitation/` for invitation handlers; `POST /Setup` goes into existing setup handlers D) Other [Answer]: A --- ### Q14 — Error handling in forms For form submission errors (network errors, validation errors from the backend), what is the preferred pattern? A) Show errors in a dismissible banner above the form (consistent with LoginPage's existing pattern) B) Show errors inline next to the relevant field C) Show errors in a toast notification (using Sonner, already installed) D) Other [Answer]: D, a combination of A and B. Isn't that also used on the login page. Inline for real live checking, but after submission a banner can be shown. I am not seeing that on the login page now. It should be consistent throughout the app though