Chapter
00 · Root Layout
Global shell, providers only, no domain logic or Prisma.
Mental Model
- Global conductor: wires providers, resolves global permissions, hands off.
- Not an entity; not a place for mutations or Prisma.
- Runs once per navigation; defines the application shell.
- If it gets “smart”, the architecture is broken.
Allowed Imports
// language / config
import "./globals.css";
import { Inter } from "next/font/google";
// context providers (client boundaries)
import Providers from "./providers";
import { EditModeProvider } from "@/contexts/EditModeContext";
import { AIEngineProvider } from "@/contexts/AssistantContext";
// global helpers (no entities)
import { resolveGlobalPermissions } from "./permissions";Typical Signature
export default async function RootLayout({
children,
}: { children: React.ReactNode; }) {
const permissions = await resolveGlobalPermissions(); // context
return (
<html lang="en">
<body>
<EditModeProvider canEdit={permissions.canEdit}>
<AIEngineProvider>
<Providers session={permissions.session}>
{children}
</Providers>
</AIEngineProvider>
</EditModeProvider>
</body>
</html>
);
}Never Do Here (and where it belongs)
- Prisma queries (🟡) → put them in entity actions.
- Business rules → keep in entity/domain services, never in layout.
- Mutations / server actions → belong in app/.../actions.ts files.
- Internal API calls → call actions directly; skip API round-trips from layout.
Colour-Coded Miniature
export default async function RootLayout({
{ children }: {
children: React.ReactNode;
}}) {
const permissions = await resolveGlobalPermissions(); // context read
return (
<html lang="en">
<body>
<EditModeProvider canEdit={permissions.canEdit}>
<AIEngineProvider>
<Providers session={permissions.session}>
{children}
</Providers>
</AIEngineProvider>
</EditModeProvider>
</body>
</html>
);
}Quick Rules
- Root layout = boring, stable shell.
- Providers are fine; logic is not.
- Reads only for global permissions; no Prisma.
- Zero entity intelligence; delegate everything downward.