presseportale/dev/migration 2026/03-MIGRATION-PLAN.md
Kevin Adametz 0a3e52d603 19-05-2026 Rebrand Pressekonto, Hub-Flux UI und Legacy-Media-Migration
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>
2026-05-19 16:36:13 +00:00

270 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.md` bleibt 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`](./00-OVERVIEW.md#5-entscheidungen-ehemals-offene-fragen-2026-04-23-geklärt)) 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`](./00-OVERVIEW.md) 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 (12 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`](./04-DATA-MODEL.md)):<br>`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`.<br>**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.31.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 (23 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.52 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/*`, Routenamen `me.*`. 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 (34 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`](./06-FEATURES-SCOPE.md)) 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 P3P5 auf einem Staging-Branch vorbereitet werden, blockiert aber P10/P11.