performance optimierungen, lazy loads etc. - plus requesttimingmiddleware, die lokal die performance trackt und loggt.

This commit is contained in:
Codex Agent
2025-11-05 10:06:29 +01:00
parent b32413b108
commit adb93b5f9d
7 changed files with 116 additions and 48 deletions

View File

@@ -0,0 +1,45 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;
class RequestTimingMiddleware
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$request->attributes->set('_timing_start', microtime(true));
return $next($request);
}
public function terminate(Request $request, Response $response): void
{
if (! app()->environment('local')) {
return;
}
$start = $request->attributes->get('_timing_start');
if (! is_float($start)) {
return;
}
$duration = microtime(true) - $start;
Log::debug('request_timing', [
'path' => $request->path(),
'method' => $request->method(),
'status' => $response->getStatusCode(),
'duration_ms' => round($duration * 1000, 2),
]);
}
}

View File

@@ -46,6 +46,7 @@ return Application::configure(basePath: dirname(__DIR__))
\App\Http\Middleware\ContentSecurityPolicy::class,
HandleInertiaRequests::class,
AddLinkHeadersForPreloadedAssets::class,
\App\Http\Middleware\RequestTimingMiddleware::class,
]);
$middleware->api(append: []);

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { Suspense } from 'react';
import { createRoot } from 'react-dom/client';
import { RouterProvider } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
@@ -9,7 +9,8 @@ import './i18n';
import './dev-tools';
import { initializeTheme } from '@/hooks/use-appearance';
import { OnboardingProgressProvider } from './onboarding';
import { DevTenantSwitcher } from './components/DevTenantSwitcher';
const DevTenantSwitcher = React.lazy(() => import('./components/DevTenantSwitcher'));
const enableDevSwitcher = import.meta.env.DEV || import.meta.env.VITE_ENABLE_TENANT_SWITCHER === 'true';
@@ -28,10 +29,22 @@ createRoot(rootEl).render(
<QueryClientProvider client={queryClient}>
<AuthProvider>
<OnboardingProgressProvider>
<Suspense
fallback={(
<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">
Oberfläche wird geladen
</div>
)}
>
<RouterProvider router={router} />
</Suspense>
</OnboardingProgressProvider>
</AuthProvider>
{enableDevSwitcher ? <DevTenantSwitcher /> : null}
{enableDevSwitcher ? (
<Suspense fallback={null}>
<DevTenantSwitcher />
</Suspense>
) : null}
</QueryClientProvider>
</React.StrictMode>
);

View File

@@ -1,26 +1,5 @@
import React from 'react';
import { createBrowserRouter, Outlet, Navigate, useLocation } from 'react-router-dom';
import LoginPage from './pages/LoginPage';
import DashboardPage from './pages/DashboardPage';
import EventsPage from './pages/EventsPage';
import SettingsPage from './pages/SettingsPage';
import EventFormPage from './pages/EventFormPage';
import EventPhotosPage from './pages/EventPhotosPage';
import EventDetailPage from './pages/EventDetailPage';
import EventMembersPage from './pages/EventMembersPage';
import EventTasksPage from './pages/EventTasksPage';
import EventToolkitPage from './pages/EventToolkitPage';
import EventInvitesPage from './pages/EventInvitesPage';
import EngagementPage from './pages/EngagementPage';
import BillingPage from './pages/BillingPage';
import TasksPage from './pages/TasksPage';
import TaskCollectionsPage from './pages/TaskCollectionsPage';
import EmotionsPage from './pages/EmotionsPage';
import AuthCallbackPage from './pages/AuthCallbackPage';
import WelcomeTeaserPage from './pages/WelcomeTeaserPage';
import LoginStartPage from './pages/LoginStartPage';
import ProfilePage from './pages/ProfilePage';
import LogoutPage from './pages/LogoutPage';
import { useAuth } from './auth/context';
import {
ADMIN_BASE_PATH,
@@ -31,10 +10,31 @@ import {
ADMIN_PUBLIC_LANDING_PATH,
} from './constants';
import { consumeLastDestination } from './lib/returnTo';
import WelcomeLandingPage from './onboarding/pages/WelcomeLandingPage';
import WelcomePackagesPage from './onboarding/pages/WelcomePackagesPage';
import WelcomeEventSetupPage from './onboarding/pages/WelcomeEventSetupPage';
import WelcomeOrderSummaryPage from './onboarding/pages/WelcomeOrderSummaryPage';
const LoginPage = React.lazy(() => import('./pages/LoginPage'));
const DashboardPage = React.lazy(() => import('./pages/DashboardPage'));
const EventsPage = React.lazy(() => import('./pages/EventsPage'));
const SettingsPage = React.lazy(() => import('./pages/SettingsPage'));
const EventFormPage = React.lazy(() => import('./pages/EventFormPage'));
const EventPhotosPage = React.lazy(() => import('./pages/EventPhotosPage'));
const EventDetailPage = React.lazy(() => import('./pages/EventDetailPage'));
const EventMembersPage = React.lazy(() => import('./pages/EventMembersPage'));
const EventTasksPage = React.lazy(() => import('./pages/EventTasksPage'));
const EventToolkitPage = React.lazy(() => import('./pages/EventToolkitPage'));
const EventInvitesPage = React.lazy(() => import('./pages/EventInvitesPage'));
const EngagementPage = React.lazy(() => import('./pages/EngagementPage'));
const BillingPage = React.lazy(() => import('./pages/BillingPage'));
const TasksPage = React.lazy(() => import('./pages/TasksPage'));
const TaskCollectionsPage = React.lazy(() => import('./pages/TaskCollectionsPage'));
const EmotionsPage = React.lazy(() => import('./pages/EmotionsPage'));
const AuthCallbackPage = React.lazy(() => import('./pages/AuthCallbackPage'));
const WelcomeTeaserPage = React.lazy(() => import('./pages/WelcomeTeaserPage'));
const LoginStartPage = React.lazy(() => import('./pages/LoginStartPage'));
const ProfilePage = React.lazy(() => import('./pages/ProfilePage'));
const LogoutPage = React.lazy(() => import('./pages/LogoutPage'));
const WelcomeLandingPage = React.lazy(() => import('./onboarding/pages/WelcomeLandingPage'));
const WelcomePackagesPage = React.lazy(() => import('./onboarding/pages/WelcomePackagesPage'));
const WelcomeEventSetupPage = React.lazy(() => import('./onboarding/pages/WelcomeEventSetupPage'));
const WelcomeOrderSummaryPage = React.lazy(() => import('./onboarding/pages/WelcomeOrderSummaryPage'));
function RequireAuth() {
const { status } = useAuth();

View File

@@ -308,7 +308,7 @@ export const messages: Record<LocaleCode, NestedMessages> = {
limitWarning: 'Nur noch {remaining} von {max} Fotos möglich. Bitte kontaktiere die Veranstalter für ein Upgrade.',
galleryWarningDay: 'Galerie läuft in {days} Tag ab. Teile deine Fotos rechtzeitig!',
galleryWarningDays: 'Galerie läuft in {days} Tagen ab. Teile deine Fotos rechtzeitig!',
status: {
packageStatus: {
title: 'Dein Paketstatus',
subtitle: 'Behalte deine Kontingente im Blick, bevor es eng wird.',
badges: {
@@ -736,7 +736,7 @@ export const messages: Record<LocaleCode, NestedMessages> = {
limitWarning: 'Only {remaining} of {max} photos left. Please contact the organizers for an upgrade.',
galleryWarningDay: 'Gallery expires in {days} day. Upload your photos soon!',
galleryWarningDays: 'Gallery expires in {days} days. Upload your photos soon!',
status: {
packageStatus: {
title: 'Your package status',
subtitle: 'Keep an eye on your remaining allowances.',
badges: {

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { Suspense } from 'react';
import { createRoot } from 'react-dom/client';
import { RouterProvider } from 'react-router-dom';
import { router } from './router';
@@ -28,7 +28,15 @@ createRoot(rootEl).render(
<React.StrictMode>
<LocaleProvider>
<ToastProvider>
<Suspense
fallback={(
<div className="flex min-h-screen items-center justify-center text-sm text-muted-foreground">
Erlebnisse werden geladen
</div>
)}
>
<RouterProvider router={router} />
</Suspense>
</ToastProvider>
</LocaleProvider>
</React.StrictMode>

View File

@@ -8,27 +8,28 @@ import { AlertTriangle, Loader2 } from 'lucide-react';
import { EventStatsProvider } from './context/EventStatsContext';
import { GuestIdentityProvider } from './context/GuestIdentityContext';
import { EventBrandingProvider } from './context/EventBrandingContext';
import LandingPage from './pages/LandingPage';
import ProfileSetupPage from './pages/ProfileSetupPage';
import HomePage from './pages/HomePage';
import TaskPickerPage from './pages/TaskPickerPage';
import TaskDetailPage from './pages/TaskDetailPage';
import UploadPage from './pages/UploadPage';
import UploadQueuePage from './pages/UploadQueuePage';
import GalleryPage from './pages/GalleryPage';
import PhotoLightbox from './pages/PhotoLightbox';
import AchievementsPage from './pages/AchievementsPage';
import SlideshowPage from './pages/SlideshowPage';
import SettingsPage from './pages/SettingsPage';
import LegalPage from './pages/LegalPage';
import PublicGalleryPage from './pages/PublicGalleryPage';
import NotFoundPage from './pages/NotFoundPage';
import { LocaleProvider } from './i18n/LocaleContext';
import { DEFAULT_LOCALE, isLocaleCode } from './i18n/messages';
import { useTranslation, type TranslateFn } from './i18n/useTranslation';
import type { EventBranding } from './types/event-branding';
import type { EventBrandingPayload, FetchEventErrorCode } from './services/eventApi';
const LandingPage = React.lazy(() => import('./pages/LandingPage'));
const ProfileSetupPage = React.lazy(() => import('./pages/ProfileSetupPage'));
const HomePage = React.lazy(() => import('./pages/HomePage'));
const TaskPickerPage = React.lazy(() => import('./pages/TaskPickerPage'));
const TaskDetailPage = React.lazy(() => import('./pages/TaskDetailPage'));
const UploadPage = React.lazy(() => import('./pages/UploadPage'));
const UploadQueuePage = React.lazy(() => import('./pages/UploadQueuePage'));
const GalleryPage = React.lazy(() => import('./pages/GalleryPage'));
const PhotoLightbox = React.lazy(() => import('./pages/PhotoLightbox'));
const AchievementsPage = React.lazy(() => import('./pages/AchievementsPage'));
const SlideshowPage = React.lazy(() => import('./pages/SlideshowPage'));
const SettingsPage = React.lazy(() => import('./pages/SettingsPage'));
const LegalPage = React.lazy(() => import('./pages/LegalPage'));
const PublicGalleryPage = React.lazy(() => import('./pages/PublicGalleryPage'));
const NotFoundPage = React.lazy(() => import('./pages/NotFoundPage'));
function HomeLayout() {
const { token } = useParams();