8.1 KiB
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,refreshsrc/lib/api-client.ts— fetch wrapper with 401 intercept + refresh retrysrc/router.tsx—_authenticatedlayout route withbeforeLoadguard (redirects to/login); public routes:/login,/setup; protected routes:/dashboard,/users,/cmssrc/pages/LoginPage.tsx— fully implemented with react-hook-form + zod, MSW-tested,data-testidattributessrc/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 insrc/pages/; locales insrc/i18n/locales/
Functional Design Steps
- Step 1: Analyze unit stories and responsibilities
- Step 2: Identify open questions (this document)
- Step 3: Collect answers from user
- 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
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
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
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
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
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
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
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
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
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
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
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
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