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>
270 lines
19 KiB
Markdown
270 lines
19 KiB
Markdown
# 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 (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`](./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.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/*`, 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 (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`](./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 P3–P5 auf einem Staging-Branch vorbereitet werden, blockiert aber P10/P11.
|