diff --git a/src/App.jsx b/src/App.jsx
index 301773a..8aa384e 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -63,6 +63,11 @@ const isPublicRoute = (pathname) => {
return PUBLIC_ROUTES.has(normalized);
};
+// The bare domain is the front door, so it can't be allowed to bounce anonymous
+// visitors to Google — signed out it shows the marketing page, signed in it shows
+// the dashboard as before.
+const ROOT_PATH = '/';
+
const AuthenticatedApp = () => {
const { isLoadingAuth, isLoadingPublicSettings, authError, isAuthenticated, navigateToLogin } = useAuth();
const location = useLocation();
@@ -78,6 +83,14 @@ const AuthenticatedApp = () => {
);
}
+ // Decided on the token rather than on the resolved auth state, so it settles
+ // synchronously: a visitor with no session gets the marketing page on the first
+ // paint instead of watching a spinner for a bootstrap request whose only
+ // possible outcome, for them, is a redirect away.
+ if (location.pathname === ROOT_PATH && !appParams.token) {
+ return ;
+ }
+
// Show loading spinner while checking app public settings or auth
if (isLoadingPublicSettings || isLoadingAuth) {
return (
@@ -92,6 +105,12 @@ const AuthenticatedApp = () => {
if (authError.type === 'user_not_registered') {
return ;
} else if (authError.type === 'auth_required') {
+ // Reaching here on the root path means a token existed but is no longer
+ // good — expired, revoked, or for another app. Treating that as signed out
+ // keeps the front door open instead of trapping it in a login redirect.
+ if (location.pathname === ROOT_PATH) {
+ return ;
+ }
// Redirect to login automatically
navigateToLogin();
return null;