feat: add backup recovery, setup wizard and user-view guards
Magent CI/CD / verify (push) Successful in 5m20s
Magent CI/CD / deploy-beta (push) Successful in 1m41s

This commit is contained in:
2026-09-18 17:23:03 +12:00
parent a6a4a9aa24
commit fd6671cf7e
44 changed files with 4650 additions and 114 deletions
+42
View File
@@ -0,0 +1,42 @@
"use client";
import { usePathname, useRouter } from "next/navigation";
import { useEffect, useState, type ReactNode } from "react";
import { requestJson } from "../lib/api-client";
import { authFetch } from "../lib/auth";
// Backup access stays available so a fresh installation can be restored before
// connecting any apps. This is navigation only; the API enforces admin access.
export default function SetupGate({ children }: { children: ReactNode }) {
const pathname = usePathname();
const router = useRouter();
const bypass = pathname === "/setup" || pathname === "/admin/backups";
const [checked, setChecked] = useState(false);
useEffect(() => {
if (bypass) return;
const controller = new AbortController();
void requestJson<{ setup_required: boolean }>(
"/setup/status",
{ signal: controller.signal, cache: "no-store" },
authFetch,
)
.then((status) => {
if (controller.signal.aborted) return;
if (status.setup_required) router.replace("/setup");
else setChecked(true);
})
.catch(() => {
// Never hide an existing installation during an API outage or rollout.
if (!controller.signal.aborted) setChecked(true);
});
return () => controller.abort();
}, [bypass, router]);
if (bypass || checked) return children;
return (
<main className="card" role="status">
Checking installation...
</main>
);
}