app->singleton(PipelineRegistry::class, fn () => new PipelineRegistry( config('provisioning.pipelines', []), )); // Real I/O implementations; tests swap in fakes via app()->instance(). $this->app->bind(RemoteShell::class, PhpseclibRemoteShell::class); $this->app->bind(WireguardHub::class, LocalWireguardHub::class); $this->app->bind(ProxmoxClient::class, HttpProxmoxClient::class); $this->app->bind(HetznerDnsClient::class, HttpHetznerDnsClient::class); $this->app->bind(TraefikWriter::class, SshTraefikWriter::class); $this->app->bind(MonitoringClient::class, HttpMonitoringClient::class); } /** * Bootstrap any application services. */ public function boot(): void { // Stamp a maintenance-notification ledger row as delivered only once the // mail is actually sent (the X-CP-Notification header carries the id). // Until then sent_at stays null → the row is a retryable marker. Event::listen(MessageSent::class, function (MessageSent $event) { $header = $event->message->getHeaders()->get('X-CP-Notification'); if ($header === null) { return; } MaintenanceNotification::query()->whereKey((int) $header->getBodyAsString())->update(['sent_at' => now()]); }); } }