<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Http\Request;
use Illuminate\Session\TokenMismatchException;
use Illuminate\Support\Facades\Route;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__ . '/../routes/web.php',
api: __DIR__ . '/../routes/api.php',
commands: __DIR__ . '/../routes/console.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware) {
// ── Global middleware ─────────────────────────────────────────────────
$middleware->web(append: [
\App\Http\Middleware\SecurityHeaders::class,
// Storefront-only maintenance mode, driven by Settings →
// Maintenance Mode. Skips /admin and /up itself — see the
// class doc comment for why this exists instead of
// `php artisan down`.
\App\Http\Middleware\CheckMaintenanceMode::class,
]);
// ── API: Force JSON responses ─────────────────────────────────────────
$middleware->api(append: [
\App\Http\Middleware\ForceJsonResponse::class,
]);
// ── Aliases ───────────────────────────────────────────────────────────
$middleware->alias([
'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,
'vendor.plan' => \App\Http\Middleware\VendorPlanGate::class,
'multivendor.only' => \App\Http\Middleware\MultiVendorOnly::class,
]);
})
->withProviders([
// Filament PanelProvider — must be registered before ModuleServiceProvider
// so Filament's panel routes are available when the rest of the app boots.
\App\Modules\Admin\Providers\AdminServiceProvider::class,
// Module autoloader — must come after core Laravel providers
\App\Providers\ModuleServiceProvider::class,
// Event → Listener mappings (OrderStatusChanged, etc.)
\App\Providers\EventServiceProvider::class,
])
->withExceptions(function (Exceptions $exceptions) {
// A CSRF token mismatch — most commonly a tab left open long enough
// for the session to expire, then the user clicks "Logout" (or
// submits any stale form) — used to dump the user on Laravel's raw
// 419 "Page Expired" page. Send them to the right login screen with
// a friendly message instead. Livewire/AJAX requests are left alone
// (they get Laravel's default JSON 419 response and Livewire's own
// "page expired, refresh?" prompt handles those client-side).
$exceptions->render(function (TokenMismatchException $e, Request $request) {
if ($request->expectsJson()) {
return null;
}
$loginRoute = $request->is('admin', 'admin/*') && Route::has('filament.admin.auth.login')
? route('filament.admin.auth.login')
: route('login');
return redirect($loginRoute)
->with('error', 'Your session expired. Please sign in again.')
->withErrors(['email' => 'Your session expired. Please sign in again.']);
});
})
->create();