Admins can toggle maintenance mode from the admin dashboard (new
"Wartung" tab). When active, all non-admin users see a full-page
maintenance screen instead of the app.
- Backend: GET /api/config/service-mode endpoint (authenticated)
- Backend: stores state in app_settings key 'service_mode'
- Frontend: ServiceModeGuard wraps all ProtectedRoutes
- Frontend: ServiceModePage full-screen maintenance UI
- Frontend: ServiceModeTab in admin dashboard with toggle + message
- Admins (dashboard_admin group) always bypass the guard
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Install @mui/x-data-grid in frontend (fixes AuditLog)
- Install jose in backend (fixes authentik service)
- Update .npmrc to use npm.apple.com proxy
- Fix AuditLog localeText to use MUI DataGrid v7 API keys
- Fix banner controller: cast req.params.id to string
- Remove unused logger import in banner.service.ts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- fix dashboard grid: use auto-fill instead of auto-fit for equal-width widgets
- atemschutz: skip stats/members API calls for non-privileged users, hide
empty Aktionen column, add personal status subtitle
- kalender: add permanent delete option for events with confirmation dialog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Layout:
- Remove Container maxWidth cap so widgets scale fluidly on wide screens
- Fix ActivityFeed Card missing height:100% and overflow:hidden that caused
the timeline connector pseudo-element to bleed outside the card boundary
Performance (frontend):
- Migrate VehicleDashboardCard, EquipmentDashboardCard, AtemschutzDashboardCard,
UpcomingEventsWidget, and PersonalWarningsBanner from useEffect+useState to
TanStack Query — cached for 5 min, so navigating back to the dashboard no
longer re-fires all 9 API requests
- Add gcTime:10min and refetchOnWindowFocus:false to QueryClient defaults to
prevent spurious refetches on tab-switch
Backend stability:
- Raise default RATE_LIMIT_MAX from 100 to 300 req/15min — the previous limit
was easily exceeded by a single active user during normal dashboard navigation
- Increase DB connectionTimeoutMillis from 2s to 5s to handle burst-load
scenarios where multiple requests compete for pool slots simultaneously
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- fix(auth): guard extractNames() against Authentik sending full name in
given_name field (e.g. "Matthias Hochmeister" + family_name "Hochmeister");
detect by checking given_name ends with family_name suffix, fall through
to name-splitting so Vorname/Nachname display correctly in Profile
- fix(db): add migration 018 to repair broken BEFORE UPDATE triggers on
veranstaltungen and veranstaltung_kategorien; old triggers called
update_updated_at_column() which references NEW.updated_at, but both
tables use aktualisiert_am, causing every category/event edit to fail
- feat(booking): open vehicle booking creation to all authenticated users;
only dashboard_admin / dashboard_moderator can change the Buchungsart
(type select disabled for regular members); edit and cancel still
restricted to WRITE_GROUPS
- feat(vehicles): VehicleDashboardCard now fetches equipment warnings via
equipmentApi.getVehicleWarnings() in parallel and shows an alert when
any vehicle equipment is not einsatzbereit
- fix(ui): add MuiTextField defaultProps (InputLabelProps.shrink=true) and
MuiOutlinedInput notch legend font-size override to theme to eliminate
floating-label / border conflict on click
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add VehicleDashboardCard: self-contained widget modelled after
AtemschutzDashboardCard, shows einsatzbereit ratio and inspection
warnings inline; replaces StatsCard + InspectionAlerts in Dashboard
- Add EquipmentDashboardCard: consolidated equipment status widget
showing only aggregated counts (no per-item listing); replaces
EquipmentAlerts component in Dashboard
- Fix auth race condition: add authInitialized flag to api.ts so 401
responses during initial token validation no longer trigger a
spurious redirect to /login; save intended destination before login
redirect and restore it after successful auth callback
- Fix profile firstname/lastname: add extractNames() helper to
auth.controller.ts that falls back to splitting userinfo.name when
Authentik does not provide separate given_name/family_name fields;
applied on both create and update paths
- Dynamic groups endpoint: replace hardcoded KNOWN_GROUPS array in
events.controller.ts with a DB query (SELECT DISTINCT unnest
(authentik_groups) FROM users); known slugs get German labels via
lookup map, unknown slugs are humanized automatically
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Link categories to user groups via new zielgruppen column on
veranstaltung_kategorien (migration 017), editable in the category
management UI with group checkboxes and chip display
- Fix broken iCal share link by adding ICAL_BASE_URL to docker-compose
and falling back to CORS_ORIGIN when ICAL_BASE_URL is unset
- Remove the colored-dot legend footer from the month calendar view
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>