app->singleton(RegisterResponseContract::class, RegisterResponse::class); $this->app->bind(BankingProviderInterface::class, function ($app) { return new EnableBankingProvider( config('services.enablebanking.app_id'), base_path(config('services.enablebanking.private_key_path')), ); }); $this->app->bind(DiscordWebhook::class, function () { return new DiscordWebhook(config('services.discord.webhook_url')); }); $this->app->bind(TransactionMatcher::class, UncategorizedTransactionMatcher::class); $this->app->bind(RuleSuggestionGenerator::class, LaravelAiRuleSuggestionGenerator::class); } /** * Bootstrap any application services. */ public function boot(): void { // Event listeners are registered automatically via Laravel's event // discovery of the App\Listeners directory (matched by their handle() // type-hint). Do not also register them explicitly here — doing both // registers every listener twice, so each queued listener is dispatched // twice per event. RateLimiter::for('emails', function (object $job): Limit { return Limit::perSecond(30); }); } }