Overview
Build the restaurant dashboard shell — the persistent layout, sidebar navigation, and authentication guard that wraps every page under `/dashboard`. This is the structural foundation that all other dashboard pages (menu editor, analytics, settings) will build inside.
This issue produces no business features by itself, but it must be completed before any other dashboard page can be built.
Figma Reference
📐 Figma: [Dashboard shell — sidebar, header bar, breadcrumb, mobile nav drawer, responsive breakpoints — placeholder, link to be added by design lead]
Routes
All pages under `/dashboard/*` use this layout.
| Path |
Page |
| `/dashboard` |
Home / KPI summary (Sprint 6) — placeholder for now |
| `/dashboard/menu` |
Menu editor (issue #184) |
| `/dashboard/orders` |
Order queue (Sprint 4) — placeholder |
| `/dashboard/analytics` |
Analytics (Sprint 6) — placeholder |
| `/dashboard/settings` |
Restaurant settings (Sprint 6) — placeholder |
File Structure
```
apps/web/app/dashboard/
layout.tsx # Auth guard + DashboardShell wrapper
page.tsx # Placeholder: "Dashboard coming soon"
menu/page.tsx # Issue #184
orders/page.tsx # Placeholder
analytics/page.tsx # Placeholder
settings/page.tsx # Placeholder
components/dashboard/
DashboardShell.tsx # Root layout: sidebar + content area
Sidebar.tsx # Nav links, restaurant name, logo
TopBar.tsx # Page title, user menu (logout)
NavLink.tsx # Active-state-aware link component
```
Authentication Guard
`apps/web/app/dashboard/layout.tsx` must:
- Check if the user is authenticated (read from `AuthContext`)
- If not authenticated → redirect to `/login`
- If authenticated but has no restaurant → redirect to `/onboarding`
- If authenticated and has a restaurant → render the dashboard shell
Use a Client Component for the guard logic (since it reads from context). The children can remain Server Components.
Sidebar Navigation
Links to show:
| Icon |
Label |
Path |
| 🏠 |
Dashboard |
`/dashboard` |
| 🍽️ |
Menu |
`/dashboard/menu` |
| 📋 |
Orders |
`/dashboard/orders` |
| 📊 |
Analytics |
`/dashboard/analytics` |
| ⚙️ |
Settings |
`/dashboard/settings` |
Use real icons from a package (e.g. `lucide-react`) — not emoji.
Active link: highlight the current route's nav item.
Bottom of sidebar: restaurant logo thumbnail + restaurant name (fetched from context or API).
Top Bar
- Page title (dynamic — passed via a context or layout slot)
- User email or display name
- Logout button (calls `useAuth().logout()` then redirects to `/login`)
Responsive Behaviour
| Breakpoint |
Behaviour |
| ≥ 1024 px |
Sidebar always visible on the left |
| < 1024 px |
Sidebar hidden; hamburger button in top bar opens a slide-in drawer |
Placeholder Pages
For dashboard pages not yet built (orders, analytics, settings), render:
```tsx
Coming soon
This section will be available in a future sprint.
\`\`\`
Do not add links to routes that don't exist.
Acceptance Criteria
Out of Scope
- Role-based access (all authenticated restaurant owners see the full sidebar)
- Notifications bell (Sprint 7)
- Dark mode (future)
Overview
Build the restaurant dashboard shell — the persistent layout, sidebar navigation, and authentication guard that wraps every page under `/dashboard`. This is the structural foundation that all other dashboard pages (menu editor, analytics, settings) will build inside.
This issue produces no business features by itself, but it must be completed before any other dashboard page can be built.
Figma Reference
Routes
All pages under `/dashboard/*` use this layout.
File Structure
```
apps/web/app/dashboard/
layout.tsx # Auth guard + DashboardShell wrapper
page.tsx # Placeholder: "Dashboard coming soon"
menu/page.tsx # Issue #184
orders/page.tsx # Placeholder
analytics/page.tsx # Placeholder
settings/page.tsx # Placeholder
components/dashboard/
DashboardShell.tsx # Root layout: sidebar + content area
Sidebar.tsx # Nav links, restaurant name, logo
TopBar.tsx # Page title, user menu (logout)
NavLink.tsx # Active-state-aware link component
```
Authentication Guard
`apps/web/app/dashboard/layout.tsx` must:
Use a Client Component for the guard logic (since it reads from context). The children can remain Server Components.
Sidebar Navigation
Links to show:
Use real icons from a package (e.g. `lucide-react`) — not emoji.
Active link: highlight the current route's nav item.
Bottom of sidebar: restaurant logo thumbnail + restaurant name (fetched from context or API).
Top Bar
Responsive Behaviour
Placeholder Pages
For dashboard pages not yet built (orders, analytics, settings), render:
```tsx
Coming soon
This section will be available in a future sprint.
Do not add links to routes that don't exist.
Acceptance Criteria
Out of Scope