Das System ist seit 20.07.2026 live; die dev-Doku spiegelt jetzt den Betriebszustand statt der Release-Vorbereitung: - dev/betrieb/: Deploy-Runbook (neu: §10 Betrieb nach Go-Live mit SFTP-Deploy-Checkliste inkl. queue:restart-Pflicht und den Betriebs-Erkenntnissen der Go-Live-Woche), Legacy-API-Parität, Umami. - dev/roadmap.md: offene Nachlauf-Punkte (Go-Live-Mails, Merge nach main, Stripe-Test-Artefakte, Key-Rotation, Alt-System-Abschaltung) und Ideen-Backlog. - dev/archive/: abgeschlossene Phasen — Migration-2026-Planung, Cutover-Runbook (mit Erledigt-Vermerk), Release-Plan/QA-Checkliste, Optimierungsphasen, Frontend-Konzepte + Responsive-Audits vom 16.07., Altsystem-Reste. - dev/README.md als Wegweiser; gitignore-Pfad der SQL-Dumps mitgezogen (dev/archive/migration-2026/sql/ bleibt untracked, ebenso dev/migration/ und dev/api/). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
9.1 KiB
Cutover-Runbook — Go-Live Pressekonto
✅ ERLEDIGT — archiviert am 20.07.2026. Die Migration ist vollständig durchgelaufen (
legacy:verify: 0 failures, 0 warnings), die echten Domains sind live geschaltet, Stripe läuft im Live-Mode. Dieses Runbook bleibt als Referenz erhalten — z. B. für einen späteren--since-Delta-Lauf, falls das Alt-System doch noch einmal Daten liefern sollte (Abschnitt 3). Betriebs-Doku ab jetzt:dev/betrieb/deploy-runbook.md.
Stand: 2026-07-14 · Branch fix/zeitzone-europe-berlin
Abhakbare Checkliste für die Umschaltung vom Alt-System auf Pressekonto.
Alle Commands laufen über Sail: vendor/bin/sail artisan … (bzw. ohne Sail
php artisan …, je nach Deployment-Umgebung).
0. Grundverständnis (einmal lesen)
- Zwei Legacy-Quellen, unterschiedlicher Charakter:
- Presseecho = echte Live-DB (
mysql_presseecho). Nur hier greift die „offline nehmen → Delta nachziehen"-Choreografie. - Businessportal24 = statischer Snapshot-Dump (
mysql_businessportal). Ändert sich nicht mehr → einmal importieren reicht, kein Delta nötig.
- Presseecho = echte Live-DB (
- Idempotenz: Alle Importer schreiben per
updateOrCreate(legacy_portal, legacy_id)- Crosswalk-Tabelle
legacy_import_map. Mehrfaches Ausführen erzeugt keine Duplikate. Bei Absturz mittendrin: einfach erneut starten (kein Rollback, Sicherheit kommt aus Idempotenz, nicht aus Transaktionen).
- Crosswalk-Tabelle
- Standard-Lauf überspringt bereits importierte Zeilen. Zwischenzeitliche
Änderungen an Altdatensätzen werden nur mit
--forcenachgezogen. - Kein Delete-Sync: Im Alt-System gelöschte Datensätze bleiben im neuen System bestehen. Für das kurze Cutover-Fenster i. d. R. vernachlässigbar.
- ⚠️
migrate:presseechoNICHT ausführen — toter, kaputter Stub. Der einzige gültige Weg istlegacy:import. - Voraussetzung Timestamp-Sync:
legacy:fix-timestampsnutzt Cross-Schema- JOINs → beide Legacy-Schemas müssen auf demselben MySQL-Server liegen wie die App-DB. Umsetzung Live (16.07.): Die KAS-Originale (All-Inkl) sind von außen nicht joinbar → Dumps als lokale Snapshot-Kopienlegacy_presseecho/legacy_businessportalauf dem Hetzner-Server eingespielt (Ploi-DBs,dbUserPressekontohat Zugriff),DB_*_PRESSEECHO/DB_*_BUSINESSPORTALzeigen auf die Kopien. Ein voller--force-Reimport ist als Ersatz ungeeignet: er setzt diepath-Spalte bereits migrierter Bildzeilen auf den Legacy- Dateinamen zurück und macht die Medien-Migration kaputt. - ⚠️ Snapshot veraltet: Alle Legacy-Commands lesen jetzt die lokalen Kopien. Beim Cutover (Abschnitt 3) und vor jedem Delta-Lauf zuerst frische KAS-Dumps ziehen und in die Kopien einspielen — sonst läuft das Delta gegen alte Daten.
1. Vorbereitung (Tage vorher, in Ruhe)
- Prod-
.envgesetzt:APP_ENV=production,APP_DEBUG=false,SESSION_SECURE_COOKIE=true,QUEUE_CONNECTION=database(o. Ä. dauerhaft). - Legacy-Zugangsdaten in
.enveingetragen:DB_HOST_PRESSEECHO / DB_DATABASE_PRESSEECHO / DB_USERNAME_PRESSEECHO / DB_PASSWORD_PRESSEECHOundDB_*_BUSINESSPORTAL(Snapshot-Dump auf denselben Server eingespielt). - Secrets rotiert (OpenAI / Google / Mail) — nicht die Alt-Keys übernehmen.
- Legacy-Medien ins lokale Staging kopiert:
dev/migration/<portal>/uploads/...(rsync vom Alt-System). - DB-Migrationen ausgeführt:
artisan migrate --force. Vorher prüfen: keine Duplikate ininvoices.stripe_invoice_id(Unique-Migration bricht sonst bewusst ab). - Rollen/Permissions ausgerollt:
artisan db:seed --class=RolesAndPermissionsSeeder.ç - Verbindungstest / Zählwerte:
artisan legacy:import --source=all --dry-run→ erwartete Zeilenzahlen plausibel?
2. Bulk-Import (Presseecho noch live, ohne Downtime)
Reihenfolge ist in legacy:import --step=all hart verdrahtet
(categories → users → companies → contacts → press-releases → link-associations).
artisan legacy:import --source=all(idempotent — beliebig oft wiederholbar).artisan legacy:migrate-media --portal=all(Datei-Bytes ausdev/migration/...→ public-Disk + Varianten).artisan press-releases:privatize-media --prune-missing(verschiebt PM-Medien public → private Disk — Security-Hardening; MUSS nachlegacy:migrate-medialaufen).--prune-missinglöscht Legacy-Bildzeilen, deren Datei im Alt-System verloren ging (Import legt pro Legacy-Bild eine Zeile an; ohne Datei bleibt sie sonst als Leiche liegen und hält die Betriebsüberwachungs-Kachel rot).artisan legacy:fix-timestamps(created_at/updated_at + published_at per Cross-DB-JOIN).- Satelliten-Migrationen (Reihenfolge unkritisch, jeweils
--dry-runzuerst):artisan legacy:import-api-keysartisan legacy:archive-invoicesartisan legacy:grandfather-subscriptionsartisan legacy:import-billing-addressesartisan legacy:migrate-agency-namesartisan companies:retire-agency-type(läuft NACHlegacy:migrate-agency-names; Reports unterstorage/app/private/migration/prüfen — Mehrfach-Namen, Owner-lose Agentur-Firmen, geschützte Fälle; s. Deploy-Runbook §7)
- Gate:
artisan legacy:verify→ JSON-Report prüfen. Go / No-Go.
3. Cutover-Fenster (kurze Downtime)
Ziel: nur die seit dem Bulk-Import geänderten/neuen Presseecho-Daten nachziehen. Businessportal24 braucht hier nichts (Dump ist statisch).
- Presseecho in Read-Only / Wartung schalten — Lesezugriff behalten, der Delta-Import muss noch aus der Legacy-DB lesen können.
- Frische KAS-Dumps ziehen und die lokalen Snapshot-Kopien neu einspielen
(
legacy_presseecho; Businessportal24 nur falls sich dort doch etwas geändert hat) — die Legacy-Connections lesen die Kopien, nicht KAS direkt. - Neues System in Wartung:
artisan down. - Delta-Import mit
--force+--since(zieht auch geänderte Bestandsdatensätze nach; uuid + slug von PMs bleiben stabil → öffentliche URLs brechen nicht).--sinceauf das Datum des Bulk-Imports minus 1 Tag Sicherheitsmarge setzen — dann scannt der Lauf nur die seither angelegten/geänderten Legacy-Zeilen (Sekunden statt Volldurchlauf):artisan legacy:import --source=presseecho --force --since="2026-07-19"Die Importer setzen Timestamps inzwischen selbst korrekt (forceFill) —legacy:fix-timestampsdanach ist Absicherung, kein Muss mehr. ⚠️ Für neue PM-Bilder vorher auch die Medien vom Alt-Server nachsyncen (rsync-Delta nachdev/migration/presseecho/…), sonst werden ihre Bildzeilen mangels Datei von--prune-missingentsorgt. - Medien-Delta:
artisan legacy:migrate-media --portal=presseecho --force(--forceerzwingt Neukopie + Varianten geänderter Bilder) → danach erneutartisan press-releases:privatize-media --prune-missing(der--force-Reimport legt die Bildzeilen verlorener Legacy-Dateien erneut an — das Pruning räumt sie wieder ab). artisan legacy:fix-timestamps --portal=presseecho- Gate:
artisan legacy:verify --portal=presseecho. - DNS umstellen auf das neue System.
- Queue-Worker läuft & wird überwacht → Admin ▸ Reports ▸ Betriebsüberwachung (alle Kacheln grün, besonders „Queue-Worker" und „Medien-Privatisierung").
artisan up— neues System live.- Alt-System komplett offline.
4. Go-Live-Kommunikation
- Passwort-Reset-Mails versenden (Importer setzt bewusst keine Passwörter):
erst
artisan auth:send-go-live-mails --dry-run(Anzahl prüfen), dannartisan auth:send-go-live-mails.- ⚠️ Massen-Mailversand über die Queue → vorher Worker-Status grün prüfen, während des Versands Betriebsüberwachung im Blick behalten (pending/failed jobs).
5. Nachlauf / Verifikation
- Stichproben: Login mit Reset-Link, PM-Detailseite (Bild + Anhang laden), Newsroom-Übersicht, Archiv-Sichtbarkeit.
- Betriebsüberwachung: keine
failed_jobs, kein „gestoppter Worker". storage/logsauf Fehler prüfen.- Backup der neuen Prod-DB direkt nach erfolgreichem Cutover.
Offene Punkte / bewusste Entscheidungen
-
Verlorene Presseecho-PM-Bilder akzeptiert (16.07.): ~22k von ~32k Legacy- Bilddateien existieren im Alt-System nicht mehr (nur Alt-Thumbnails retteten ~4,5k). Entscheidung: ohne Bild importieren — betrifft alte Archiv-Meldungen; betroffene PMs erscheinen bildlos, kaputte Referenzen entstehen nicht (
press-releases:privatize-media --prune-missingräumt die Datensatz-Leichen ab). -
Gelöschte Legacy-Datensätze werden nicht synchronisiert (kein Delete-Sync). Falls im Parallelbetrieb im Alt-System gelöscht wird → im neuen System nachher manuell prüfen (i. d. R. vernachlässigbar bei kurzem Fenster).
-
legacy:fix-timestampssetzt voraus, dass beide Legacy-Schemas auf demselben MySQL-Server liegen. Andernfalls voller--force-Reimport statt Timestamp-Fix.