FrontendRouting
Overview
App Router structure with route groups and nested layouts.
HyperSaaS uses Next.js App Router with route groups to separate public, authenticated, and dashboard areas — each with its own layout and navigation.
Route Architecture
src/app/
├── layout.tsx # Root: fonts, theme, toaster
├── (marketing)/ # Public: header + footer
│ ├── layout.tsx
│ ├── page.tsx # /
│ ├── pricing/ # /pricing
│ ├── features/ # /features
│ ├── blog/ # /blog, /blog/[slug]
│ └── ...
├── (auth)/ # Minimal: no nav
│ ├── layout.tsx
│ ├── login/ # /login
│ ├── register/ # /register
│ └── ...
├── (dashboard)/ # Protected: sidebar + breadcrumbs
│ └── dashboard/
│ ├── layout.tsx
│ └── workspaces/
│ └── [workspaceId]/
│ ├── layout.tsx # Sidebar with workspace context
│ ├── chat/
│ ├── documents/
│ ├── knowledge-bases/
│ ├── teams/
│ └── settings/
├── (workspaces)/ # Workspace list
├── (invitations)/ # Invitation acceptance
├── (chats)/ # Public shared chats
└── api/ # API route handlersLayout Hierarchy
Each route group provides its own layout, and they don't interfere with each other:
Root Layout (fonts, theme, toaster)
│
├── Marketing Layout (header, footer, session provider)
│
├── Auth Layout (minimal wrapper)
│
└── Dashboard Layout
└── Workspace Layout (sidebar, breadcrumbs, auth check)
└── Chat Layout (flex container, overflow control)URL Structure
| Route | Page | Auth |
|---|---|---|
/ | Home (marketing) | No |
/pricing | Pricing page | No |
/features | Features page | No |
/blog | Blog listing | No |
/blog/[slug] | Blog post | No |
/login | Login form | No |
/register | Registration form | No |
/dashboard | Workspace list | Yes |
/dashboard/workspaces/[id] | Workspace home | Yes |
/dashboard/workspaces/[id]/chat | New chat | Yes |
/dashboard/workspaces/[id]/chat/[chatId] | Chat session | Yes |
/dashboard/workspaces/[id]/chat/history | Chat history | Yes |
/dashboard/workspaces/[id]/documents | Documents | Yes |
/dashboard/workspaces/[id]/knowledge-bases | Knowledge bases | Yes |
/dashboard/workspaces/[id]/knowledge-bases/[kbId] | KB detail | Yes |
/dashboard/workspaces/[id]/teams | Teams | Yes |
/dashboard/workspaces/[id]/teams/[teamId] | Team detail | Yes |
/dashboard/workspaces/[id]/settings | Workspace settings | Yes |
/dashboard/workspaces/[id]/details | Workspace details | Yes |
/invitations/accept/[id] | Accept invitation | Yes |
/chats/[wsId]/[shareableLink] | Shared chat (public) | No |
Workspace Context Flow
The workspace layout ([workspaceId]/layout.tsx) is the central authority for workspace context:
export default async function WorkspaceLayout({ children, params }) {
const { workspaceId } = await params;
// 1. Authenticate
const user = await getCurrentUserServer();
// 2. Fetch workspaces
const workspaces = await getUserWorkspaces();
// 3. Validate access
const currentWorkspace = workspaces.find(w => w.id === workspaceId);
if (!currentWorkspace) redirect("/dashboard");
// 4. Render shell with sidebar
return (
<NextAuthSesionProvider session={session}>
<SidebarProvider>
<AppSidebar
workspaces={workspaces}
user={user}
currentWorkspaceId={workspaceId}
/>
<main>{children}</main>
</SidebarProvider>
</NextAuthSesionProvider>
);
}All child pages inherit the authenticated user and workspace context.