--- phase: 01-foundation-portal-shell plan: 02 subsystem: ui tags: [next-intl, next-themes, zustand, tailwindcss, oklch, i18n, theming, responsive-layout, portal-shell] # Dependency graph requires: - phase: 01-01 provides: "Monorepo scaffold, Next.js app, Tailwind CSS v4, build tooling" provides: - OKLCH design token system with yellow #ffed00 primary and dark gray-blue dark mode - i18n framework with DE/EN translations via next-intl cookie-based locale - Theme switching (light/dark/system) via next-themes with persistence - Sticky header with logo, breadcrumb, theme toggle, locale switcher, user avatar placeholder - Collapsible sidebar (240px to 64px) with Dashboard/Marketplace nav and accordion categories - Mobile responsive layout with hamburger menu and overlay sidebar - Empty dashboard state with "Keine Widgets aktiv" placeholder and add widget button - AppShell layout composition component for all future pages - Zustand sidebar store with localStorage persistence affects: [01-03-portal-shell, phase-2-auth, phase-3-modules, phase-4-marketplace, phase-5-dashboard] # Tech tracking tech-stack: added: [next-intl@4.13, next-themes@0.4.6, zustand@5.0.14] patterns: [design-tokens-oklch, cookie-based-locale, zustand-persist-store, provider-wrapped-layout, responsive-sidebar-overlay] key-files: created: - apps/web/src/app/globals.css - apps/web/src/i18n/request.ts - apps/web/src/messages/de.json - apps/web/src/messages/en.json - apps/web/src/lib/stores/sidebar-store.ts - apps/web/src/components/layout/app-shell.tsx - apps/web/src/components/layout/header.tsx - apps/web/src/components/layout/sidebar.tsx - apps/web/src/components/layout/sidebar-footer.tsx - apps/web/src/components/theme-toggle.tsx - apps/web/src/components/locale-switcher.tsx modified: - apps/web/package.json - apps/web/next.config.ts - apps/web/src/app/layout.tsx - apps/web/src/app/page.tsx key-decisions: - "Used OKLCH color space for all design tokens per Tailwind v4 best practice" - "Dark mode uses oklch(0.17 0.01 260) dark gray-blue for comfortable contrast with yellow primary" - "Cookie-based locale (NEXT_LOCALE) instead of URL routing since portal is a logged-in app" - "Zustand with persist middleware for sidebar state to survive page refreshes" - "CSS custom property --current-sidebar-width for responsive main content margin" - "Added Inter font-family as --font-sans variable for clean modern style" patterns-established: - "Design tokens: All colors as CSS custom properties at :root, theme variants via .dark selector" - "i18n: Every user-visible string through useTranslations() hook, German as default locale" - "State management: Zustand stores in src/lib/stores/ with persist middleware" - "Layout composition: AppShell wraps Header + Sidebar + main content area" - "Component organization: layout/ for structural components, root for reusable UI" - "Responsive: md breakpoint (768px) separates mobile overlay from desktop sidebar" requirements-completed: [PRTAL-01, PRTAL-04, UI-01, UI-02, UI-03] # Metrics duration: 7min completed: 2026-06-18 --- # Phase 1 Plan 02: Portal Shell Summary **Responsive portal shell with OKLCH design tokens (yellow #ffed00 primary), collapsible sidebar, sticky header, DE/EN i18n via next-intl cookies, and light/dark/system theme switching via next-themes** ## Performance - **Duration:** 7 min - **Started:** 2026-06-18T08:21:15Z - **Completed:** 2026-06-18T08:28:41Z - **Tasks:** 2 - **Files modified:** 15 ## Accomplishments - Full design token system with OKLCH colors, sidebar/header layout tokens, and light/dark theme variants - Bilingual interface (DE/EN) with 24 translation keys and cookie-based locale persistence - Complete portal layout: sticky header with branding/actions, collapsible sidebar with nav and categories, responsive main area - Theme toggle cycling light/dark/system with localStorage persistence and SSR-safe mounted guard - Empty dashboard state showing "Keine Widgets aktiv" with add widget button per D-16 ## Task Commits Each task was committed atomically: 1. **Task 1: Design token system + i18n framework + theme provider setup** - `f3791c6` (feat) 2. **Task 2: Portal layout components -- header, sidebar, app shell, interactions** - `6039387` (feat) ## Files Created/Modified - `apps/web/src/app/globals.css` - OKLCH design tokens with @theme inline block, light/dark variants, sidebar tokens, layout dimensions - `apps/web/next.config.ts` - Wrapped with createNextIntlPlugin for i18n support - `apps/web/src/app/layout.tsx` - Async root layout with ThemeProvider and NextIntlClientProvider wrappers - `apps/web/src/i18n/request.ts` - Locale resolution from NEXT_LOCALE cookie, dynamic message import - `apps/web/src/messages/de.json` - German translations (24 keys across 6 namespaces) - `apps/web/src/messages/en.json` - English translations (matching 24 keys) - `apps/web/src/lib/stores/sidebar-store.ts` - Zustand store with isCollapsed, isMobileOpen, persist to localStorage - `apps/web/src/components/layout/header.tsx` - Sticky header: logo left, breadcrumb center, theme/locale/user right, mobile hamburger - `apps/web/src/components/layout/sidebar.tsx` - Collapsible sidebar: Dashboard (active), Marketplace, accordion categories, collapse toggle, mobile overlay - `apps/web/src/components/layout/sidebar-footer.tsx` - Settings icon and user info placeholder - `apps/web/src/components/layout/app-shell.tsx` - Layout composition with responsive main content margin - `apps/web/src/components/theme-toggle.tsx` - Three-state theme cycle with SVG icons and hydration guard - `apps/web/src/components/locale-switcher.tsx` - Cookie-based DE/EN toggle with router.refresh - `apps/web/src/app/page.tsx` - Dashboard page with empty state: grid icon, translated text, add widget button - `apps/web/package.json` - Added next-intl, next-themes, zustand dependencies ## Decisions Made - **OKLCH color space**: Used OKLCH for all design tokens (Tailwind v4 native support) rather than hex/hsl -- provides perceptually uniform color manipulation - **Dark gray-blue dark mode**: Used oklch(0.17 0.01 260) -- comfortable with yellow primary, avoids harsh true-black per user recommendation in D-14 - **Cookie-based locale**: NEXT_LOCALE cookie with 1-year max-age, read server-side by next-intl -- avoids URL routing complexity for portal app - **CSS custom property for main margin**: Used --current-sidebar-width CSS variable with @media query rather than inline style -- cleanly handles responsive breakpoint - **Inter font-family**: Selected Inter as primary font per discretion recommendation for clean modern style ## Deviations from Plan ### Auto-fixed Issues **1. [Rule 2 - Missing Critical] Added i18n for hardcoded strings in mobile sidebar and sidebar footer** - **Found during:** Task 2 (Portal layout components) - **Issue:** Mobile sidebar header had hardcoded "Tessera" text and sidebar footer had hardcoded "User" placeholder -- violated UI-03 requirement - **Fix:** Added tCommon('appName') in sidebar mobile header, t('userPlaceholder') in sidebar footer, common.menu key for hamburger aria-label - **Files modified:** sidebar.tsx, sidebar-footer.tsx, de.json, en.json - **Verification:** grep for hardcoded strings returns no results - **Committed in:** 6039387 (Task 2 commit) --- **Total deviations:** 1 auto-fixed (1 missing critical -- i18n compliance) **Impact on plan:** Essential fix for UI-03 requirement compliance. No scope creep. ## Issues Encountered None - both tasks executed cleanly with type-check and build verification passing. ## User Setup Required None - no external service configuration required. ## Known Stubs - `apps/web/src/components/layout/header.tsx` line 67 - User avatar is a placeholder div (will be wired to auth in Phase 2) - `apps/web/src/components/layout/sidebar-footer.tsx` line 52 - User name shows translation placeholder (will be wired to auth in Phase 2) - `apps/web/src/app/page.tsx` line 40 - Add widget button is non-functional (dashboard implementation in Phase 5) ## Next Phase Readiness - Portal shell is fully functional with theme, i18n, and responsive layout - AppShell component ready to wrap all future page routes - Sidebar navigation entries ready for dynamic population from module registry (Phase 3-4) - Design token system provides consistent theming foundation for all future components - Message file structure supports additional namespaces for future modules ## Self-Check: PASSED All 15 key files verified present. Both commit hashes (f3791c6, 6039387) verified in git log. --- *Phase: 01-foundation-portal-shell* *Completed: 2026-06-18*