docs(unit-3): Functional design for Layout & Navigation

- Role-filtered sidebar (Owner/Admin/User visibility rules BR-U3-01–06)
- Topbar removed; UserMenu + LanguageSwitcher move to sidebar footer
- Mobile slide-over sidebar with hamburger button
- Theme toggle (light/dark) with localStorage persistence and no-flash init
- New components: MobileBar, SidebarOverlay, ThemeToggle, useTheme
- Unit 2 marked complete in aidlc-state

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 11:44:24 +02:00
co-authored by Claude Haiku 4.5
parent bbb8d5f423
commit 31cc45d79b
6 changed files with 349 additions and 2 deletions
@@ -0,0 +1,65 @@
# Business Rules — Unit 3: Layout & Navigation
## Navigation Visibility Rules (BR-U3-01 through BR-U3-06)
| Route / Item | Owner | Administrator | User | Rule ID |
|---|---|---|---|---|
| Dashboard (`/dashboard`) | ✅ visible | ✅ visible | ✅ visible | BR-U3-01 |
| User Management (`/users`) | ✅ visible | ✅ visible | ❌ hidden | BR-U3-02 |
| System Settings (`/settings`) | ✅ visible | ❌ hidden | ❌ hidden | BR-U3-03 |
| CMS Management (`/cms`) | ✅ visible | ❌ hidden | ❌ hidden | BR-U3-04 |
| Profile (`/profile`) | ✅ visible | ✅ visible | ✅ visible | BR-U3-05 |
| Logout | ✅ visible | ✅ visible | ✅ visible | BR-U3-06 |
Sidebar items are filtered client-side based on `user.role` from `AuthContext`. The backend is the authoritative enforcement point; sidebar filtering is defence-in-depth UX only.
---
## Active Route Highlighting (BR-U3-07)
- The sidebar highlights the nav item whose `to` path matches the current route (TanStack Router `activeProps`).
- Exact match for leaf routes (`/dashboard`, `/profile`); prefix match for section roots (`/users`, `/cms`, `/settings`).
---
## Responsive Behaviour (BR-U3-08)
- On screens **≥ 768px (md)**: sidebar is always visible at fixed width (256px / `w-64`).
- On screens **< 768px**: sidebar is hidden by default; a hamburger button in a slim top bar opens it as a slide-over overlay.
- The mobile overlay closes when: the user taps outside it, taps the close button, or navigates to a new route.
---
## Theme Toggle (BR-U3-09 through BR-U3-12)
| Rule | Description |
|---|---|
| BR-U3-09 | Toggle switches between `light` and `dark` class on `<html>` immediately |
| BR-U3-10 | Chosen theme is persisted in `localStorage` under key `cms-theme` |
| BR-U3-11 | On app load, persisted preference is applied before first render (no flash of unstyled content) |
| BR-U3-12 | If no preference is stored, OS preference (`prefers-color-scheme`) is used as default |
Only `cms-theme` is stored in localStorage — no auth data.
---
## Language Switcher (BR-U3-13)
- The language switcher (`LanguageSwitcher`) is moved from the Topbar into the sidebar footer.
- Behaviour (NL/EN toggle, i18next `changeLanguage`) is unchanged from Unit 1.
---
## Topbar Removal (BR-U3-14)
- The `Topbar` component is removed from `AppLayout`.
- A slim mobile-only bar replaces it (hamburger button + app name) — only rendered on `< md` screens.
- All functionality previously in Topbar (`LanguageSwitcher`, `UserMenu`) moves into the sidebar footer section.
---
## Layout Shell (BR-U3-15)
- `AppLayout` renders: `<Sidebar>` + `<main>` (full remaining width/height).
- No persistent top bar on desktop — the sidebar is the only chrome.
- `<main>` has padding (`p-6`) and fills remaining viewport height.