- CSV import dialog shows format line + example before mode selection
- Exchange connection test: on 401, inline hint lists common causes
(wrong credentials, domain format, username prefix, O365 not supported)
- Both de/en translations updated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- testConnection now returns { success, message? } instead of boolean so
admins see the actual EWS/IMAP error in the UI rather than "Unbekannter Fehler"
- Exchange provider: resolveFolder() maps folder string to WellKnownFolderName
(Inbox, SentItems, DeletedItems, Drafts, JunkEmail + German aliases)
- InboxConfigForm: folder field now shown for both IMAP and Exchange protocols
with Exchange-specific help text listing valid well-known names
- Controller returns testConnection result directly (no more redundant wrapping)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Server reachable without credentials (port 25 open relay) returns
{ success: true, warning: 'no_auth' } instead of green success.
Frontend shows red warning: server reachable but emails will fail.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
new Date() never throws so the catch was unreachable. Invalid dates rendered
as NaN.NaN.NaN, NaN:NaN Uhr. Use isNaN(d.getTime()) guard to fall back to
the raw string instead.
Backend dkv.service.ts returned { imported } but frontend read result.count,
causing the success toast to always display "undefined Fahrzeuge importiert".
Align backend field name to count and update the dkv-api.ts return type to
include mode for completeness.
- Add 'Allgemein' category section ABOVE existing Dashboard category
- Single SMTP link to /settings/general/smtp with identical active/inactive styling and aria-current
- isActive('/settings/general/smtp') works via pathname.startsWith branch
- Existing Dashboard/Widgets/Calendar items unchanged
- Accept full domains (e.g. "example.xyz") not just labels
- Check the entered TLD as primary result
- Show .de, .com, .net, .org as alternative suggestions below
- Primary result highlighted with accent border
- Input without TLD still works (shows all 4 suggestions)
- Updated i18n placeholders and added "suggestions" label
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- calendar-settings-panel.tsx: source list with color dots, type badges, visibility toggle (CAL-02), edit/delete actions, connection test auto-run, delete confirmation dialog
- calendar-source-form.tsx: add/edit form with name/type/URL/credentials/color; Exchange-mode select for exchange type; username/password hidden for ICS; client-side https-only validation (T-05-14)
- settings/dashboard/calendar/page.tsx: route page rendering CalendarSettingsPanel
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Three test cases: source list with name/type/visibility, visibility toggle calls updateSource, form validation
- Mocks calendar-api functions following existing test patterns
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- calendar-api.ts: fetchSources/addSource/updateSource/deleteSource/testSource/fetchEvents with credentials:'include'
- calendar-widget.tsx: upcoming-events list with source color dots, three empty states (no sources/no events/loading)
- widget-registry.tsx: wireCalendarWidget() replaces placeholder with real CalendarWidget
- page.tsx: wires CalendarWidget into registry on mount
- i18n: added calendar.loading key to de.json and en.json
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Three test cases: event rendering with color dots, no-events empty state, no-sources empty state
- Mocks calendar-api and next-intl following existing test patterns
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SearchWidget: provider dropdown, text input, button; opens search in new tab via window.open (D-14/D-15)
- NoteWidget: MDEditor with compact toolbar, debounced autosave (1500ms), AbortController for in-flight cancellation (D-16/D-17/D-18)
- rehype-sanitize enabled for Markdown XSS prevention (T-05-05)
- Widget registry updated with wireSearchWidget/wireNoteWidget (no more placeholders)
- dashboard-api.ts: added fetchSearchProviders, addSearchProvider, removeSearchProvider, signal support on updateWidgetConfig
- 9 new tests passing (search: 5, note: 4)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
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>
- 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)
- DomainInput component with text input and submit button
- ResultList component with green/red status badges (D-01)
- checkDomainAction fetches POST /modules/domaincheck/check with auth cookie
- Page renders within portal AppShell at /modules/domaincheck
- i18n keys added for both DE and EN locales
- Create split-screen login page with branding left (#ffed00) and form right (D-01)
- Login form has username, password, and remember-me checkbox (D-02)
- Wire header user avatar with auth store: shows user initial, dropdown with role badge and logout
- Wire sidebar footer with auth store: shows user name, role, and initial
- Add auth, header role, and admin i18n keys to both de.json and en.json
- All new UI strings use t() function (no hardcoded text)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Create (auth) route group with standalone layout (no sidebar/header, D-04)
- Create (portal) route group wrapping children with AppShell
- Move dashboard page into (portal) route group
- Add Next.js middleware for JWT-based route protection using jose
- Create session.ts with verifySession/getSessionFromCookies helpers
- Create auth-actions.ts server actions: login, logout, fetchCurrentUser
- Create Zustand auth-store for client-side user state
- Install jose and zod dependencies
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>