diff --git a/src/app/dashboard/layout.tsx b/src/app/dashboard/layout.tsx
index 01dd9d6..75307d4 100644
--- a/src/app/dashboard/layout.tsx
+++ b/src/app/dashboard/layout.tsx
@@ -1,13 +1,25 @@
import { Sidebar } from "@/components/layout/sidebar";
import { AuthGate } from "@/components/auth-gate";
+import { SiteScopeProvider } from "@/components/layout/site-scope-provider";
+import { getSiteScope, scopeFallbackValue } from "@/lib/site-scope";
+
+export const dynamic = "force-dynamic";
+
+export default async function DashboardLayout({ children }: { children: React.ReactNode }) {
+ // No searchParams here — layouts cannot read them and do not re-render
+ // on navigation. This call supplies `allowed` (stable for the session)
+ // and the cookie-resolved default; the switcher reads the live value
+ // from the URL itself.
+ const scope = await getSiteScope();
-export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
-
+
+
+
);
}
diff --git a/src/components/layout/site-scope-provider.tsx b/src/components/layout/site-scope-provider.tsx
new file mode 100644
index 0000000..c0523c1
--- /dev/null
+++ b/src/components/layout/site-scope-provider.tsx
@@ -0,0 +1,37 @@
+"use client";
+
+import * as React from "react";
+import type { ScopeSite } from "@/lib/site-scope";
+
+interface SiteScopeContextValue {
+ /** Every site the user may see. Loaded once by the dashboard layout. */
+ allowed: ScopeSite[];
+ /**
+ * What to show when the URL carries no ?site= — the cookie-resolved
+ * default. Deliberately NOT the active scope: active always comes
+ * from useSearchParams() so the control's state is the URL.
+ */
+ fallbackValue: string;
+}
+
+const SiteScopeContext = React.createContext(
+ undefined
+);
+
+export function SiteScopeProvider({
+ allowed,
+ fallbackValue,
+ children,
+}: SiteScopeContextValue & { children: React.ReactNode }) {
+ const value = React.useMemo(
+ () => ({ allowed, fallbackValue }),
+ [allowed, fallbackValue]
+ );
+ return {children};
+}
+
+export function useSiteScope() {
+ const ctx = React.useContext(SiteScopeContext);
+ if (!ctx) throw new Error("useSiteScope must be used inside SiteScopeProvider");
+ return ctx;
+}