Files
KantSites/migrations/Version20260912000800.php
T
kantarciandClaude Opus 5 a40c2bb27e SEO, Weiterleitungen und strukturierte Daten (Arbeitspaket E)
Migration 20260912000800 ergänzt page.robots, page.og_media_id,
website.settings und die Tabelle redirect.

Alles Maschinenlesbare wird aus dem veröffentlichten Bestand
abgeleitet, nichts separat gepflegt: die Sitemap listet nur
veröffentlichte, indexierbare Seiten samt Beitragsübersicht und
Begriffsarchiven, und dieselbe Einstellung setzt auch das
noindex-Meta - beide Aussagen können nicht auseinanderlaufen.

Strukturierte Daten entstehen nur aus gepflegten Werten: ohne
Angaben wird kein leerer Organization-Block ausgegeben. JSON-LD ist
ein Datenblock, kein Skript, daher bleibt script-src 'none'
unberührt.

Weiterleitungen greifen vor dem 404, aber nach der Seitensuche: eine
vorhandene Seite gewinnt immer, sonst könnte ein alter Eintrag eine
neue Seite unerreichbar machen. Ketten werden abgewiesen. robots.txt
nimmt zusätzliche Zeilen nur nach festem Muster an, damit ein
Eintrag die Datei nicht umdeuten kann. llms.txt ist standardmäßig
aus.

Geprüft: 128 PHP-Tests / 507 Assertions unter PHP 8.2.12 und 8.4.22,
14 JavaScript-Modelltests, Lint/Format/Container. Dazu eine reine
Sichtprüfung im Browser auf einer lokalen Demoseite - weiterhin
keine axe- oder Lighthouse-Messung.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 12:43:00 +02:00

48 lines
1.9 KiB
PHP

<?php
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260912000800 extends AbstractMigration
{
public function getDescription(): string
{
return 'Indexing control, social image, company data and redirects.';
}
public function isTransactional(): bool
{
return false;
}
public function up(Schema $schema): void
{
$page = $schema->getTable('page');
// 'index' or 'noindex'. A page excluded here also disappears from the sitemap.
$page->addColumn('robots', 'string', ['length' => 16, 'notnull' => true, 'default' => 'index']);
$page->addColumn('og_media_id', 'string', ['length' => 32, 'notnull' => false]);
// Company data, social profiles and switches, kept as one document per website.
$schema->getTable('website')->addColumn('settings', 'json', ['notnull' => false]);
$redirect = $schema->createTable('redirect');
$redirect->addColumn('id', 'string', ['length' => 64]);
$redirect->addColumn('website_id', 'string', ['length' => 64]);
// Stored without a leading slash, exactly like page.path, so both are comparable.
$redirect->addColumn('from_path', 'string', ['length' => 400]);
$redirect->addColumn('to_path', 'string', ['length' => 400, 'notnull' => false]);
// 301 for a moved address, 410 for one that is deliberately gone.
$redirect->addColumn('status', 'integer');
$redirect->addColumn('created_at', 'datetime_immutable');
$redirect->setPrimaryKey(['id']);
$redirect->addUniqueIndex(['website_id', 'from_path'], 'uniq_redirect_from');
}
public function down(Schema $schema): void
{
$this->throwIrreversibleMigrationException('Contains indexing settings, company data and redirects. Restore a verified database backup with matching code.');
}
}