# 00 – Overview ## 1. Ausgangslage ### 1.1 Zwei Legacy-Portale (technisch identisch, organisatorisch getrennt) | Eigenschaft | `presseecho` | `businessportal24` | |---|---|---| | Technologie | Symfony 1.4, Doctrine 1.2, PHP 5.6 | Symfony 1.4, Doctrine 1.2, PHP 5.6 | | Server | Server A | Server B | | Datenbank | `db_presseecho` (MySQL) | `db_businessportal` (MySQL) | | Frontend-Domain | presseecho.de | businessportal24.com | | Code-Base | identisch (nur `app.yml` + Templates abweichend) | identisch | Code-Referenz im Repo: `/_businessportal24.com/` (exemplarisch; `presseecho` ist inhaltsgleich). ### 1.2 Neue Frontends (bereits in diesem Repo) - `resources/views/web/` – Landingpages für `presseecho.test` und `businessportal24.test` - Domain-basiertes Theme-System (`config/domains.php` + `ThemeServiceProvider`) - Zwei Tailwind-/Vite-Configs (Portal vs. Web) Diese Frontends sollen künftig **gegen das neue Backend arbeiten** – via direkter DB-Lesezugriffe (same-DB) oder API. ### 1.3 Neues Backend (Aufgabe dieses Projekts) - Läuft unter `pressekonto.test` / `pressekonto.de` - Stack: **Laravel 12, PHP 8.4, Livewire 4, Volt, Flux UI 2, MySQL 8, Tailwind 4** - **Vorarbeiten bereits vorhanden**: Admin-UI-Gerüst, Routes, Auth-Stack - **Noch zu tun**: Eloquent-Models, Migrations, Services, Daten-Migration, API, Payment (Stripe), Cron-Jobs --- ## 2. Ziele der Migration ### 2.1 Fachliche Ziele 1. **Ein Backend für beide Portale** – Schluss mit dupliziertem Code und doppeltem Betrieb. 2. **Ein Datenbestand** – beide Legacy-DBs in eine Ziel-DB konsolidiert, disambiguiert durch `portal` (`presseecho` | `businessportal24`). 3. **Moderne Admin-UX** – Livewire + Flux UI statt generierter Symfony-Admin-Tabellen. 4. **Saubere REST-API** – mit Sanctum-Auth und Laravel-API-Resources. Harter Cut-over auf Sanctum PATs ohne Legacy-Key-Kompatibilität; Legacy-Keys liefern 410 mit Migrationshinweis. 5. **Automatisierbarer Betrieb** – Laravel Scheduler + Queues statt Bash-Scripts. ### 2.2 Nicht-Ziele - Kein Umbau der neuen Frontends (`presseecho.test`, `businessportal24.test`) – die laufen bereits. - Kein 1:1-Port der alten Backend-Symfony-Templates – wir bauen das Admin neu (UI-Gerüst steht schon). - **Keine Migration der Legacy-Payments/Invoices** als operative Daten – nur Archiv. - **Keine Übernahme alter API-Keys** – Cut-over auf Sanctum-Tokens. - **Keine Übernahme alter Passwörter** – User werden zum Reset aufgefordert. - **Keine Promotion-Links** (Legacy-Feature entfällt). - Keine Übernahme von PayPal Express, SPK-Berlin, Cortal Consors, Post/Bar, Rechnungszahlung – **einzig Stripe**. - Kein CMS-Modul für redaktionelle Seiten (`page`-Modul im Legacy) – wird über Blade-Views im Frontend abgebildet. --- ## 3. Erfolgskriterien | Kriterium | Messbar an | |---|---| | Backend unter `pressekonto.test` erreichbar | HTTP 200 auf Login-Seite | | Admin-Login (Fortify + 2FA) funktioniert | Feature-Test `AuthTest` | | Customer-Portal via Magic-Link erreichbar | Feature-Test `MagicLinkLoginTest` | | Pressemitteilungen CRUD (Admin + Customer) | Livewire-Tests `PressReleaseIndex/Create/Edit/Show` | | Firmen & Kontakte CRUD | Livewire-Tests | | Sauberes Migrations-Skript (wiederholbar) | `artisan legacy:import` idempotent, läuft gegen die konfigurierten Legacy-DB-Verbindungen | | Daten beider Portale importiert | `portal`-Verteilung plausibel, Counts Delta ≤ 1 % | | Rechnungslauf (neu, Stripe) | Stripe-Webhook-Tests, `invoices:generate` Command | | Legacy-Rechnungen im Archiv einsehbar | `legacy_invoices`-Table vollständig importiert; PDF wird bei Abruf aus Legacy-Daten generiert | | API v1 mit Sanctum | API-Feature-Tests | | Coverage ≥ 70 % auf Domain-Code | `./vendor/bin/pest --coverage` | --- ## 4. Phasen (High-Level) Ausführlicher Plan in [`03-MIGRATION-PLAN.md`](./03-MIGRATION-PLAN.md). | Phase | Titel | Ergebnis | |---|---|---| | P1 | Fundament | DB-Schema (Migrations), Models, Factories, Seeders, Config (countries/salutations) | | P2 | Auth & Tenancy | Fortify-Profile, **Magic-Link Auth**, Rollen/Rechte (Spatie), `portal`-Scope auf Models | | P3 | Admin-UI füllen | Volt-Komponenten an echte Models/Services anbinden (UI existiert) | | P4 | **Customer-Portal** | Self-Service für Companies (PM erstellen, Rechnungen, Tokens, Profil) | | P5 | Services & Domain-Logic | PressRelease-, Company-, Newsletter-Services; Slugging; Blacklist-Check | | P6 | **Daten-Migration** ⭐ | Import-Commands aus beiden Legacy-DBs (**wiederholbar**), Bilder-Transfer, Legacy-Invoice-Archiv | | P7 | API v1 | Sanctum, API-Resources, **Cut-over** (keine Legacy-Key-Kompatibilität) | | P8 | Payment & Invoicing (Stripe, **neu**) | Neue Produkte, Checkout, Webhooks, PDF, Mahnwesen, Grandfathering | | P9 | Scheduler & Queues | Laravel Scheduler + Queues | | P10 | Testing & Härtung | Pest-Tests, Pint, statische Analyse | | P11 | Deployment | Staging, Produktiv-Import-Rehearsal, DNS-Cutover, Produktivstart | --- ## 5. Entscheidungen (ehemals offene Fragen, 2026-04-23 geklärt) | ID | Thema | Entscheidung | |---|---|---| | **Q-01** | Produktiv-DB-Dumps beider Legacy-Systeme | ✅ **Liegen vor** unter `dev/migration 2026/sql/` (`businessportal24_2026-04-23.sql` 578 MB, `presseecho_2026-04-23.sql` 369 MB). **Wichtig:** Die Migration muss als *sauberes, wiederholbares Skript* gebaut werden, sodass am Go-Live-Tag der **aktuelle Produktivstand** beider DBs in die neue Live-DB überführt werden kann. Auf dem Test-Server stehen Dumps **und direkter Read-Only-Zugriff** auf die Legacy-DBs zur Verfügung. | | **Q-02** | Alte User-Passwörter | ❌ **Werden NICHT übernommen.** Beim Go-Live geht eine E-Mail an alle User mit Sicherheitshinweis und Passwort-Reset-Link. **Zusätzlich** wird ein **„Login per E-Mail-Link" (Magic Link / Einmal-Passwort)** eingebaut – insbesondere für Companies, die aktuell gar keinen Login haben, aber über die API Pressemitteilungen veröffentlichen. Über diese E-Mail können sie künftig auch auf ihre Pressemappe, Pressemitteilungen, Rechnungen und API-Tokens zugreifen. | | **Q-03** | Legacy-API-Keys | ❌ **Werden NICHT übernommen.** Neue Token-Technik (Sanctum PATs). Tokens sind pro User im Backend abrufbar und verwaltbar. Alte API-Clients müssen einmalig auf den neuen Token umgestellt werden. | | **Q-04a** | Alte Rechnungen (PDFs) | ✅ **Kommen ins Archiv** – nur lesbare Ansicht, kein aktiver Workflow. Separate `legacy_invoices`-Tabelle mit vollständigem DB-Import inkl. Status/User-Zuordnung; PDF wird für Legacy-Rechnungen bei Abruf aus diesen Daten generiert, nicht als neuer Stripe-Rechnungslauf. | | **Q-04b** | Rechnungslauf | ✅ **Komplett neu entwickelt.** Keine Rechnungs-Zahlungsweise mehr. **Einzige Zahlungsart: Stripe.** | | **Q-04c** | PaymentOptions | ✅ **Neue Produkte**, direkt über Stripe bezahlt. **Grandfathering:** Aktive User behalten ihre alten Konditionen bis Laufzeit-Ende, werden dann auf neue Produkte migriert. | | **Q-05** | Media/Bilder | ✅ **Lokal** (Storage-Disk `public`, später `s3`). Funktionen werden **erweitert**: Pressemitteilungen dürfen künftig mehrere/größere Bilder enthalten, Companies bekommen ordentliche Logo-Varianten (Legacy war sehr minimalistisch). | | **Q-06** | Pflicht-Datenfelder neu | ✅ `deleted_at` **überall** (Soft-Deletes). `portal`-Spalte auf allen mandantenfähigen Entitäten. Weitere sinnvolle Erweiterungen pro Entität: `uuid` (öffentliche Links), `gdpr_consent_at`, `last_seen_at` (User), `published_at` (PressRelease). | | **Q-07** | Mehrsprachigkeit | ✅ **Deutsch + Englisch** werden direkt initialisiert (Admin-UI DE, Content zweisprachig DE/EN). | | **Q-08a** | Promotion Links | ❌ **RAUS.** | | **Q-08b** | Footer Code | ✅ Bleibt (deaktivierbar pro Company). | | **Q-08c** | Newsletter | 🔁 **Neu aufgebaut**, nicht migriert. Nur die bestehenden Subscriber-Daten werden importiert. | | **Q-08d** | **Kundenbereich / Customer-Portal** | ✅ **WICHTIG** (erweitert den Scope): Das Backend ist **NICHT nur Admin**. Drei Nutzer-Bereiche:
• **Admin** – interne Mitarbeiter, volle Verwaltung
• **Customer** – Company-User, eingeloggt *oder* via Magic-Link. Eigene Pressemitteilungen erstellen/bearbeiten, Rechnungen einsehen, API-Tokens verwalten, Company-/Contact-Daten pflegen
• **API-Only** – reine Token-Nutzung für automatisiertes Publishing | | **Q-09** | Coupons | ⏸️ **Vertagt.** Kein Model/Feld in Phase 1. Kommt später separat dazu. | | **Q-10** | Agency vs. Company | ✅ **Unterscheidung bleibt** (per `type`-Enum auf `companies`, kein Table-Inheritance). | **Kernaussage:** Fokus dieser Migration liegt auf **Pressemitteilungen + Companies + Contacts** aus beiden Portalen sauber in eine neue DB zu überführen. **Zahlungen, Abwicklungen und Newsletter werden neu entwickelt** (nicht migriert). Das Backend dient **Admin-UND-Kunden** (Customer-Portal mit Magic-Link). --- ## 6. Stack-Vergleich | Domäne | Legacy | Ziel | |---|---|---| | Framework | Symfony 1.4 | Laravel 12 | | ORM | Doctrine 1.2 (YAML-Schema) | Eloquent | | PHP | 5.6 | 8.4 | | Auth | sfDoctrineGuardPlugin (sha1 + salt) | Fortify + bcrypt + **Magic-Link** | | API-Auth | statischer `api_key`-String | **Sanctum PAT** (Cut-over, keine Legacy-Kompatibilität) | | Rollen | `sfGuardGroup` / `sfGuardPermission` | Spatie/Permission | | Admin-UI | Generator (auto-admin) | Livewire Volt + Flux UI | | Forms | sfForm / sfFormDoctrine | Livewire + FormRequest + Flux | | i18n | Doctrine `I18n` behavior | Spatie/Laravel-Translatable oder `*_translations`-Tabelle | | Slugs | Doctrine `Sluggable` | `spatie/laravel-sluggable` | | Images | `sfImageTransformPlugin` | `intervention/image` + Image Driver GD/Imagick | | PDF | TCPDF (via sfpInvoicePdf) | `barryvdh/laravel-dompdf` | | Cron | Bash-Scripts + Symfony-Tasks | Laravel Scheduler + Jobs/Queues | | Mail | Swift Mailer | Laravel Mail (symfony/mailer) | | Templates | PHP `.php` | Blade | | Testing | kaum | Pest 3 | | Assets | symlinks in `web/` | Vite 5 (Portal + Web getrennt) | --- ## 7. Risikopunkte | Risiko | Wahrscheinlichkeit | Impact | Mitigation | |---|---|---|---| | Inkonsistente Daten zwischen beiden Legacy-DBs (gleiche IDs, unterschiedliche Inhalte) | hoch | hoch | Import mit ID-Offset/Re-Mapping; `legacy_id` + `portal` als Unique-Key | | Abhängigkeiten zwischen Frontends (presseecho.test) und neuem DB-Schema | mittel | hoch | Eloquent-Models können beide Frontends bedienen; Übergangsweise read-only Views | | Differenz zwischen Test-Dump und Produktiv-Stand am Go-Live-Tag | hoch | hoch | **Wiederholbares Import-Skript**; Delta-Modus; Rehearsal-Import am Staging 1 Tag vor Cutover | | API-Clients brechen nach Token-Umstellung | hoch | hoch | Frühe Kommunikation an alle API-User; Tokens im Backend self-service abrufbar; Übergangs-Banner | | User können sich nicht einloggen (weil alte PW weg) | mittel | mittel | Magic-Link + Reset-Mail-Kampagne + gut sichtbare Hilfe | | Grandfather-Abos falsch abgerechnet | mittel | hoch | Explizite `grandfathered_until`-Spalte, Tests, manuelle Liste | | Bilder-Pfade ändern (Slug-basierte Thumbnails) | hoch | mittel | Redirect-Rules für alte `/thumbnails/...`-URLs; Import + URL-Map | --- ## 8. Nächste Schritte (konkret) 1. ✅ Entscheidungen geklärt (siehe §5, Stand 2026-04-23) 2. ✅ DB-Dumps liegen in `dev/migration 2026/sql/` 3. **Aktuell:** Phase 1 starten – Migrations, Models, Factories, Seeders (siehe [`03-MIGRATION-PLAN.md`](./03-MIGRATION-PLAN.md)) 4. Parallel: Staging-DB-Verbindung zu Legacy-Systemen konfigurieren (Read-Only) 5. Phase 2: Magic-Link Auth + Customer-Bereich skizzieren