presseportale/dev/release/entwicklungsplan-release.md
2026-07-03 09:24:39 +00:00

133 lines
17 KiB
Markdown
Raw 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.

# Entwicklungsplan: Release-Fertigstellung Pressekonto
> Konsolidiert aus vier Analysen vom **03.07.2026** (dev-Doku-Abgleich, Web-Frontend-Bestandsaufnahme, Backend-Baustellen, Deploy-Readiness).
> Reihenfolge nach **Risiko/Nutzen**: erst Korrektheit & kaputte Pfade, dann Release-Entscheidungen (Billing), dann Frontend-Fertigstellung, dann Aufräumen, dann Deploy/QA.
> Ergänzt `dev/optimize/entwicklungsplan.md` (Phasen 0–5 dort abgeschlossen; dessen Phase 6 ist hier als R4 aufgenommen).
---
## Stand & Wiedereinstieg (zuletzt: 03.07.2026)
**Phase R0 komplett; R1 bis auf [EXTERN] fertig; R2.1 erledigt.** Erledigt: R0.1–R0.5 (Variant-Routen raus, gdpr_consent_at in allen drei Registrierungspfaden, Newsletter-Binding config-aware + fail-fast, Seeder produktionssicher inkl. PlanSeeder + Dev-User-Guard, Fehlerseiten 403/404/419/500/503 self-contained) · R1.1 (Gate safe-by-default `true`, Legacy-/Grandfathered-Pfade per Test festgeschrieben, Scope-Logik war korrekt) · R1.3 (Quota-Reset als finales Tarif-Modell-Verhalten dokumentiert).
Offen in R1 (alle [EXTERN]): R1.2 Stripe-Live-Sync, R1.4 Preisfreigabe, R1.5 Refund-Entscheidung.
R2.1 Kontaktformular komplett (Backend + Web-Form, Brand-Empfaenger via CONTACT_EMAIL_*-Keys [EXTERN: echte Adressen]). Bonus-Fix: legal-request-Honeypot nickt Bots wieder still ab (size:0-Regel verriet die Falle).
**03.07. nachmittags (User-Vorgaben):** Preise/Limits der Buchungsseite sind die abgestimmte Wahrheit; Pipeline verifiziert: admin/payments/plans pflegt Plan-DB (inkl. Vorteile zeilenweise) -> erscheint auf Buchungsseite, oeffentlicher Preise-Seite, pricing-teaser UND (neu) Hub. **Vorteilstexte selbst sind noch nicht final [EXTERN: User passt sie im Admin-UI an — schlaegt automatisch ueberall durch].**
R2.2+R2.3 erledigt: Hub-Landing komplett ueberarbeitet (datengetriebenes Tarif-Grid aus Plan::active() via neuem `HubPageData`, echte Plattform-Kennzahlen statt erfundener, Fake-Kundenliste raus, alle toten Links beseitigt, unhaltbare Claims entschaerft, Footer-Rechtslinks auf /de/*-Seiten der Hub-Domain). Hub-Rechtsseiten sind erreichbar, brauchen aber weiterhin finale Texte (R3.1).
**Naechste Schritte:** R2.4 (Sitemap/robots/meta) ohne User-Input machbar; R3 Inhalte + R1.2 Stripe-Live [EXTERN].
---
## Ausgangslage (Stand 03.07.2026)
- **Testsuite komplett grün:** 838 passed, 1 skipped (3.678 Assertions, ~70 s).
- **Branch:** `fix/zeitzone-europe-berlin`, **73 Commits vor `main`**, 62 davon ungepusht. `main` hat nichts Neues → Merge/Push ist Teil des Release (R6.5).
- **Keine Debug-Reste** (`dd`/`dump`/Test-Routen) im Backend; Mailables vollständig mit Views; Scheduler (5 Tasks) angeschlossen.
- **Wichtig:** `dev/migration 2026/12-NAECHSTE-SCHRITTE.md` ist teilweise **veraltet** — Stripe/Billing (dort „Phase 8 komplett offen") ist laut `dev/frontend/hub-flux/PROGRESS.md` seit 12.06. umgesetzt (Checkout, Webhooks, Tarif-Admin, Grandfathering). Restaufwand-Schätzungen von dort nicht übernehmen.
- **Nachgelagert (User-Entscheidung 03.07.):** kompletter getesteter Flow fürs User-Panel — bewusst NICHT Teil dieses Plans.
---
## Arbeitsregeln (für jeden Schritt)
- **Test-First bei Korrektheits-/Verhaltensänderungen** (R0–R2): erst Pest-Test, dann ändern.
- Tests gezielt laufen: `php artisan test --compact --filter=<Name>` (wir sind bereits im Sail-Container).
- Nach PHP-Änderungen: Pint (`--dirty`).
- **Web-Frontend** (`resources/views/web/**`, `components/web/**`) gehört dem User → separat committen, **vor jedem Löschen bestätigen lassen**.
- `resources/views/components/layouts/app/sidebar.blade.php` gehört dem User und bleibt aus allen Commits ausgeschlossen (`git reset -q -- …` vor jedem `git add`).
- Jeder Schritt = ein eigener, fokussierter Commit.
- Punkte mit **[EXTERN]** brauchen Input vom User/Auftraggeber (Texte, Entscheidungen, Zugänge) — früh anstoßen, parallel weiterarbeiten.
---
## Phase R0 — Korrektheit & kaputte Pfade (klein, sofort, Test-First)
- [x] **R0.1 Variant-Routen reparieren** — `routes/web.php:211-227`: `/variant-1` + `/variant-2` verweisen für die Businessportal-Domain auf `web.businessportal24-variant-float-glow` / `-glass-gradient` — **diese Views existieren nicht** → 500. Entscheidung: Routen entfernen (Design-Experimente sind abgeschlossen) oder auf `web.businessportal24` zurückfallen. Regressionstest.
- [x] **R0.2 `gdpr_consent_at` im Registrierungsflow befüllen** — Feld existiert (Model-Cast + Migration), wird aber **nirgends geschrieben** (verifiziert 03.07.). Bei Registrierung (Fortify `CreateNewUser`), Magic-Link-/Social-Provisioning (`CustomerAccountProvisioner`) setzen. DSGVO-relevant. Test-First. *(= rev-1 aus migration-Doku)*
- [x] **R0.3 Newsletter-Sync-Binding ehrlich machen** — `AppServiceProvider.php:47` bindet `NewsletterSyncClient` **unconditional** an `NullNewsletterSyncClient`; `NEWSLETter_SYNC_ENABLED=true` bewirkt nichts, das Admin-UI (`admin/newsletter/sync`) suggeriert aber eine funktionierende Sync. Fürs Release: No-Op bleibt (echte Sync ist nachgelagert), aber Binding config-aware machen und im Admin-UI den Placeholder-Status sichtbar ausweisen. Test.
- [x] **R0.4 Seeder produktionssicher machen** —
- `PlanSeeder` (Starter/Business/Pro/Agency) wird von `DatabaseSeeder` **nicht** aufgerufen → in den Produktions-Seed-Pfad aufnehmen (eigener `ProductionSeeder` oder Aufnahme + Guard).
- `PaymentOptionSeeder` schreibt Platzhalter (`prod_placeholder_monthly`, `price_placeholder_monthly`, …) → echte IDs via `billing:sync-stripe-plans` bzw. Seed anpassen (R1.2-Abhängigkeit).
- Test-User (`admin@pressekonto.test`, `test@example.com`, Passwort `password`) in `DatabaseSeeder` nur noch in `local`/`testing` anlegen.
- [x] **R0.5 Fehlerseiten erstellen** — `resources/views/errors/` existiert nicht → 404/500/503 (mind. 404 + 503 theme-/domain-aware fürs Web, neutrale Variante fürs Portal). Render-Tests.
---
## Phase R1 — Backend-Release-Entscheidungen (Billing/Gates)
- [x] **R1.1 Buchungs-/Tarif-Gate prüfen & bereinigen (User-Vorgabe 03.07.)** — Das Gate muss vollständig geprüft und bereinigt werden; **Legacy-Buchungen müssen funktionieren** (Bestandskunden mit Alt-Abo/Grandfathering dürfen veröffentlichen). Ist-Stand beim Testen: ohne gebuchtes Paket keine Veröffentlichung möglich (Gate lokal scharf via `.env`: `BILLING_ENFORCE_BOOKING=true`) — Soll-Verhalten bestätigt. Teilschritte:
- Alle Gate-Pfade durchgehen: `User::hasActiveBooking()`, `hasUnlimitedPressReleaseQuota`, `openSinglePurchaseCount()`, `UserPaymentOption::scopeActiveNow()`/`scopeGrandfatheredNow()`, Submit-Gate im `PressReleaseService`.
- **Legacy-Buchungen end-to-end testen:** migrierter User mit Alt-Abo (grandfathered, gültiges `grandfathered_until`) kann einreichen/veröffentlichen; abgelaufener Bestandsschutz wird korrekt geblockt (`NULL = abgelaufen`, Entscheidung 19.06.).
- Config-Default absichern: `config/billing.php` default `false` — bei vergessenem Prod-Env-Key liefert `hasActiveBooking()` für **alle** `true` → Default auf `true` drehen oder Runbook-Pflichtkey; `.env.example` korrigieren.
- Suite + manueller Submit-Flow (mit/ohne Buchung, mit Legacy-Buchung) gegengetestet.
- [ ] **R1.2 Stripe produktiv vorbereiten** — `billing:sync-stripe-plans` gegen **Live-Mode** ausführen (bislang nur Test-Mode); `STRIPE_PRICE_SINGLE_PM` setzen (sonst ist Einzel-PM-Checkout stumm deaktiviert, `CheckoutController.php:58`); Plan-`stripe_price_id_monthly/_yearly` gepflegt (sonst Abo-Checkout deaktiviert). Danach Checkout-Smoke-Test inkl. Webhook. **[EXTERN: Live-Stripe-Zugang]**
- [x] **R1.3 Quota-Reset-Provisorium festschreiben** — `ResetMonthlyPressReleaseQuota` ist als „temporärer Stub bis zum echten Tarif-/Credit-Modul" markiert, läuft aber monatlich per Scheduler. Prüfen ob das Verhalten fürs Release korrekt ist (Zusammenspiel mit Credit-Wallet/Add-ons); Doc-Kommentar aktualisieren oder Logik ersetzen.
- [ ] **R1.4 Preise/Lineup final abstimmen** — `PreisePageData.php:44` TODO („Lineup/Preise hängen am Bookings-/Magic-Link-Rework"): öffentliche Preisseite (correction/update/depublish-Pfade) gegen finale Preisliste prüfen. **[EXTERN: Preisfreigabe]**
- [ ] **R1.5 Refund-Workflow: Entscheidung** — laut hub-flux offen. Empfehlung: nachgelagert (Refunds initial direkt im Stripe-Dashboard), Entscheidung dokumentieren.
---
## Phase R2 — Web-Frontend funktional fertigstellen
- [x] **R2.1 Kontaktformular anbinden** — `kontakt.blade.php:52` TODO: aktuell nur `mailto:`, kein Form/Handler; Telefon/Adresse sind Fake-Daten. Umsetzung analog `LegalRequestController` (POST-Controller + Validierung + Honeypot + `throttle` + Mailversand an konfigurierbare Adresse). Feature-Tests. Echte Kontaktdaten **[EXTERN]**.
- [x] **R2.2 Hub-Pricing datengetrieben** — `pressekonto.blade.php:401/469/538`: 3 hartcodierte Pricing-`<article>`s (0 €/49 €/149 €) → `<x-web.pricing-teaser>` (iteriert `Plan::active()`, wird von beiden Spokes schon genutzt). Beseitigt Drift-Risiko zum Plan-Katalog. *(= alt Phase 6.1)*
- [x] **R2.3 Tote `href="#"`-Links in Live-Seiten fixen** — pressekonto (16×, u. a. Kundenlogos + Support-/Datenschutz-Links), release-detail (3×, Share-Aktionen), `hub/top-utility-bar` (3×), `events-week`/`highlight-card`. Echte Ziele setzen oder Elemente entfernen.
- [ ] **R2.4 SEO-Basics** — Sitemap fehlt komplett: `sitemap.xml`-Route je Domain (veröffentlichte PMs + Newsrooms + statische Seiten); `robots.txt` um Sitemap-Verweis ergänzen. Fehlende `meta_description` nachziehen (home-Sections, karriere, partner, presse, team); hartcodierte „Business Portal 24"-Titel brand-aware machen. Tests.
- [ ] **R2.5 legal-request-Hinweistexte finalisieren** — `legal-request.blade.php:8/65`: Texte je Anfragetyp als „ENTWURF" markiert. **[EXTERN: finale Texte]**
---
## Phase R3 — Inhalte [EXTERN, früh anstoßen, parallelisierbar]
- [ ] **R3.1 Rechtstexte final** — `agb`, `datenschutz`, `impressum`, `cookies` sind explizit als „Platzhalter — vor Go-Live ersetzen" markiert. Ohne finale Texte **kein Go-Live** (Abmahnrisiko). Cookie-Consent-Setup klären.
- [ ] **R3.2 Marketing-Seiten: Inhalt oder Rückbau** — `presse` (erfundener Pressekontakt „Lisa Müller"), `team` (erfundene Personen), `karriere` (Bewerben-Buttons ohne Ziel), `partner`, `hilfe` (dünn), `ueber-uns` (Platzhalter-Kennzahlen) sind live geroutet. Pro Seite entscheiden: echte Inhalte liefern **oder** Route + Navigation vorerst entfernen. Empfehlung: lieber weniger Seiten, aber ehrlich.
---
## Phase R4 — Web-Frontend aufräumen (= alt Phase 6; vor jedem Löschen bestätigen)
> Kontext (User, 03.07.): Bei der Frontend-Entwicklung gab es eine **alte Version** — es können noch **Fragmentseiten aus dieser Version** herumliegen. Die Funde unten (examples/, altes engl. Header/Footer-Layout, welcome, brand-mark, Variant-Views) passen dazu; beim Aufräumen gezielt nach weiteren Alt-Fragmenten suchen (auch in `components/web/**` und ungerouteten Blades).
- [ ] **R4.1 Tote Dateien entfernen** — `web/examples/` (4 Demo-Views mit Lorem/Mustermann), `welcome.blade.php`, `brand-mark.blade.php`, `layouts/web-master-test.blade.php`, `layouts/footer.blade.php` + `layouts/header.blade.php` (altes englisches Layout, 38 tote Links) — alle nirgends geroutet/inkludiert (verifiziert per grep; dynamische Auflösung vor Löschen nochmal prüfen).
- [ ] **R4.2 Tote Komponenten entfernen** — 12 ungenutzte `x-web`-Komponenten: `category-strip`, `dossier-card`, `events-week`*, `hero-banner`, `highlights-slider`, `home-hero`, `press-release-list-item`, `presseecho-release-card`, `sidebar-categories`, `sidebar-companies`, `sidebar-newsletter`, `sidebar-rss`. (*`events-week` erst nach Entscheidung R2.3/Konzept „echte Datenquellen".)
- [ ] **R4.3 Dedup (optional, nice-to-have)** — Release-Card-Vereinheitlichung, Industrie-Icon-Map → Config, Inline-SVGs → Icon-Set, `<x-web.container>` (alt 6.2/6.3). Nur wenn Zeit; kein Release-Blocker.
---
## Phase R5 — Deploy-Readiness
- [ ] **R5.1 `.env.example` vervollständigen** — es fehlen alle projektspezifischen Keys: Portal-URLs (`APP_PORTAL_URL/NAME/…`, `APP_BUSINESSPORTAL_*`, `APP_PRESSEECHO_*`, `APP_PROTOCOL`), Legacy-DBs (`DB_*_BUSINESSPORTAL`, `DB_*_PRESSEECHO`), Stripe/Billing (`STRIPE_KEY/SECRET/WEBHOOK_SECRET`, `STRIPE_PRICE_SINGLE_PM`, `BILLING_*` inkl. `BILLING_OWN_VAT_ID`), KI (`OPENAI_*`, `CLASSIFICATION_*`, `CONTENT_SCORE_*`), `SANCTUM_STATEFUL_DOMAINS`, `NEWSLETTER_SYNC_*`, `BASIC_AUTH_*`, `SESSION_SECURE_COOKIE`.
- [ ] **R5.2 Deploy-Runbook schreiben** — fürs neue Laravel-System existiert **keine** Deploy-Anleitung (FTP-LIVE-DEPLOY.md betrifft nur das Alt-Symfony-System). Inhalt: `composer install --no-dev --optimize-autoloader`, `npm run build` (Builds sind gitignored!), `php artisan storage:link`, `migrate --force`, Seeder-Reihenfolge (`RolesAndPermissionsSeeder`, `PlanSeeder`, `PaymentOptionSeeder` — NICHT der Test-User-Seed), `config:cache`/`route:cache`/`view:cache`, **Queue-Worker** (database-Queue: `ScorePressRelease`, `ClassifyPressRelease`) + **Cron** `schedule:run` (5 Tasks, u. a. `PublishScheduledPressReleases` alle 5 Min — ohne Cron werden geplante PMs nie veröffentlicht). Prod-`.env`-Solltabelle: `APP_ENV=production`, `APP_DEBUG=false`, echter `MAIL_MAILER` (Default `log`!), `SESSION_SECURE_COOKIE=true`, `DB_CONNECTION=mysql`.
- [ ] **R5.3 Monitoring/Alerting entscheiden** — kein Sentry o. ä. installiert; Scheduler-/Queue-Failure-Alerting fehlt. Minimalvorschlag: `schedule`-`onFailure`-Mail + Log-Rotation; optional Sentry. **[EXTERN: Entscheidung]**
- [ ] **R5.4 Favicons je Domain** — `domains:generate-favicons` erzeugt bewusst leere Platzhalter-Dateien; echte Favicons für pressekonto/presseecho/businessportal24 deployen. **[EXTERN: Assets]**
---
## Phase R6 — QA & Go-Live (teils extern/Ops)
- [ ] **R6.1 Manuelle QA-Checkliste durcharbeiten** — `dev/migration 2026/06-FEATURES-SCOPE.md` §15 (komplett offen): Logins inkl. 2FA + Magic-Link, Portal-Scoping, PM-Workflow Admin+Customer, Image-Upload, Blacklist, Stripe-Checkout inkl. Webhook + Invoice-PDF, Grandfathering, Legacy-Rechnungen, API (Sanctum + Abweisung alter api_key), Thumbnail-Redirect, Scheduler. Dabei auch verifizieren, was die (veraltete) Frontend-Konzept-Doku noch als offen führt (Branchen-/Kategorieseite, Veröffentlichen-Landing — im Code existieren `KategorieController`/`VeroeffentlichenController` bereits → visuell abnehmen statt neu bauen).
- [ ] **R6.2 Security-Review** — CSRF/CORS (keine `config/cors.php` → Framework-Default prüfen), Rate-Limits, Upload-Handling, Magic-Link-TTL, `SESSION_SECURE_COOKIE`/`same_site` (Multi-Domain!), BasicAuth-Strategie für Staging. *(= P10.5)*
- [ ] **R6.3 Staging-Import-Rehearsal** — Datenimport gegen produktiven Legacy-Snapshot auf Staging (mehrfach als der offene Vollständigkeitsnachweis referenziert, P6.10/P11.3). Achtung: `mysql_businessportal`-Verbindung lokal ist nur ein ~April-Snapshot — fürs Rehearsal echten aktuellen Dump ziehen. **[EXTERN: Server/Snapshot]**
- [ ] **R6.4 Go-Live-Kette** — Go-Live-Mailing (Passwort-Reset) + API-Kunden-Mailing: Code fertig, **finale Texte + Freigabeliste [EXTERN]**; DNS-Cutover `pressekonto.de`; Legacy-System read-only während Final-Import; alte Symfony-Server abschalten. *(= P11.x)*
- [ ] **R6.5 Git-Hygiene** — Branch `fix/zeitzone-europe-berlin` (73 Commits vor `main`) pushen und nach `main` mergen; danach Release-Tag. Die drei `user_filter_presets`-Migrations zusammenführen (rev-5, „Hygiene vor Go-Live") optional davor.
- [ ] **R6.6 Doku-Sync** — `dev/migration 2026/12-NAECHSTE-SCHRITTE.md` + `08-PROGRESS.md` auf den echten Stand bringen (Phase 8/Stripe als erledigt markieren), damit die Doku nicht weiter in die Irre führt.
---
## Bewusst NACHGELAGERT (kein Teil dieses Release-Plans)
- **Kompletter getesteter User-Panel-Flow** (User-Entscheidung 03.07.2026).
- Echte Newsletter-Sync-Implementierung (No-Op bleibt, R0.3 macht es nur ehrlich); Newsletter-Subscriber-Admin/CSV (P3.7, vertagt).
- Coupons (UI-Skeleton, D-16 vertagt), Google-Login (Socialite), Regionen-Übersichten `/region/{slug}` (301-Redirect bleibt), Blacklist-Admin-UI (Config reicht), PM-Nice-to-haves (Inline-Edit, Bulk, In-App-Notifications, Permission-Granularität).
- Legacy-Logging/-Performance-Deployments (betreffen nur das Alt-System als Überbrückung bis zum Cutover).
- Performance-Polishing aus `11-NOCH-ZU-TUN-OPTIMIERUNGEN.md` (Slow-Query-Auswertung braucht echte Live-Daten).
- Coverage-Ziel 70 % / arch()-Tests / `test --parallel` (P10.1–10.3) — Suite ist grün, Ausbau nachgelagert.
---
## Reihenfolge-Empfehlung (TL;DR)
1. **R0** sofort — kaputte Pfade, DSGVO, Seeder, Fehlerseiten (alles klein, Test-First).
2. **[EXTERN]-Punkte parallel anstoßen** — Rechtstexte (R3.1), Stripe-Live-Zugang (R1.2), Enforce-Booking-Entscheidung (R1.1), Kontaktdaten (R2.1), Mailing-Texte (R6.4). Das sind die längsten Wartezeiten.
3. **R1 + R2** — Billing scharf + Frontend funktional (Kern der Fertigstellung).
4. **R4 + R5** — Aufräumen + Deploy-Runbook, sobald R1/R2 stehen.
5. **R6** — QA, Security, Rehearsal, Cutover.