- 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>
- 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>