withRouting( web: __DIR__.'/../routes/web.php', api: __DIR__.'/../routes/api.php', commands: __DIR__.'/../routes/console.php', channels: __DIR__.'/../routes/channels.php', health: '/up', ) ->withMiddleware(function (Middleware $middleware): void { $middleware->web(replace: [ StartSession::class => ConditionalStartSession::class, ShareErrorsFromSession::class => ConditionalShareErrorsFromSession::class, ValidateCsrfToken::class => ConditionalValidateCsrfToken::class, ]); $middleware->validateCsrfTokens(except: [ 'chat_post', 'chat_post/*', 'api/art/*/view', ]); $middleware->web(append: [ \App\Http\Middleware\RedirectLegacyProfileSubdomain::class, \App\Http\Middleware\UpdateLastVisit::class, \App\Http\Middleware\HandleInertiaRequests::class, // Runs on every web request; no-ops for guests, redirects authenticated // users who have not finished onboarding (e.g. OAuth users awaiting username). \App\Http\Middleware\EnsureOnboardingComplete::class, \App\Http\Middleware\EnsureEmailLoginUpgradeComplete::class, ]); $middleware->alias([ 'artwork.maturity.access' => \App\Http\Middleware\EnsureArtworkMaturityAccess::class, 'admin.moderation' => \App\Http\Middleware\EnsureAdminOrModerator::class, 'admin.access' => \App\Http\Middleware\EnsureStaffAccess::class, 'admin.role' => EnsureAdminRole::class, 'creator.access' => \App\Http\Middleware\EnsureCreatorAccess::class, 'ensure.email.login.upgrade'=> \App\Http\Middleware\EnsureEmailLoginUpgradeComplete::class, 'ensure.onboarding.complete'=> \App\Http\Middleware\EnsureOnboardingComplete::class, 'forum.ai.moderation' => \App\Http\Middleware\ForumAIModerationMiddleware::class, 'forum.bot.protection' => \App\Http\Middleware\ForumBotProtectionMiddleware::class, 'forum.spam.detection' => \App\Http\Middleware\ForumSpamDetectionMiddleware::class, 'forum.security.firewall' => \App\Http\Middleware\ForumSecurityFirewallMiddleware::class, 'forum.rate_limit' => \App\Http\Middleware\ForumRateLimitMiddleware::class, 'onboarding' => \App\Http\Middleware\EnsureOnboardingComplete::class, 'normalize.username' => \App\Http\Middleware\NormalizeUsername::class, ]); }) ->withExceptions(function (Exceptions $exceptions): void { Integration::handles($exceptions); $exceptions->render(function ( AuthenticationException $e, \Illuminate\Http\Request $request ) { if ($request->expectsJson()) { return null; } return redirect()->to(route('login')); }); // ── HTML HTTP errors — use Nova-styled templates when possible ─────── $exceptions->render(function ( \Symfony\Component\HttpKernel\Exception\HttpException $e, \Illuminate\Http\Request $request ) { if ($request->expectsJson()) { return null; // Let Laravel produce the default JSON response. } $status = $e->getStatusCode(); // Generic 404 — smart URL-pattern routing to contextual views. if ($status === 404) { return app(\App\Http\Controllers\Web\ErrorController::class) ->handleNotFound($request); } $view = view()->exists("errors.{$status}") ? "errors.{$status}" : 'errors.http'; $data = $view === 'errors.http' ? [ 'error_code' => $status, 'error_title' => \Symfony\Component\HttpFoundation\Response::$statusTexts[$status] ?? 'Unexpected Error', 'error_message' => $e->getMessage() ?: 'Something went wrong while loading this page.', ] : []; if ($status === 403) { $data['message'] = $e->getMessage() ?: null; } return response()->view($view, $data, $status, $e->getHeaders()); }); // ── ModelNotFoundException → contextual 404 on web ─────────────────── $exceptions->render(function ( \Illuminate\Database\Eloquent\ModelNotFoundException $e, \Illuminate\Http\Request $request ) { if ($request->expectsJson()) { return null; } return app(\App\Http\Controllers\Web\ErrorController::class) ->handleNotFound($request); }); // ── 500 server errors — log with correlation ID ─────────────────────── $exceptions->render(function ( \Throwable $e, \Illuminate\Http\Request $request ) { if ($request->expectsJson()) { return null; } if ($e instanceof \Illuminate\Validation\ValidationException) { return null; } // Only handle truly unexpected server errors (not HTTP exceptions already handled above). if ($e instanceof \Symfony\Component\HttpKernel\Exception\HttpException) { return null; } // In debug mode let Laravel/Ignition render the full error page. if (config('app.debug')) { return null; } try { $correlationId = app(\App\Services\NotFoundLogger::class)->log500($e, $request); } catch (\Throwable) { $correlationId = 'UNKNOWN'; } return response(view('errors.500', ['correlationId' => $correlationId]), 500); }); })->create();