AZ-006 — Login and protected navigation
Status
Done
Context
Read README. AZ-002 provides registry/access metadata, responsive shell and a real preferences Settings page. AZ-005 provides cookie/CSRF login/logout/me and user provisioning. The frontend transport is the sole networking boundary; TanStack Query owns server state. Settings must now become authenticated deliberately; Home/message stay public to preserve the original slice.
Goal
Deliver mobile login/logout and correct protected-route/session behavior without stale-user data or credentials in browser storage.
Requirements
- Add a localized MUI
/loginpage registered as public and hidden from side navigation. It uses ordinary vertical labeled email/password inputs, appropriate email keyboard and autocomplete username/current-password, password-manager support, bounded width and touch targets. Allow paste, reveal-password with accessible control, and keyboard submit. No large modal login or desktop-first two-column marketing layout. - Implement auth endpoint wrappers beside existing
app/api/modules, reusingapiRequest. Cookie handling/CSRF acquisition/header injection stays there. Use credentials appropriate to the configured supported origin model (include when configured); never read HttpOnly cookie, store token/session ID in Redux/localStorage, or bypass CSRF/origin validation. A transient in-memory CSRF token is allowed; clear/reacquire after session rotation and expiry. - Cache
/auth/meonly through TanStack Query with stable key; pending, authenticated, unauthenticated and transport/server-failure states are distinct. A known 401 is normal unauthenticated state, with no redundant retry. A network/500 error is a recoverable failure, not a redirect that masquerades as logout. Do not mirror DTO in Redux. - Enforce registry authenticated access through a small React Router layout/guard. Direct Settings
URLs, refresh, browser back and unknown routes work; while session is resolving show accessible
progress rather than protected-content flash. Logged-out Settings redirects to
/loginwith a safe internal return destination. Validate destination to reject external, protocol-relative and recursive auth URLs; default to/settingsafter login. - Protect
/settingsand show its navigation entry only to authenticated users; Home remains available. The shell exposes an appropriately labeled login action when anonymous and current display name/logout when authenticated. Login is not a fake ordinary menu page. Backend authorization remains authoritative regardless of menu/guard visibility. - Keep language selection available on the public login page using the existing device-preference control, since Settings is now protected. Later public recovery pages reuse it. This must not require a session or write another user's account settings; AZ-007 defines account precedence.
- Successful login invalidates/refetches me, acquires new CSRF state and navigates safely. Disable duplicate submits; render generic translated invalid-credentials and rate-limit state with Retry-After guidance. Inline field errors follow AZ-003 focus/summary conventions. Do not display server exception messages or announce password content.
- Logout waits for confirmed server invalidation, then cancels/removes authenticated queries, clears session-derived state and resets CSRF. A network failure must not report successful server logout; show retry guidance while preventing accidental presentation of stale sensitive data. Expired/401 protected queries clear authenticated caches and return to login coherently; no redirect loops, notification floods, or automatic replay of failed mutations.
- During login/account switching and logout, cancel in-flight authenticated requests and ensure late responses from the old user cannot repopulate the cache. Query keys/ownership must be explicit before AZ-007 adds mutable profile data. Public message queries need not be discarded.
- Update browser E2E fixtures to create per-test users before real API/browser login, with distinct mobile/desktop identities and cleanup. Keep Chromium projects from AZ-002. Login, refresh/current user, direct protection and logout journeys exercise real backend/PostgreSQL; no mocked auth API as E2E proof. Exclude password values/cookies from failure diagnostics.
Non-goals
No account editing/recovery yet, self-registration, role authorization, external provider widgets, persisted bearer tokens, generic auth state machine, multi-tab synchronization platform or private ordering workflow.
Implementation guidance
Extend registry/router/providers/API modules and existing RTL renderApp, with injected controlled
HTTP for frontend integration tests. Use MUI input labels/helper text, proper alert/status regions
and route-heading focus. Keep session mutation retries off; Query's default read retry is not a
reason to retry login/logout automatically. No raw fetch or status checks in page components. Use
stable app/provider instances to prevent current-user requests on every render.
Acceptance criteria
- Login/logout work in canonical local Docker and at mobile/desktop viewports using real cookies/CSRF; password managers/paste/keyboard are supported.
- Protected direct routes show no private content before auth; safe redirects restore the intended route, and public Home/message still work anonymously.
- Session pending, 401 and server/network failures have distinct usable outcomes.
- Logout/expiry/account switching removes private cache and rejects late old-user responses.
- No session credentials or user DTOs are persisted in local browser preference storage.
Verification
pnpm quality
pnpm --filter @foodtruck-order/frontend test
pnpm --filter @foodtruck-order/frontend test:coverage
pnpm build
pnpm validate:docker
RTL tests cover guards/navigation, unsafe return URLs, failure/rate-limit/focus and cache races; Playwright proves the real mobile/desktop session journeys. Manually test 320/360px, tablet, desktop, phone virtual keyboard, password autofill, 200% zoom, Escape/focus and back navigation. Check protected-route refresh through nginx SPA fallback. Hosted same-site cookie behavior needs its own target evidence when release is authorized; do not claim it from localhost.
Documentation
Update development (login/provisioning/return routes, protected page registration), architecture (auth/query/cache ownership), testing (real auth fixtures and races), current-state/handover. Update Docker/CI if fixture lifecycle changes; never introduce hosted credentials in test jobs.
Dependencies
AZ-005 and its predecessors; app registry/theme/preferences and error conventions already exist.