+
Create account
+
+ First account on this server becomes admin and inherits existing local projects.
+
+
+
+ Already have an account?{" "}
+
+ Sign in
+
+
+
+ );
+}
diff --git a/frontend/src/components/layout/auth-gate.tsx b/frontend/src/components/layout/auth-gate.tsx
new file mode 100644
index 0000000..f019577
--- /dev/null
+++ b/frontend/src/components/layout/auth-gate.tsx
@@ -0,0 +1,33 @@
+"use client";
+
+import { useEffect } from "react";
+import { usePathname, useRouter } from "next/navigation";
+import { useOptionalAuth, useOptionalUser } from "@/hooks/use-optional-auth";
+import { localAuthEnabled } from "@/lib/auth";
+
+/** When local auth is on, send unsigned users to /sign-in. */
+export function AuthGate({ children }: { children: React.ReactNode }) {
+ const router = useRouter();
+ const pathname = usePathname();
+ const { isSignedIn } = useOptionalAuth();
+ const { isLoaded } = useOptionalUser();
+
+ useEffect(() => {
+ if (!localAuthEnabled || !isLoaded) return;
+ if (!isSignedIn) {
+ const next = encodeURIComponent(pathname || "/");
+ router.replace(`/sign-in?next=${next}`);
+ }
+ }, [isLoaded, isSignedIn, pathname, router]);
+
+ if (!localAuthEnabled) return <>{children}>;
+ if (!isLoaded) {
+ return (
+