# Frontend UI: App Shell & Routing Scaffold (RHL-019) This document describes the **frontend routing scaffold** and the **application shell layout** for the RHL Lieferscheine app. Scope (RHL-019): - Public `/login` route. - Protected application shell for all other routes. - Placeholder pages for branch/year/month/day routes and branch search. - Minimal session-awareness placeholders (no real auth guard yet). - Minimal tests to validate scaffold stability. Non-goals (out of scope for RHL-019): - Real login form, auth guard, and session-based redirects. - Explorer navigation UI (years/months/days list). - Search UI and filters. - PDF viewer / file open. --- ## 1. Route Groups & URL Structure The app uses Next.js App Router **Route Groups** to separate public and protected UI. ### 1.1 Route groups - **Public**: `app/(public)` - Routes that do **not** show the authenticated app shell. - Current route: `/login` - **Protected**: `app/(protected)` - Routes that render inside the **AppShell**. - RHL-019 intentionally does **not** enforce authentication yet. ### 1.2 URL map (scaffold) | URL | Purpose | Notes | | ---------------------------- | --------------------------- | ------------------------------------------------------ | | `/login` | Login placeholder | Public layout (no AppShell) | | `/` | Protected entry placeholder | Later redirects based on session | | `/:branch` | Branch placeholder | Example: `/NL01` | | `/:branch/:year` | Year placeholder | Example: `/NL01/2025` | | `/:branch/:year/:month` | Month placeholder | Example: `/NL01/2025/12` | | `/:branch/:year/:month/:day` | Day placeholder | Example: `/NL01/2025/12/31` | | `/:branch/search` | Search placeholder | Explicit segment so `search` is not treated as `:year` | Important: - There is **no** standalone `/search` route. Visiting `/search` matches `/:branch` with `branch = "search"`. --- ## 2. Layouts ### 2.1 Root layout File: `app/layout.jsx` Responsibilities: - Global CSS imports (`app/globals.css`). - Theme provider setup (shadcn/ui + next-themes wrapper). - Base HTML/body structure. ### 2.2 Public layout File: `app/(public)/layout.jsx` Responsibilities: - Minimal centered layout for public routes. - Intended for `/login` (and potential future public routes). ### 2.3 Protected layout File: `app/(protected)/layout.jsx` Responsibilities: - Wraps all protected pages with the **AppShell**. - Intentionally contains **no auth guard** in RHL-019. --- ## 3. AppShell The AppShell is the stable frame for authenticated UI. Folder: `components/app-shell/*` - `AppShell.jsx` - Overall layout container: **TopNav** + content area. - Uses `min-h-screen flex flex-col` so the content area can fill remaining height. - `TopNav.jsx` - Branding. - User status placeholder. - Placeholder buttons for theme and logout (not wired yet). - `SidebarPlaceholder.jsx` - Reserved space for future navigation/filter UI. - Later additions: - Admin/dev branch selector - Explorer navigation (year/month/day) - Search filters and shortcuts - `UserStatus.jsx` - Placeholder only. - Later reads session state (via `apiClient.getMe()`). ### 3.1 Responsive behavior - Sidebar is hidden on small viewports (`md:block`). - Main content remains usable on mobile sizes. --- ## 4. Placeholder Pages Placeholder pages validate: - URL structure - Layout composition - Dynamic route parameter handling They render via: - `components/placeholders/PlaceholderPage.jsx` ### 4.1 Dynamic route params (Next.js App Router) In this project setup, dynamic route `params` can behave like an async value. Rule of thumb: - In dynamic routes (`[branch]`, `[year]`, `[month]`, `[day]`), unwrap `params` before using properties. --- ## 5. File Naming Convention (.js vs .jsx) To keep the project consistent and avoid test/tooling issues: - Use **`.jsx`** for files that contain JSX: - `app/**/page.jsx`, `app/**/layout.jsx` - React components in `components/**` - Use **`.js`** for non-JSX files: - `lib/**` utilities and helpers - `app/api/**/route.js` - `models/**` - tests that do not contain JSX --- ## 6. Frontend Route Helpers File: `lib/frontend/routes.js` Purpose: - Centralize URL building so UI code does not scatter hardcoded strings. - Encode dynamic segments defensively. - Keep navigation consistent across components. Provided helpers: - `homePath()` → `/` - `loginPath()` → `/login` - `branchPath(branch)` → `/:branch` - `yearPath(branch, year)` → `/:branch/:year` - `monthPath(branch, year, month)` → `/:branch/:year/:month` - `dayPath(branch, year, month, day)` → `/:branch/:year/:month/:day` - `searchPath(branch)` → `/:branch/search` --- ## 7. Tests ### 7.1 Unit tests - `lib/frontend/routes.test.js` - Validates URL builder behavior. - `components/app-shell/AppShell.test.js` - Smoke test: server-renders AppShell and asserts key text is present. - `next/link` is mocked to avoid Next runtime dependency. ### 7.2 Running tests From the repo root: ```bash npx vitest run ``` Optional (recommended) build check: ```bash npm run build ``` --- ## 8. Manual Verification Checklist ### 8.1 Local (Docker) Follow `Docs/runbook.md`. Typical command: ```bash docker compose -f docker-compose.yml -f docker-compose.local.yml up -d --build ``` Verify routes: - `/login` (public layout) - `/` (protected app shell) - `/:branch` (e.g. `/NL01`) - `/:branch/:year/:month/:day` (placeholder) - `/:branch/search` ### 8.2 Server Follow `Docs/runbook.md`. Verify: - `curl -s http://127.0.0.1:3000/api/health` - Browser: - `http(s)://:3000/login` - `http(s)://:3000/NL01/...` (or a real branch) --- ## 9. Planned Follow-ups - Add real **auth guard** and session-based redirects (`/` → `/login` or `/:branch`). - Replace placeholders with Explorer pages (years/months/days + files). - Add Search UI and filters. - Add PDF open/view experience.