- Create settings/layout.tsx with SettingsSidebar and back-to-dashboard link
- Create settings/page.tsx with redirect to /settings/dashboard
- Create settings-sidebar.tsx with Widgets and Calendar nav items, aria-current
- Add Settings link in header user dropdown (gear icon, before logout)
- Add settings namespace (DE+EN) with all category and action keys
- Add widgets namespace (DE+EN) with all widget names, descriptions, error states
- Add header.settings key ("Einstellungen"/"Settings")
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Install react-grid-layout@2.2.3 and react-resizable
- Create widget-registry.tsx with all 4 widget types, WIDGET_CONSTRAINTS, WidgetProps
- Create dashboard-api.ts with fetch/save layout and widget CRUD functions
- Create dashboard-store.ts (Zustand, NO persist — D-05) with edit mode and auto-save on exit
- Create DashboardGrid with react-grid-layout v2 Responsive, ResizeObserver width
- Create ClockWidget using Intl.DateTimeFormat (no manual UTC offsets)
- Create WidgetWrapper with drag handle and delete button in edit mode
- Create EditModeToggle (pencil/checkmark), WidgetCatalogModal (2x2 grid)
- Rewrite portal page.tsx as dashboard with grid, edit toggle, widget catalog
- Add ResizeObserver polyfill in test setup, CSS mock support in vitest config
- All 5 tests green (dashboard grid + clock widget)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove frontend artifacts from 05-03 must_haves (belong to 05-04)
- Remove trailing XML generation artifacts from 05-04 and 05-05
- Update ROADMAP Phase 5: 5 plans across 4 waves
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reduce typography to 4 sizes (12/14/18/28) and 2 weights (400/600).
Clock scaling declared as responsive exception, not standalone size.
Destructive CTAs now include noun (Quelle loeschen / Delete source).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Defines visual and interaction contracts for Phase 05 including
dashboard grid, 4 widget types, settings page, and calendar integration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Human verified marketplace features on localhost. 26 tests green.
Reverse proxy API URL config deferred. Phase 04 done, ready for Phase 05.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Plan 04-03 done — sidebar migrated, 5 new tests (26 total).
Ready for Plan 04-04 (navigation polish).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all raw <a> with Next.js Link. Add usePathname-based active
highlighting, SidebarSearch with category/module filtering, and
sidebarRefreshKey subscription for live activation updates. 26 tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Compact detail view with back link, full description (no line-clamp),
status indicator, and activation controls. Reuses ActivationDialog for
deactivation. 3 tests pass, 21 total green.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Create marketplace-store (Zustand) with sidebarRefreshKey signal and
tenant context. Build /marketplace page with parallel fetch, activation
Map, role gate, empty state, and responsive card grid. All 9 tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 4 tests: card grid rendering, activation status display,
access-denied for non-admin, empty state
- Tests fail as expected (RED phase) - page and store not yet implemented
- Add marketplace namespace to de.json and en.json with all copywriting contract strings
- Add sidebar.search and sidebar.noResults i18n keys
- Create MarketplaceCard with icon, name, localized description, category badge,
status badge (role="status"), and activate/deactivate button
- All 5 unit tests pass (GREEN phase)
- Add vitest, @testing-library/react, @testing-library/jest-dom, jsdom, @vitejs/plugin-react as dev deps
- Create vitest.config.ts with jsdom environment and @ path alias
- Create test setup file importing jest-dom/vitest matchers
- Add test scripts to apps/web and root package.json
- Add test task to turbo.json pipeline
Users naturally type full domains (e.g. "google.de") but the API
validates DNS labels only. Extract the label part before the first
dot to prevent 400 validation errors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ModuleGuard now reads tenantId from req.user?.tenantId as fallback
(same pattern as module-registry controller), and throws 403 instead
of silently allowing access when no tenant context exists.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use window.location.href for full page reload after login (ensures auth state)
- Add API_INTERNAL_URL for server-side requests within Docker network
- Remove unnecessary credentials:'include' from SSR fetch calls
- Update planning state for Phase 03 progress
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Controller now falls back to user.tenantId from JWT when
req.tenantId is null (SUPER_ADMIN without x-tenant-id header).
Also added error display to admin modules page.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Admin modules page at /admin/modules with toggle switches
- Sidebar categories now fetch active modules from API dynamically
- Added "Module" link under admin section in sidebar
- Added i18n keys for module management (DE + EN)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create [moduleSlug] page that loads module component via MODULE_REGISTRY whitelist
- Only registered slugs trigger dynamic imports; unknown slugs show not-found state (T-03-09)
- Create api.ts with getActiveModules and getModuleBySlug utility functions
- Back-link navigation from expanded view to category page
- Create module-loader.ts with MODULE_REGISTRY mapping slugs to dynamic imports (ssr:false)
- Create [category] page fetching active modules from API, filtering by category
- Create ModuleCard component with icon, name, description, and link to expanded view
- Add i18n keys for modules namespace (de + en)
- DNS-based domain availability checking across TLD variants
- Frontend page with input form and color-coded results
- Module self-seeds into registry on startup