Umbenennung presseportale → pressekonto in Domains, Themes und Dokumentation. Design-Tokens, Portal-Shell, Customer-Dashboard, Auth- und Admin-PM-Views. Artisan-Befehl migrate:legacy-media mit Tests und Hub-Flux-Entwicklungsdocs. Co-authored-by: Cursor <cursoragent@cursor.com>
19 KiB
03 – Migrations-Plan (Phasenweise)
Jede Phase hat einen Satz klar abgegrenzter Aufgaben, ein greifbares Deliverable und Exit-Kriterien. Prioritäten: 🔴 hoch · 🟡 mittel · 🟢 niedrig.
Legende Status: ⬜ offen · 🔄 in Arbeit · ✅ fertig · ⏸️ blockiert · ❌ verworfen
Status-Abgleich 2026-04-29: Diese Datei wurde gegen den realen Code-Stand abgeglichen.
08-PROGRESS.mdbleibt das chronologische Log; die Tabellen hier bilden den operativen Phasenstatus ab.
Scope-Anpassung 2026-04-23: Nach den Entscheidungen des Auftraggebers (siehe
00-OVERVIEW.md §5) wurde der Plan deutlich geschärft:
- P2 enthält jetzt Magic-Link-Auth, keine Legacy-Passwort-Übernahme.
- P4 (Customer-Portal) ist neu eingezogen worden.
- P7 (API) macht einen sauberen Cut-over, keine Legacy-Key-Kompatibilität.
- P8 (Billing) wird komplett neu gebaut – keine Übernahme alter Rechnungen in den neuen Rechnungskreis; Legacy-Rechnungen werden vollständig als DB-basiertes Archiv importiert, Grandfathering bleibt separat.
- Promotion Links und Coupons entfallen in Phase 1.
Phase 0 – Vorbereitung ✅ (weitgehend erledigt)
| # | Aufgabe | Status |
|---|---|---|
| 0.1 | Entscheidungen in 00-OVERVIEW.md §5 mit Auftraggeber klären |
✅ 2026-04-23 |
| 0.2 | Legacy-DB-Dumps beschaffen → dev/migration 2026/sql/ |
✅ |
| 0.3 | .env anpassen: DB-Connections für mysql, legacy_presseecho, legacy_businessportal |
✅ lokal/testfähig, da P6-Import gelaufen; Staging/Prod-Credentials bleiben P11-Thema |
| 0.4 | Lokale MySQL-Schemas legacy_pe_snapshot / legacy_bp_snapshot aus Dumps erstellen |
✅ für bisherigen Vollimport erledigt |
| 0.5 | Stripe-Test-Account + API-Keys vom Auftraggeber | ⬜ |
| 0.6 | Liste der neuen Stripe-Produkte (Preisliste) vom Auftraggeber | ⬜ |
| 0.7 | Liste der aktiven Alt-Abos für Grandfathering (oder Kriterien) vom Auftraggeber | ⬜ |
Exit: DB-Dumps lokal importierbar, .env konfiguriert, Stripe-Zugang vorhanden.
Phase 1 – Fundament (1–2 d) 🔴
Ziel: Alle Eloquent-Models + Migrations + Factories + Seeders existieren und php artisan migrate:fresh --seed läuft durch.
| # | Aufgabe | Abhängigkeiten | Status |
|---|---|---|---|
| 1.1 | config/countries.php + config/salutations.php aus Legacy-Daten exportieren |
0.4 | ✅ |
| 1.2 | Enums anlegen (app/Enums/*) inkl. Portal, PressReleaseStatus, UserPaymentOptionStatus (mit grandfathered), InvoiceStatus (Stripe-nah) |
– | ✅ |
| 1.3 | Migrations schreiben (Tabellen aus 04-DATA-MODEL.md):magic_links, companies, contacts, profiles, categories, category_translations, press_releases, press_release_images, press_release_contact, newsletter_subscriptions, billing_addresses, invoice_billing_addresses, invoices, payment_options, payment_option_translations, user_payment_options, user_payments, legacy_invoices, legacy_import_map, contact_user, api_usage_logs, admin_presets, footer_codes, category_footer_code.Scope-Hinweis: blacklists und Coupons sind weiterhin nicht produktiv umgesetzt bzw. vertagt. |
1.2 | ✅ Kernschema (inkl. Footer-Codes 2026-05-04) |
| 1.4 | users-Tabelle erweitern: portal, registration_type, gdpr_consent_at, legacy_portal, legacy_id, last_seen_at. password auf NULLABLE. |
– | ✅ |
| 1.5 | Soft-Deletes + portal-Spalte auf allen relevanten Tabellen |
1.3 | ✅ |
| 1.6 | Models mit Relationships + Casts + Global Scopes anlegen | 1.3 | ✅ Kernmodels |
| 1.7 | Factories für alle Models (Faker-DE-Locale) | 1.6 | ✅ Kernfactories |
| 1.8 | Seeder: RolesAndPermissionsSeeder (admin/editor/customer/api-only), CategorySeeder (DE+EN), DefaultAdminUserSeeder, SalutationTranslationSeeder |
1.6 | 🔄 Rollen, Kategorien, PaymentOptions, AdminPresets vorhanden; kein separater DefaultAdmin/SalutationSeeder |
| 1.9 | php artisan migrate:fresh --seed läuft grün |
1.3–1.8 | ✅ laut 08-PROGRESS.md |
| 1.10 | Erste Pest-Tests (Smoke): alle Factories erzeugen valide Models | 1.7 | ✅/🔄 Billing/Auth/Admin/API-Featuretests vorhanden; keine zentrale Factory-Smoke-Suite |
Exit: DB-Struktur stabil, Test-Daten vorhanden, Tests grün. Keine PromotionLinks/Coupons-Tabellen (D-14/D-16).
Phase 2 – Auth & Tenancy (1.5 d) 🔴
| # | Aufgabe | Status |
|---|---|---|
| 2.1 | Spatie-Seeder mit Rollen: admin, editor, customer, api-only + passende Permissions |
✅ |
| 2.2 | User-Model: canAccessAdmin() + canAccessCustomer() + Policies |
✅ |
| 2.3 | Magic-Link Auth ⭐ (D-10): MagicLinkGenerator + MagicLinkConsume-Controller/Livewire + MagicLoginLink-Mailable |
✅ |
| 2.4 | Fortify-Login-View erweitern um "Login per E-Mail-Link" Toggle | ✅ |
| 2.5 | Middleware SetCurrentPortal + CurrentPortalScope (Global Scope) |
✅ SetCurrentPortal, PortalScope, CurrentPortalContext |
| 2.6 | Portal-Dropdown im Admin-Header (Flux UI Dropdown) | ✅ admin.portal-switcher in Sidebar |
| 2.7 | GoLivePasswordReset-Mailable + Command auth:send-go-live-mails (vor Go-Live, dry-runnable) |
✅ Command + Mailable vorbereitet; Versand bleibt P11 |
| 2.8 | Tests: Passwort-Login, Magic-Link-Flow (happy + expired + consumed), Portal-Scope | ✅ Auth-/MagicLink-/Access-Tests vorhanden |
Exit: Neue Nutzer können sich per Passwort + Magic-Link einloggen. Portal-Scope filtert Datensätze.
Phase 3 – Admin-UI an Models binden (2–3 d) 🔴
Die Views existieren bereits als Blade/Livewire-Stubs (resources/views/admin/*, resources/views/livewire/admin/*). Aufgabe: echte Daten-Queries + Actions einbauen.
| # | Bereich | Aufgaben | Status |
|---|---|---|---|
| 3.1 | Dashboard | Widgets: Anzahl PMs, neue Companies, neue Newsletter-Abos | ✅ echte Counts + Review-Queue |
| 3.2 | Press Releases | Index, Create, Edit, Show, Publish/Reject-Actions, mehrere Bilder | ✅ 2026-05-04: CRUD/Workflow + Multi-Image-Upload mit Sortierung/Preview-Flag/Löschen via livewire/components/press-release-images-manager (gleicher Component für Admin + Customer), API generiert thumb/medium/large-Varianten |
| 3.3 | Categories | Index mit DE+EN-Translations, Create/Edit (Slug-Live-Preview) | ✅ 2026-05-04: Index, Create und Edit (DE+EN Slugs mit Live-Preview, Parent-Hierarchie + Loop-Schutz, Lösch-Schutz bei verknüpften PMs/Sub-Kategorien). Tests (8 Cases). |
| 3.4 | Companies | CRUD inkl. erweitertem Logo-Upload (Varianten) | ✅ 2026-05-04: Admin-Logo-Upload nutzt jetzt ImageService::storeCompanyLogo(), generiert sq/wide-Varianten und schreibt logo_variants. Logo-Entfernen-Flow inklusive. |
| 3.5 | Contacts | CRUD, Verknüpfung zu Company | ✅ |
| 3.6 | Users & Roles | CRUD + Role-Assign + Permission-Editor + Legacy-Archivrechnungen-Tab | ✅ Kern umgesetzt; Legacy-Rechnungs-Tab im Admin separat prüfen |
| 3.7 | Newsletter | Subscriber-Liste, Ex-/Import CSV | ⏸️ Vertagt 2026-05-04 – wird nach dem Pressemitteilungs-Veröffentlichungs-Block angegangen. Aktuell vorhanden: Newsletter-Sync-UI für die Legacy-Maillisten. |
| 3.8 | Invoices (neu) | Liste, Detail, Stripe-Status, PDF-Download | ⬜ Admin-View noch Dummy; wartet auf P8 |
| 3.9 | Legacy-Invoices (Archiv) ⭐ | Read-only Liste, Filter, PDF-Download | ✅ 2026-05-04: Admin-Archivübersicht mit Suche, Portal-/Status-/Mapping-/PDF-Filtern, Hinweisen für unzugeordnete Legacy-User und on-demand PDF-Download |
| 3.10 | Payments | Liste (Filter), Detail | ⬜ Admin-View noch Dummy; wartet auf P8 |
| 3.11 | Footer-Codes | CRUD (blieb im Scope) | ✅ 2026-05-04: Schema (footer_codes + category_footer_code), Model + Factory, Admin-Volt (Index mit Suche/Filter, Create, Edit, Soft-Delete, Toggle-Active), Sidebar-Link, Tests (9 Cases). |
Exit: Alle CRUD-Screens funktionsfähig mit echten Daten. Promotions-Admin entfällt.
Phase 4 – Customer-Portal ⭐ NEU (1.5–2 d) 🔴
Ziel (D-11): Endkunden (Company-User) können sich selbst bedienen – kein Admin nötig für tägliche Aufgaben.
Architektur-Update 2026-05-04 (Panel-Konsolidierung): Customer-Bereich ist als "Mein Bereich" ins gemeinsame Admin-Panel überführt. URL-Prefix
/admin/me/*, Routenamenme.*. Alte/customer/*-Pfade als 301-Redirects erhalten. Login-Redirect erfolgt rollenbasiert (Admin/Editor →/dashboard, Customer →/admin/me). Sidebar zeigt "Mein Bereich" auch Admin/Editor; Admin-Bereiche bleiben Admin/Editor vorbehalten.
| # | Aufgabe | Status |
|---|---|---|
| 4.1 | Route-Gruppe me.* unter /admin/me/* mit auth:web + EnsureUserIsCustomer (admin/editor/customer) |
✅ 2026-05-04: konsolidiert ins Admin-Panel; alte customer.*-Routen als 301-Redirects erhalten. |
| 4.2 | Dashboard (Livewire\Customer\Dashboard): aktive Abos, letzte eigene PMs, offene Rechnungen |
🔄 Dashboard + eigene PMs fertig; aktive Abos/offene neue Rechnungen warten auf P8 |
| 4.3 | Press Releases: Index, Create, Edit, Submit-for-Review (Status review) |
✅ |
| 4.4 | Rechnungen: neue + Legacy-Archivrechnungen einsehen, PDF-Download | 🔄 Legacy-Archiv + PDF-Download vorbereitet; neue Rechnungen warten auf P8 |
| 4.5 | API-Tokens: Self-Service Create/Revoke, Scope-Auswahl | ✅ |
| 4.6 | Company-/Contact-Profile pflegen (inkl. Logo-Upload) | ✅ Customer-Profile editierbar inkl. Logo-Upload mit Varianten |
| 4.7 | Passwort / 2FA / E-Mail ändern | ✅ customer.security mit Passwort-/Mail-Update + Fortify 2FA-Aktivierung/Recovery-Codes |
| 4.8 | Policies auf allen Aktionen (Customer darf nur eigenes sehen) | ✅ PressReleasePolicy, CompanyPolicy, ContactPolicy, LegacyInvoicePolicy |
| 4.9 | Livewire-Feature-Tests | ✅ Token + Legacy-Rechnungen + Profile/Security/Policies abgedeckt |
Exit: Ein Test-Customer kann per Magic-Link einsteigen, PM erstellen, Token generieren, Legacy-Rechnung ansehen.
Phase 5 – Domain-Services & Geschäftslogik (2 d) 🟡
| # | Aufgabe | Status |
|---|---|---|
| 5.1 | PressReleaseService + PublishPressRelease/RejectPressRelease-Actions + Mailable |
✅ 2026-05-04: PressReleaseService mit Submit/Publish/Reject (mit Pflicht-Begründung)/BackToDraft/Archive/Auto-Reject bei Blacklist; Audit-Log via press_release_status_logs mit Quelle (admin/customer/blacklist) und Bearbeiter; rollenbasierte Mail-URLs (me.* für Customer, admin.* für Admin); Cache-Invalidation für Stats + Review-Counter. |
| 5.2 | BlacklistService (Wort-Prüfung im Text; Integration in Publish-Flow) |
✅ 2026-05-04: App\Services\PressRelease\BlacklistService + BlacklistViolationException, in submitForReview()/publish() integriert (auto-rejected + Mail an Autor), Wortliste in config/blacklist.php |
| 5.3 | NewsletterService neu (Subscribe/Confirm/Unsubscribe mit Token) |
⏸️ Vertagt 2026-05-04 – wird nach dem Pressemitteilungs-Veröffentlichungs-Block angegangen. Heute genutzt: NewsletterSyncService/Null-Client für Legacy-Listen. |
| 5.4 | CompanyService (Aktivierung, Logo-Upload, Footer-Code-Management) |
⬜ |
| 5.5 | ImageService (Intervention Image, Varianten, Thumbnail-Redirect) |
✅ 2026-05-04: Logos + PressRelease-Bilder mit thumb/medium/large via Cover-Resize. Verwendet GD ohne neue Composer-Dep, Aufruf von Customer/Admin/API/Sync. Legacy-Thumbnail-Redirect noch offen, aber kein Blocker. |
| 5.6 | SluggableTrait für Models + Unique-per-Language-Logik |
✅ 2026-05-04: App\Models\Concerns\HasUniqueSlug mit konfigurierbarem Scope; PressRelease (portal+language) und Company (portal) nutzen ihn. Category bleibt aussen vor (Slugs in Translations). |
| 5.7 | Domain-Events + Listeners (PressReleasePublished → SendPublishNotification) |
🔄 Mailables vorhanden, keine dedizierten Domain-Events |
| 5.8 | Tests pro Service (Feature-Tests + Unit-Tests) | 🔄 PressRelease/Admin/API-Pfade abgedeckt; keine vollständige Service-Suite |
Phase 6 – Daten-Migration ⭐ KERN (3–4 d) 🔴
Ziel: Alle relevanten Daten aus beiden Legacy-DBs in die neue DB – als wiederholbares Skript (D-18).
Stand 2026-04-28: Kern-Import vollständig abgeschlossen ✅
| # | Aufgabe | Status |
|---|---|---|
| 6.1 | Legacy-Zugriff via direkte DB-Connection (kein Legacy-Model nötig) | ✅ |
| 6.2 | legacy_import_map-basierte Upsert-Logik (idempotent) |
✅ |
| 6.3 | --source, --step, --dry-run, --force auf Master-Command |
✅ |
| 6.4 | Import-Commands: categories → users → companies → contacts → press_releases (inkl. Bilder + Kontakt-Pivot) |
✅ beides Portale |
| 6.5 | legacy:archive-invoices: erster Archivlauf mit 864 Rechnungen in legacy_invoices |
✅ in 6.5d technisch erweitert |
| 6.5b | legacy:fix-timestamps: Historische Timestamps auf allen Entitäten korrekt |
✅ |
| 6.5c | legacy:import --step=link-associations: 16.968 User↔Kontakt-Links |
✅ |
| 6.5d | Legacy-Rechnungen Vollimport: alle bestehenden Rechnungen beider Portale inkl. Status, Beträgen, Datumsfeldern, Zahlart, vollständigem Raw-Snapshot, pdf_payload und User-Zuordnung importieren; PDF bleibt DB-basiert/on-demand auf Knopfdruck statt Datei-Archiv |
✅ 2026-05-04 |
| 6.6 | legacy:grandfather-subscriptions: aktive Alt-Abos übernehmen |
⬜ warten auf Kriterien |
| 6.7 | Konflikt-Handling-Reports | ✅ via Importer-Fehlerlog |
| 6.8 | Bilder-Transfer (Mediendateien) | ✅ 2026-05-04: legacy:sync-company-logos + legacy:sync-press-release-images decken beide Asset-Typen ab. Generiert Varianten via ImageService, idempotent, Dry-Run + Reports vorhanden. |
| 6.9 | legacy:verify: Konsistenz-Checks |
✅ 0 Fehler / 0 Warnungen |
| 6.10 | Rehearsal-Lauf gegen produktiven Snapshot auf Staging | ⬜ |
Datenstand (2026-04-28):
- Users: 66.150 | Companies: 107.836 | Contacts: 16.964 | PMs: 174.688 | Rechnungen: 864 im bisherigen Archivlauf
Klarstellung Legacy-Rechnungen (2026-05-04): legacy:archive-invoices übernimmt jede Legacy-Rechnung idempotent, erhält den Originalstatus unverändert und löst die Zuordnung zum neuen User über legacy_import_map auf. Unzuordenbare Rechnungen bleiben im Archiv sichtbar und werden im Import-Report gezählt. pdf_payload speichert zusätzlich Billing-Adresse und User-Payment-Snapshot für die DB-basierte PDF-Erzeugung. Neue Stripe-Rechnungen werden erst in P8 separat konzipiert.
Exit: Kompletter Import beider Portale auf Staging erfolgreich. Rehearsal-Lauf dokumentiert. legacy:verify grün.
Phase 7 – API v1 (1.5 d) 🔴
| # | Aufgabe | Status |
|---|---|---|
| 7.1 | Analyse Legacy-Access-Logs (letzte 90 Tage), Priorisierung Endpoints | ✅ Tooling fertig; Legacy-App-Logs nicht vorhanden, Entscheidung über migrierte Daten/Codeprüfung getroffen |
| 7.2 | routes/api.php: Prefix v1, Middleware api,auth:sanctum |
✅ |
| 7.3 | Controller + Resources für: PressRelease (CRUD), PressReleaseImage (minimal), Company (read), Category (read), Newsletter (subscribe) | ✅ newsletter/unsubscribe bewusst aus P7 entfernt; neuer Newsletter-Dienst folgt später |
| 7.4 | Request-Validation via FormRequests | ✅ |
| 7.5 | Sanctum Token-Abilities (`press-releases:read | write, companies:read`, etc.) |
| 7.6 | Legacy-Cut-Handler (410 Gone bei api_key-Param) |
✅ |
| 7.7 | Rate-Limiting pro Token | ✅ 60/min pro Sanctum-Token bzw. Bearer-Token-Fingerprint |
| 7.8 | API-Doku (Scribe oder OpenAPI YAML) | ✅ OpenAPI YAML unter docs/api/v1.yml + Route /docs/api/v1 |
| 7.9 | Feature-Tests für alle Endpoints | ✅ Kern-Endpunkte + Images + Token-Freigabe + API-Usage-Logging abgedeckt |
| 7.10 | Legacy-API-Kundenkommunikation vorbereiten | ✅ Kundenreport fertig: api:legacy-customers-report; operative Mailtexte folgen außerhalb P7 |
Phase 8 – Payment & Invoicing (Stripe, neu gebaut) (2.5 d) 🔴
| # | Aufgabe | Status |
|---|---|---|
| 8.1 | Stripe-Setup (.env Keys, Entscheidung Cashier vs. raw stripe-php) |
⬜ |
| 8.2 | PaymentOption-Admin mit neuen Produkten + Sync zu Stripe Products/Prices (Command stripe:sync-products) |
⬜ |
| 8.3 | Checkout-Flow (Livewire im Customer-Portal): Stripe Checkout Session, Rückkehr-URL | ⬜ |
| 8.4 | Webhook-Controller /webhooks/stripe + Event-Handler (checkout.session.completed, invoice.paid, invoice.payment_failed, customer.subscription.deleted) |
⬜ |
| 8.5 | InvoiceNumberGenerator (neuer Kreislauf {YYYY}{MM}-{seq}) |
⬜ |
| 8.6 | PDF-Blade + InvoiceService |
⬜ |
| 8.7 | Mahnwesen vereinfacht (invoices:remind nur für Stripe-Fails) |
⬜ |
| 8.8 | Grandfathering-Handler ⭐: ExpireGrandfatheredSubscriptions-Scheduler + Customer-Benachrichtigung |
⬜ |
| 8.9 | Legacy-Rechnungen Archiv-UI im Customer-/Admin-Bereich anbinden | ✅ Customer- und Admin-Archiv inkl. DB-basierter PDF-Erzeugung vorhanden |
| 8.10 | Tests mit Stripe-Test-Mode (Fake-Webhooks) | ⬜ |
Phase 9 – Scheduler & Queues (0.5 d) 🟡
| # | Aufgabe | Status |
|---|---|---|
| 9.1 | Supervisor/Queue-Worker-Setup (Dev + Prod Docs) | ⬜ |
| 9.2 | routes/console.php: daily invoices:remind, magic-links:purge, grandfather:expire, monthly newsletter:campaign-digest (optional) |
🔄 magic-links:purge täglich und press-releases:purge-drafts wöchentlich vorhanden; P8/P5-Jobs offen |
| 9.3 | Failure-Alerting (Log-Channel + Mail bei fehlgeschlagenem Job) | ⬜ |
Phase 10 – Testing & Härtung (1 d) 🔴
| # | Aufgabe | Status |
|---|---|---|
| 10.1 | Coverage-Ziel 70 % auf app/Services, app/Actions |
⬜ |
| 10.2 | Architecture-Tests (Pest arch()) |
⬜ |
| 10.3 | php artisan test --parallel grün |
⬜ |
| 10.4 | Manuelle QA-Checkliste (siehe 06-FEATURES-SCOPE.md §15) durchgehen |
⬜ |
| 10.5 | Security-Review: CSRF, CORS, Rate-Limits, File-Uploads, Magic-Link-TTL | ⬜ |
Phase 11 – Deployment (1 d) 🔴
| # | Aufgabe | Status |
|---|---|---|
| 11.1 | Produktiv-DB-Server provisionieren, Backups konfigurieren | ⬜ |
| 11.2 | Staging-Deployment + Smoke-Tests | ⬜ |
| 11.3 | Produktiv-Import-Rehearsal gegen aktuellen Legacy-Snapshot | ⬜ |
| 11.4 | Go-Live-Mailing: Passwort-Reset + Sicherheitshinweis an alle User | 🔄 Command/Mailable fertig; Versand und finale Texte offen |
| 11.5 | API-Kunden-Kommunikation (Token-Migration) | 🔄 Kundenreport fertig; Freigabeliste und operative Mailtexte offen |
| 11.6 | DNS-Cutover-Plan: pressekonto.de auf neuen Server |
⬜ |
| 11.7 | Read-Only-Modus auf Legacy-Systemen während Final-Import | ⬜ |
| 11.8 | Abschalten der alten Symfony-Server (nach Review-Periode) | ⬜ |
Aufwandsschätzung (grob, nach Scope-Schärfung)
| Phase | Aufwand (MT) |
|---|---|
| 0 | 0.25 (Rest) |
| 1 | 1.5 |
| 2 | 1.5 |
| 3 | 2.5 |
| 4 | 2.0 |
| 5 | 2.0 |
| 6 | 3.5 |
| 7 | 1.5 |
| 8 | 2.5 |
| 9 | 0.5 |
| 10 | 1.0 |
| 11 | 1.0 |
| Σ | ~19.75 MT (∼4 Wochen Vollzeit) |
Grund für Erhöhung ggü. ursprünglich 16 MT: Customer-Portal (P4) ist neu, Billing ist komplett Neubau statt Migration, Daten-Migration aufwändiger wegen Wiederholbarkeits-Anforderung.
Abhängigkeitsgraph
P0 → P1 → P2 ┬→ P3 ┐
├→ P4 ┤
│ ├→ P5 ┐
│ │ ├→ P7 ┐
│ │ │ ├→ P10 → P11
│ │ ├→ P8 ┘
│ │ │
│ └→ P6 ┘
│
└→ P9
P6 (Daten-Migration) ist der kritische Pfad – kann parallel zu P3–P5 auf einem Staging-Branch vorbereitet werden, blockiert aber P10/P11.