BrowserRouter without a basename sees /lusa-Back-Planner/ as the pathname,
which doesn't match route path="/", so React Router falls to NotFound.
Using import.meta.env.BASE_URL (set by Vite's base config) fixes both
prod and dev environments.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Update CLAUDE.md to use correct mixed-case URL without trailing slash
(lusa-Back-Planner) to match what is registered in Azure AD.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
loginPopup defaults to window.location.href when no redirectUri is set
in the request — causing a mismatch if the user visits a lowercase URL.
Pinning redirectUri from config ensures Microsoft always receives the
exact registered URI regardless of how the user navigated to the app.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Vite caches built assets and reuses them across builds, causing env
variable changes to not take effect. Always wipe dist/ and
node_modules/.vite before building.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
loginRedirect causes interaction_in_progress because MSAL's internal
NavigationClient can't navigate to /lusa-Back-Planner/ (base path)
via React Router after returning from Microsoft auth — leaving the
interaction lock set. loginPopup avoids the redirect cycle entirely.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Refactor auth init: initialize MSAL before React mounts so MsalProvider
handles handleRedirectPromise exactly once (no double-calls, no stale locks)
- Simplify AuthGuard to pure AuthenticatedTemplate/UnauthenticatedTemplate
- Remove trailing slash from redirect URI to match Azure AD registration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clear stale interaction.status key from localStorage before MSAL
initializes. A failed or interrupted loginRedirect leaves this lock
set, blocking all subsequent auth calls with interaction_in_progress.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Purge stale msal.* keys from sessionStorage before MSAL initializes.
When cache location was switched from sessionStorage to localStorage,
leftover MSAL entries caused Storage.key(i) to return null during
createKeyMaps iteration, crashing isCredentialKey with TypeError.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Switch MSAL cache to localStorage + cookie fallback to fix AADSTS90014 (PKCE state lost on redirect)
- Fix base path and redirect URI to use correct case: lusa-Back-Planner
- Add deploy.sh for server-side build and deploy
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MSAL SPA redirect flow with Azure AD authentication
- AuthGuard wrapper with auto-redirect for unauthenticated users
- Navbar shows logged-in user name and sign out button
- Vite base path set to /lusa-back-planner/ for subdirectory hosting
- Apache config for SPA fallback routing
- Environment variables for Azure AD tenant/client/redirect
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>