web: Entitaeten im JSON-LD verknuepft, News-Sitemap und llms.txt (Roadmap 2.1, 2.2, 2.7)

- App\Support\StructuredData: Portal-Organization als Publisher mit @id
  und Logo (ImageObject), Newsroom-@id; NewsArticle.author auf der
  Meldung und Organization auf der Newsroom-Seite beschreiben jetzt
  dieselbe Entitaet. Startseiten nutzen denselben Publisher.
- /sitemap-news.xml je Spoke (NewsSitemapController): im Archiv
  sichtbare Meldungen der letzten 48 h, max. 1.000, news:publication
  mit Portalname und Sprache; 15 min gecacht, mit den anderen Sitemaps
  geleert; in robots.txt der Spokes. Hub liefert leere Liste.
- /llms.txt je Host (LlmsTxtController): sachliche Beschreibung,
  URL-Aufbau, aktive Kategorien, Seiten fuer Unternehmen, Rechtliches;
  Hub verweist auf beide Portale. Keine Aussagen ueber KI-Nennungen.
- Protokoll Teil 5 (Block 2) inkl. Betreiber-Schritten fuer das
  Publisher Center und Befund zu 2.5/E5; Roadmap 2.1/2.7 abgehakt.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-17 10:15:28 +00:00
parent 713024be37
commit b74f881ac8
15 changed files with 521 additions and 23 deletions

View file

@ -0,0 +1,53 @@
<?php
namespace App\Support;
/**
* Gemeinsame Entitäten für das JSON-LD der Web-Seiten (Roadmap 2.1):
* das Portal als Publisher mit stabiler `@id` und Logo, der Newsroom als
* Organization mit stabiler `@id`. NewsArticle.author auf der Meldung und
* die Organization auf der Newsroom-Seite zeigen damit auf dieselbe Entität,
* statt zwei namensgleiche Objekte zu sein.
*/
class StructuredData
{
public static function portalBase(?string $domainUrl): string
{
return rtrim($domainUrl ?? (string) config('app.url'), '/');
}
/**
* Portal-Organisation (Publisher der Meldungen) — Name aus der
* Domain-Konfiguration, Logo als ImageObject (600×200-SVG unter /images).
*
* @return array<string, mixed>
*/
public static function publisher(string $portalBase): array
{
$isPresseecho = config('app.theme') === 'presseecho';
$brand = (array) config('domains.domains.'.($isPresseecho ? 'presseecho' : 'businessportal24').'.brand', []);
return [
'@type' => 'Organization',
'@id' => $portalBase.'/#organization',
'name' => ($brand['name'] ?? ($isPresseecho ? 'presse' : 'businessportal')).($brand['accent'] ?? ($isPresseecho ? 'echo' : '24')),
'url' => $portalBase.'/',
'logo' => [
'@type' => 'ImageObject',
'url' => $portalBase.'/images/'.($isPresseecho ? 'presseecho-logo.svg' : 'businessportal-logo.svg'),
'width' => 600,
'height' => 200,
],
];
}
public static function newsroomUrl(string $portalBase, string $slug): string
{
return $portalBase.'/'.app()->getLocale().'/newsroom/'.$slug;
}
public static function newsroomId(string $newsroomUrl): string
{
return $newsroomUrl.'#organization';
}
}

View file

@ -33,6 +33,7 @@ class WebCaches
if ($host) {
Cache::forget('web.sitemap.'.$host);
Cache::forget('web.sitemap-news.'.$host);
}
}
}