presseportale/app/Http/Controllers/Web/LlmsTxtController.php
Kevin Adametz f1648a05b0 web: Erstquelle-Absatz in der Veröffentlichungsmail, vierte Transparenzseite „kostenlos veröffentlichen" (Anhang 1: 1d, 2.4, E7)
Meldungen, die über die API eingegangen sind, bekommen in der
Veröffentlichungsmail einen Absatz zum Unterschied Erstquelle/Kopie —
technische Tatsache, ohne Preis und Angebot; direkt eingereichte nicht.

/pressemitteilung-kostenlos-veroeffentlichen beantwortet die Suche nach
„kostenlos" ehrlich: kein kostenloser Weg (E7), was kostenlose Portale
leisten, warum Links aus Presseportalen kaum tragen (auch bei uns
sponsored nofollow), warum Annahme ohne Gegenwert und Prüfung sich
ausschließen, wer am Ende zahlt. Die Liste kostenloser Portale ist in
config/transparency.php vorbereitet und bleibt leer, bis geprüfte
Einträge mit Prüfdatum vorliegen.

Unter-Navigation, Hilfe, Sitemaps, llms.txt und die Modelltabelle der
Kostenseite verlinken die neue Seite. Anhang 1 und Protokoll Teil 6.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 14:22:05 +00:00

130 lines
6.7 KiB
PHP

<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Models\Category;
use App\Support\WebPortalContext;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Cache;
/**
* `/llms.txt` (Roadmap 2.7): eine kurze, sachliche Beschreibung des Hosts
* für KI-Systeme — was die Seite ist, wie die URLs aufgebaut sind, wo die
* strukturierten Daten und Sitemaps liegen. Keine Werbeaussagen, keine
* Versprechen über Nennungen in KI-Antworten (Formulierungsgrenze 2.7).
* Hub und Spokes bekommen je eine eigene Fassung; pro Host eine Stunde
* gecacht.
*/
class LlmsTxtController extends Controller
{
public function __invoke(Request $request): Response
{
$host = $request->getHost();
$base = rtrim($request->getSchemeAndHttpHost(), '/');
$isHub = str_contains($host, 'pressekonto');
$text = Cache::remember('web.llms.'.$host, 3600, fn (): string => $isHub ? $this->hub($base) : $this->portal($base));
return response($text, 200, ['Content-Type' => 'text/plain; charset=UTF-8']);
}
private function hub(string $base): string
{
$presseecho = rtrim((string) config('domains.domains.presseecho.url'), '/');
$businessportal = rtrim((string) config('domains.domains.businessportal24.url'), '/');
return implode("\n", [
'# pressekonto',
'',
'> Publisher-Bereich der Presseportale presseecho und businessportal24: Unternehmen schreiben hier Pressemitteilungen, lassen sie automatisiert prüfen und veröffentlichen sie auf beiden Portalen.',
'',
'Die Meldungen selbst erscheinen nicht auf dieser Domain, sondern auf den beiden Portalen. Jede Meldung trägt dort NewsArticle-Markup (schema.org), jeder Newsroom Organization-Markup; Urheber einer Meldung ist immer das genannte Unternehmen, nicht das Portal.',
'',
'## Informationen',
'',
'- [Hilfe]('.$base.'/de/hilfe): Ablauf von der Registrierung bis zur Veröffentlichung',
'- [Was eine gute Pressemitteilung ausmacht]('.$base.'/de/gute-pressemitteilung): Anlass, Aufbau, Sprache, Prüfablauf',
'- [FAQ]('.$base.'/de/faq)',
'- [Richtlinien]('.$base.'/de/richtlinien): Was veröffentlicht wird und was nicht',
'- [Was kostet eine Pressemitteilung?]('.$base.'/de/was-kostet-eine-pressemitteilung): Abrechnungsmodelle, Prüfliste für Folgekosten, Rechenbeispiel',
'- [Pressemitteilung löschen oder ändern lassen]('.$base.'/de/pressemitteilung-loeschen-oder-aendern-lassen)',
'- [Pressemitteilung kostenlos veröffentlichen?]('.$base.'/de/pressemitteilung-kostenlos-veroeffentlichen): Warum es hier keine kostenlose Einreichung gibt, was kostenlose Portale leisten',
'- [API]('.$base.'/de/api): Einlieferung per REST-API; OpenAPI-Spezifikation unter '.$base.'/docs/api/v1',
'',
'## Portale',
'',
'- [presseecho]('.$presseecho.'/llms.txt): Pressemitteilungen aus Wirtschaft und Industrie',
'- [businessportal24]('.$businessportal.'/llms.txt): Pressemitteilungen aus Deutschland, Österreich und der Schweiz',
'',
'## Rechtliches',
'',
'- [Impressum]('.$base.'/de/impressum)',
'- [Datenschutz]('.$base.'/de/datenschutz)',
'- [AGB]('.$base.'/de/agb)',
'- [Inhalte melden]('.$base.'/de/melden)',
'',
]);
}
private function portal(string $base): string
{
$context = WebPortalContext::fromRequest();
$brand = (array) ($context->domainConfig['brand'] ?? []);
$name = ($brand['name'] ?? '').($brand['accent'] ?? '');
$hub = rtrim((string) config('domains.domains.pressekonto.url'), '/');
$categories = Category::query()
->where('is_active', true)
->whereIn('portal', $context->portalValues)
->with('translations')
->get()
->map(fn (Category $category) => $category->translations->firstWhere('locale', 'de'))
->filter()
->sortBy('name')
->map(fn ($translation) => '- ['.$translation->name.']('.$base.'/de/category/'.$translation->slug.')')
->values()
->all();
return implode("\n", [
'# '.$name,
'',
'> '.($brand['tagline_long'] ?? 'Presseportal für Pressemitteilungen.'),
'',
'Pressemitteilungen werden von Unternehmen eingereicht und vor der Veröffentlichung geprüft. Urheber einer Meldung ist das im Kopf genannte Unternehmen; das Portal ist Herausgeber. Meldungen tragen NewsArticle-Markup (schema.org) mit dem Newsroom des Unternehmens als author, Newsrooms tragen Organization-Markup.',
'',
'## Aufbau',
'',
'- Meldung: '.$base.'/de/press-release/{slug}',
'- Newsroom eines Unternehmens: '.$base.'/de/newsroom/{slug} — Übersicht unter '.$base.'/de/newsrooms',
'- Kategorie: '.$base.'/de/category/{slug}',
'- Sitemap: '.$base.'/sitemap.xml — News-Sitemap (Meldungen der letzten 48 Stunden): '.$base.'/sitemap-news.xml',
'',
'## Kategorien',
'',
...$categories,
'',
'## Für Unternehmen',
'',
'- [Veröffentlichen]('.$base.'/de/veroeffentlichen): Wie eine Meldung auf das Portal kommt',
'- [Preise]('.$base.'/de/preise)',
'- [Was kostet eine Pressemitteilung?]('.$base.'/de/was-kostet-eine-pressemitteilung): Abrechnungsmodelle, Prüfliste für Folgekosten, Rechenbeispiel',
'- [Pressemitteilung veröffentlichen ohne Abo]('.$base.'/de/pressemitteilung-veroeffentlichen-ohne-abo)',
'- [Pressemitteilung löschen oder ändern lassen]('.$base.'/de/pressemitteilung-loeschen-oder-aendern-lassen): Korrektur, Änderung, DSGVO, Depublikation',
'- [Pressemitteilung kostenlos veröffentlichen?]('.$base.'/de/pressemitteilung-kostenlos-veroeffentlichen): Warum es hier keine kostenlose Einreichung gibt, was kostenlose Portale leisten',
'- [Was eine gute Pressemitteilung ausmacht]('.$base.'/de/gute-pressemitteilung)',
'- [Hilfe]('.$base.'/de/hilfe)',
'- [API]('.$base.'/de/api): Einlieferung per REST-API über den Publisher-Bereich '.$hub,
'',
'## Rechtliches',
'',
'- [Impressum]('.$base.'/de/impressum)',
'- [Datenschutz]('.$base.'/de/datenschutz)',
'- [AGB]('.$base.'/de/agb)',
'- [Richtlinien]('.$base.'/de/richtlinien)',
'- [Inhalte melden]('.$base.'/de/melden)',
'',
]);
}
}