diff --git a/backend/src/middleware/maintenance.js b/backend/src/middleware/maintenance.js index e3be0e0e..37ffb202 100644 --- a/backend/src/middleware/maintenance.js +++ b/backend/src/middleware/maintenance.js @@ -64,10 +64,15 @@ async function checkMaintenanceMode() { // Middleware to enforce maintenance mode async function maintenanceMiddleware(req, res, next) { - // Skip maintenance check for certain paths + // Skip maintenance check for certain paths. Admin auth MUST work during + // maintenance — otherwise enabling it locks every admin out, including + // already-logged-in ones (their /auth/session check would 503 and read as + // logged-out). These are the REAL endpoints: the admin login + session + // routes live under /api/auth, NOT /api/admin (the old /api/admin/login + // entries here matched nothing, which is exactly why the lockout happened). const skipPaths = [ - '/api/admin/login', - '/api/admin/auth/login', + '/api/auth/admin/login', + '/api/auth/session', '/api/public/settings', '/health' ]; diff --git a/frontend/src/components/MaintenanceWrapper.tsx b/frontend/src/components/MaintenanceWrapper.tsx index ccd3e159..f3606e4e 100644 --- a/frontend/src/components/MaintenanceWrapper.tsx +++ b/frontend/src/components/MaintenanceWrapper.tsx @@ -19,6 +19,12 @@ export const MaintenanceWrapper: React.FC = ({ children const [hasAdminSession, setHasAdminSession] = useState(false); const isAdminRoute = location.pathname.startsWith('/admin'); + // The admin login page must ALWAYS render during maintenance — it's how an + // admin gets a session to bypass it. Without this exemption a logged-out + // admin sees the maintenance screen over the login form (catch-22: needs a + // session to get past maintenance, but the login page that grants one is + // hidden). + const isAdminLoginRoute = location.pathname.startsWith('/admin/login'); useEffect(() => { let isMounted = true; @@ -54,7 +60,7 @@ export const MaintenanceWrapper: React.FC = ({ children }); }, [setMaintenanceMode]); - if (isMaintenanceMode && (!isAdminRoute || !hasAdminSession)) { + if (isMaintenanceMode && !isAdminLoginRoute && (!isAdminRoute || !hasAdminSession)) { return ; }