app->singleton(HtmlSanitizerService::class); $this->app->singleton(GeocodingService::class); $this->app->singleton(InvitationService::class); $this->app->singleton(SupportApiService::class); // During installation: ensure .env exists, APP_KEY is set, // and session/cache use file driver (database may not exist yet). // This must happen in register() — before middleware and any cache access. if (! file_exists(storage_path('installed'))) { $envPath = base_path('.env'); if (! file_exists($envPath) && file_exists(base_path('.env.example'))) { copy(base_path('.env.example'), $envPath); } if (file_exists($envPath) && empty(config('app.key'))) { $key = 'base64:'.base64_encode(random_bytes(32)); $envContent = file_get_contents($envPath); $envContent = preg_replace('/^APP_KEY=.*$/m', 'APP_KEY='.$key, $envContent); file_put_contents($envPath, $envContent); config(['app.key' => $key]); } // Session und Cache auf Datei-basiert umschalten. // Die .env hat SESSION_DRIVER=database und CACHE_STORE=database, // aber vor der Installation existiert die Datenbank noch nicht. config([ 'session.driver' => 'file', 'cache.default' => 'file', 'session.cookie' => 'handball_installer_session', 'session.encrypt' => false, // Verschluesselung braucht stabilen Key; bei Erstinstall unnoetig ]); } } public function boot(): void { RateLimiter::for('login', function (Request $request) { return Limit::perMinute(5)->by($request->input('email') . '|' . $request->ip()); }); RateLimiter::for('registration', function (Request $request) { return Limit::perHour(5)->by($request->ip()); }); RateLimiter::for('user-actions', function (Request $request) { return Limit::perMinute(30)->by($request->user()?->id ?: $request->ip()); }); RateLimiter::for('geocoding', function (Request $request) { return Limit::perMinute(30)->by($request->ip()); }); } }