Commit Graph
16 Commits
Author SHA1 Message Date
SluijsensandClaude Haiku 4.5 5331be4279 fix(auth): configurable SameSite cookie for cross-origin dev setup
Chrome 89+ schemeful same-site treats http://localhost and https://localhost
as different sites, blocking SameSite=Strict cookies on cross-origin fetch
(e.g. Vite on port 5173, API on port 7221).

Fix: make CookieSameSite configurable per environment in JwtSettings.
- Default: Strict (production)
- appsettings.Development.json: None (allows cross-origin cookie in dev)
- When SameSite=None, Secure is always forced (browser requirement)

Revert the earlier Vite proxy approach in favour of this backend config.
VITE_API_BASE_URL remains a freely configurable URL in .env.local.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 15:42:56 +02:00
SluijsensandClaude Haiku 4.5 546b773781 fix(auth): add Vite dev proxy to fix SameSite=Strict cookie on page reload
Chrome 89+ treats http://localhost and https://localhost as different sites
(schemeful same-site). The refreshToken cookie (SameSite=Strict) was not
sent when the Vite dev server (HTTP) made cross-origin fetch calls to the
.NET backend (HTTPS), causing a 401 on every page reload.

Fix: route /api/* through the Vite dev server proxy so all requests stay
same-origin. The cookie is now always sent and auth sessions survive reloads.

- vite.config.ts: proxy /api → https://localhost:7221 (secure:false for dev cert)
- .env.example: document proxy vs direct mode, set default VITE_API_BASE_URL to empty
- config.ts: accept empty string as valid apiBaseUrl alongside full URLs

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 15:23:19 +02:00
SluijsensandClaude Haiku 4.5 d8b0484803 fix(availability): translate status messages, return stored admin reason from API
- Add AvailabilityStatusDetails record and GetStatusDetailsAsync() to
  IAvailabilityService; implement in PersistentAvailabilityService so the
  admin-set reason stored in the database is returned alongside the status
- AvailabilityController.GetStatus() now returns the stored message instead
  of hardcoded English strings
- Add messageAvailable / messageMaintenance / messageUnavailable translation
  keys in en + nl so default messages are fully translatable
- AvailabilityStatusBadge: Available always shows the translated default;
  Maintenance and Unavailable show the custom admin reason when set,
  otherwise fall back to the translated default

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 14:53:11 +02:00
SluijsensandClaude Haiku 4.5 d69512a449 fix(i18n): eager-load nl bundle, fix language selector, remove hardcoded backend messages
- Eager-load both en and nl translation bundles at i18n init to eliminate
  the async gap that caused English flash when Dutch was the detected language
- LanguageSwitcher: use i18n.language (synchronous) instead of resolvedLanguage
  (asynchronous) so the visual selection is always correct after switching
- AvailabilityController: remove hardcoded English messages ("System is running
  normally.") from GET /availability/status; return empty string so the frontend
  translations control the display text

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 14:16:27 +02:00
SluijsensandClaude Haiku 4.5 3c6a06028e feat(unit-4): Dashboard — availability widget with TanStack Query
- Add @tanstack/react-query 5.101.0; wrap app with QueryClientProvider
- Add AvailabilityStatus type and AvailabilityResponse to api/types.ts
- Implement useAvailabilityStatus (staleTime 30s, stale-on-error preserved)
- Add AvailabilityStatusBadge with green/amber/red states and stale indicator
- Replace DashboardPage placeholder card with live availability widget
- Add MSW availability handler; update test/utils with QueryClientProvider
- 55/55 tests pass (FR-05)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 13:39:29 +02:00
SluijsensandClaude Haiku 4.5 f476e06691 fix(unit-3): Add settings/profile routes, move profile to UserMenu
- Add /settings (Owner only) and /profile routes under authenticatedRoute
  so sidebar stays visible and layout is preserved
- Create SettingsPage and ProfilePage placeholder components (coming soon)
- Remove Profile nav item from Sidebar — profile now accessible via UserMenu
- Add Profile link to UserMenu dropdown above logout
- Update Sidebar tests to reflect profile-free nav

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 12:56:16 +02:00
SluijsensandClaude Haiku 4.5 76b7bfc09b feat(unit-3): Layout & Navigation — sidebar, mobile overlay, theme toggle
- Remove Topbar; move UserMenu + LanguageSwitcher to sidebar footer
- Add ThemeToggle (dark/light) with localStorage persistence
- Add useTheme hook; no-flash inline script in index.html
- Add MobileBar (hamburger + app name, mobile-only)
- Add SidebarOverlay (slide-in from left, backdrop closes it)
- Sidebar: role-filtered nav (BR-U3-01–06), onClose prop for mobile
- AppLayout: desktop sidebar-only layout, mobile bar + overlay
- i18n: theme.* and nav.openMenu/closeMenu keys (NL + EN)
- Tests: 43/43 passing (14 new — useTheme, Sidebar roles, AppLayout)

Stories: US-08, US-18, US-19

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 12:03:10 +02:00
SluijsensandClaude Haiku 4.5 7237669b14 fix(setup): Apply language choice and fix post-setup redirect
- Call changeLanguage(values.language) after successful owner creation so
  the UI immediately switches to the language the owner chose
- Call _markSystemInitialized() to update the router cache before navigating
  to /login; without this the guard saw initialized=false and redirected
  back to /setup, blocking the redirect

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 11:25:40 +02:00
SluijsensandClaude Haiku 4.5 27490356cb fix(ui): Add type=button to FormErrorBanner dismiss to prevent form resubmit
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 11:20:48 +02:00
SluijsensandClaude Haiku 4.5 2f381d8407 fix(frontend): Strip confirmPassword before API calls; add pointer cursor
- Destructure confirmPassword out of form values in SetupPage and
  InviteCompletePage so it is never sent to the backend
- Add global cursor:pointer rule for buttons, selects, labels and links

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 11:17:20 +02:00
SluijsensandClaude Haiku 4.5 f221d7cee5 fix(unit-2-auth): Redirect to /setup on API failure; store owner display name
- Router catch block now falls back to { initialized: false } instead of
  silently continuing, preventing unwanted redirect to /login when the
  API call fails at startup
- Add Name field to CreateOwnerRequest and propagate to ApplicationUser.DisplayName
  so the owner's display name is stored during initial setup

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 11:06:34 +02:00
SluijsensandClaude Haiku 4.5 8d95754ece fix(unit-2-auth): Fix API endpoint paths and JSON casing for real backend
- Add /api/v1/ prefix to all Unit 2 API calls (Setup/status, Setup/owner,
  Invitation/validate, Invitation/complete) to match backend ApiPrefixConvention
- Fix setup status endpoint to POST /api/v1/Setup/owner (not /Setup)
- Handle PascalCase 'Initialized' response from .NET backend without camelCase policy
- Update all MSW mock handlers to match corrected /api/v1/ URL patterns
- Remove unused imports from RouteGuard.test.tsx

Root cause: backend uses ApiPrefixConvention('api/v1') but frontend calls
were missing the prefix, and .NET defaults to PascalCase JSON serialization.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 10:55:34 +02:00
SluijsensandClaude Haiku 4.5 c9cd0ff457 fix(unit-2-auth): Fix all 4 failing unit tests to 29/29 passing
- Fix invitation MSW handler: use 'valid-token' to match test fixtures
- Add data-testid='setup-success' to SetupPage success state
- Change invite email input from readOnly to disabled (matches test assertion)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 10:20:00 +02:00
SluijsensandClaude Haiku 4.5 53879a891a feat(unit-2-auth): Implement authentication pages and guards
Completes Unit 2 Code Generation (Steps 1-21 of 24):
- SetupPage: First Owner account creation with language preference
- InviteCompletePage: User invitation completion with token validation
- InitGuard: System initialization status checking
- RoleGuard: Role-based access control for protected routes
- API hooks: useSetup, useValidateInvitation, useCompleteInvitation
- Shared password validation schema via Zod
- Error display components: FormErrorBanner, FieldError
- MSW mock handlers for setup and invitation flows
- i18n translations (en/nl) for auth screens
- Router updates: public routes (/setup, /invite/complete) + role guards
- Unit/integration tests: 25/29 passing (86% pass rate)
- Build:  PASSED, Lint:  PASSED, Tests: 86% PASSED

Stories: US-01, US-02, US-03, US-04, US-05, US-06, US-07, US-13, US-14
Remaining: Step 22 (README), Step 23 (final verification), Step 24 (commit)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-22 09:58:28 +02:00
Sluijsens ab93a5c7d1 Adds auth pages 2026-06-21 00:15:28 +02:00
Sluijsens 7dfc3a9692 Adds front-end set-up 2026-06-20 17:04:17 +02:00