admin: Bericht „Indexierung & Abrufe" — Rolle Erstquelle/Kopie, Quellenbefund, Crawler-Abrufe; Schlüsselpfad ab Projektwurzel

Der Bericht meldete auf Live „nicht konfiguriert", während der Lauf
längst Daten holte: der relative Pfad der Schlüsseldatei war im Cron
(Projektwurzel) lesbar, im Web-Request (public/) nicht. Relative Pfade
werden jetzt ab base_path() aufgelöst.

Die Verteilung trennt zusätzlich nach Rolle in der kanonischen Zuordnung
(1c.8): bei einer Kopie mit Verweis ist „ausgeschlossen" der erwartete
Befund. Neu: Quellenbefund über Erstquellen (welche Adresse Google führt,
fremde Hosts), Abrufe durch Such- und KI-Dienste je Dienst, Tag und
Meldung mit CSV. Herkunftsmarker als Join statt korreliertem EXISTS,
Aggregate 15 Minuten gecacht.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-18 12:53:22 +00:00
parent 1c421c0377
commit c26bdff681
8 changed files with 609 additions and 87 deletions

View file

@ -22,9 +22,26 @@ class SearchConsoleClient
public function isConfigured(): bool
{
$file = (string) config('search_console.credentials');
$file = $this->credentialsPath();
return (bool) config('search_console.enabled') && $file !== '' && is_readable($file);
return (bool) config('search_console.enabled') && $file !== null && is_readable($file);
}
/**
* Pfad der Schlüsseldatei, relative Angaben ab Projektwurzel. Ohne das
* hing die Lesbarkeit vom Arbeitsverzeichnis ab: im Cron (Projektwurzel)
* lesbar, im Web-Request (public/) nicht — der Admin meldete „nicht
* konfiguriert", während der Lauf längst Daten holte.
*/
private function credentialsPath(): ?string
{
$file = trim((string) config('search_console.credentials'));
if ($file === '') {
return null;
}
return str_starts_with($file, '/') ? $file : base_path($file);
}
public function propertyFor(string $portal): ?string
@ -102,8 +119,8 @@ class SearchConsoleClient
*/
private function credentials(): array
{
$file = (string) config('search_console.credentials');
$json = is_readable($file) ? json_decode((string) file_get_contents($file), true) : null;
$file = $this->credentialsPath();
$json = $file !== null && is_readable($file) ? json_decode((string) file_get_contents($file), true) : null;
if (! is_array($json) || empty($json['client_email']) || empty($json['private_key'])) {
throw new RuntimeException('Search Console: Schlüsseldatei des Service-Kontos fehlt oder ist unvollständig.');