docs: Runbooks auf den echten Migrationsstand nachgezogen (16.07.)

Cutover-Runbook: Legacy-DBs liegen bei KAS und sind als lokale Snapshot-
Kopien eingespielt (Delta-Läufe brauchen vorher frische Dumps); privatize-
media läuft mit --prune-missing; retire-agency-type als Satellit ergänzt;
verlorene Presseecho-PM-Bilder (~22k) als bewusste Entscheidung dokumentiert.
Deploy-Runbook: Seeder-Liste um LegalDocumentSeeder/RejectionCategorySeeder
ergänzt, billing:sync-stripe-plans nach frischem Seeding, Tinker-Befehl für
die Admin-Rolle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-20 10:50:59 +00:00
parent 3842fbcc15
commit 263f030a6e
2 changed files with 100 additions and 6 deletions

View file

@ -68,6 +68,12 @@ php artisan db:seed --class=RolesAndPermissionsSeeder --force
php artisan db:seed --class=AdminPresetSeeder --force
php artisan db:seed --class=PlanSeeder --force
php artisan db:seed --class=PaymentOptionSeeder --force
php artisan db:seed --class=LegalDocumentSeeder --force
php artisan db:seed --class=RejectionCategorySeeder --force
# 5a) Nach frischem Seeding (Erst-Einrichtung oder DB-Reset): Stripe-Produkte/
# Preise neu verknüpfen — die Price-IDs stehen in der plans-Tabelle:
# php artisan billing:sync-stripe-plans
# 6) Caches bauen (bei JEDEM Deploy neu)
php artisan config:cache
@ -179,6 +185,24 @@ Endpoint in Stripe (Live-Mode) registrieren: `https://pressekonto.de/stripe/webh
Events: die Cashier-Defaults (Subscriptions, Invoices, Payment-Intents).
## 7. Erst-Einrichtung (nur beim allerersten Go-Live)
# kopieren der Bilddaten per rync #@jk:8#PN§!4V02wR:rV#
rsync -avz --partial ssh-w01eb4f6@w008b36f.kasserver.com:/www/htdocs/w01eb4f6/presseecho.de/web/thumbnails/ \
dev/migration/presseecho/thumbnails/
rsync -avz --partial ssh-w01eb4f6@w008b36f.kasserver.com:/www/htdocs/w01eb4f6/presseecho.de/web/uploads/ \
dev/migration/presseecho/uploads/
rsync -avz --partial ssh-w01eb4f6@w008b36f.kasserver.com:/www/htdocs/w01eb4f6/businessportal24.com/web/thumbnails/ \
dev/migration/businessportal24/thumbnails/
rsync -avz --partial ssh-w01eb4f6@w008b36f.kasserver.com:/www/htdocs/w01eb4f6/businessportal24.com/web/uploads/ \
dev/migration/businessportal24/uploads/
1. Legacy-Datenimport (Reihenfolge beachten, read-only-Quellen konfiguriert):
`legacy:import` → `legacy:fix-timestamps` → `legacy:migrate-media`
@ -191,11 +215,55 @@ Events: die Cashier-Defaults (Subscriptions, Invoices, Payment-Intents).
Owner-lose Agentur-Firmen und geschützte Fälle), dann scharf.
Namen werden nie überschrieben; gelöscht wird nur soft und nur ohne
PMs/Kontakte/Dritt-Mitgliedschaften/Zahlungsoptions-Verknüpfung.
3. Ersten Admin-User anlegen (Prod hat keine Demo-User):
Registrierung + Rolle via Tinker/DB oder dedizierter Befehl.
3. Ersten Admin-User anlegen (Prod hat keine Demo-User): normal registrieren
(inkl. E-Mail-Verifizierung), dann Rolle via Tinker setzen —
`syncRoles` ersetzt dabei alle bisherigen Rollen des Users:
```bash
php artisan tinker --execute 'App\Models\User::where("email", "mail@example.com")->firstOrFail()->syncRoles(["admin"]);'
```
4. Favicons je Domain deployen (Platzhalter-Generator reicht nicht) [EXTERN R5.4].
5. Smoke-Test: siehe Abschnitt 8.
1. Medien migrieren
# Erst prüfen, ob die Ordnerstruktur stimmt (zählt "Datei fehlt"/"Ziel fehlt")
php artisan legacy:migrate-media --portal=all --dry-run
# Dann scharf (kopiert + erzeugt Bildvarianten — dauert bei der Menge eine Weile)
php artisan legacy:migrate-media --portal=all
Kleine „Datei fehlt"-Restmengen sind bei Altbeständen normal (verwaiste DB-Einträge); große Zahlen heißen Ordnerproblem — dann melde dich mit der Ausgabe.
2. PM-Medien privatisieren (Pflicht, direkt danach)
php artisan press-releases:privatize-media
Verschiebt die PM-Bilder von der public- auf die private-Disk (Security-Hardening). Muss nach migrate-media laufen — und nach jedem späteren Medien-Lauf erneut.
3. Timestamps korrigieren (bewusst NACH den Medien)
php artisan legacy:fix-timestamps
Setzt created_at/updated_at/published_at authoritativ aus den Legacy-DBs. Nach den Medien deshalb, weil die Medien-Migration die Datensätze anfasst und updated_at neu stempelt — der Fix räumt das wieder auf. Wichtig fürs Frontend: Die Sortierung hängt an published_at.
4. Satelliten-Migrationen (jeweils erst --dry-run, dann scharf)
php artisan legacy:import-api-keys --dry-run # lokal waren es 406 Keys — Zahl vergleichen
php artisan legacy:archive-invoices --dry-run
php artisan legacy:grandfather-subscriptions --dry-run # MUSS nach archive-invoices (leitet sich aus dem Rechnungsarchiv ab)
php artisan legacy:import-billing-addresses --dry-run # Report: Kunden mit leeren/kaputten Alt-Adressen → manuell nachpflegen
php artisan legacy:migrate-agency-names --dry-run
php artisan companies:retire-agency-type --dry-run # NACH migrate-agency-names
Die Reports landen unter storage/app/private/migration/ — besonders bei den letzten beiden reinschauen (Mehrfach-Namen, Owner-lose Agentur-Firmen), bevor du sie scharf laufen lässt.
5. Das Gate: Gesamtverifikation
php artisan legacy:verify
JSON-Report prüfen → das ist deine Go/No-Go-Entscheidung für den Cutover. Wenn du magst, reich mir den Report hier rein, ich gehe ihn mit dir durch.
Danach: Stichproben im Browser
Newsroom-Übersicht, eine alte PM-Detailseite (lädt Bild + Anhang?), Firmenlogo, Archiv — und ein Blick in Admin ▸ Reports ▸ Betriebsüberwachung (alle Kacheln grün, besonders „Medien-Privatisierung").
## 8. Smoke-Test nach jedem Deploy
- [ ] Alle drei Domains laden (Hub-Landing, 2× Spoke-Home) über HTTPS