presseportale/dev/release/entwicklungsplan-release.md
Kevin Adametz 5a352425d7 API-Legacy-Paritaet: Arbeitsdokument mit Alt-Vertrag, Log-Auswertung, Schrittplan
- Alt-Vertrag komplett aus dem Symfony-Code extrahiert (Routen, Params
  verschachtelt, Response-Shapes, Sofort-Publish-Logik, Fehlerformat)
- Prod-Logs (dev/api, User) ausgewertet: ein Client (connektar),
  5 Endpoints; Company-/Kontakt-Create heute 410 -> muessen nachgebaut
  werden; Sofort-Publish beim POST belegt
- Entscheidungen 10.07.: Sofort-Publish + Admin-Schalter KI-Pruefung,
  getrennte Legacy-/v1-API, Ablehnungs-Rueckkanal spaeter
- dev/api/ enttrackt (.gitignore, Produktivdaten analog SQL-Dumps)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 13:40:24 +00:00

176 lines
43 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: 09.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].
**03.07. abends — Hub-Inhalts-Audit + Rechtstexte (Entscheidung E2: B2B-only!):** Alle Hub-/Web-Inhalte gegen den echten Funktionsstand geprueft und korrigiert (Startseiten-Claims, FAQ, Hilfe, Veroeffentlichen, API-Doku inkl. OpenAPI); kontakt/ueber-uns zurueckgebaut; Rechtstexte aus docs/legal eingebaut (Impressum echt, AGB v0.6, /richtlinien, /melden); Widerrufs-UI raus (E2), Submit-Modal auf Archiv-Hinweis (T2neu); Preise nach Leistungsbeschreibung v0.2. Details in R3.0–R3.2.
**03.07. spaet — Rechtstexte komplett + T1neu + Mail-CI (TAGESABSCHLUSS, Suite: 935 gruen):** Datenschutzerklaerung v0.3 host-aware eingebaut (Hub-/Spoke-Bausteine, Magic-Link 15 Min., Stripe Payments Europe); Cookie-Seite zurueckgebaut (301 -> /datenschutz, Cookies stehen in Abschnitt 4, kein Banner). T1neu umgesetzt: Unternehmer-Pflicht-Checkbox im Buchungs-Modal, protokolliert in `booking_confirmations` (Timestamp/IP/AGB-Version aus `config/legal.php`), CheckoutController erzwingt zeitnahe Bestaetigung serverseitig. System-Mails auf zentrales pressekonto-CI-Layout umgestellt (components/emails/layout, inkl. Framework-Auth-Mails via toMailUsing, EmailBrandingTest).
**06.07. — Zentrale Rechts-E-Mail (User-Entscheidung):** `info@pressekonto.com` ist die Haupt-E-Mail fuer alle rechtlichen Anliegen; zentral in `config/legal.php` (`LEGAL_CONTACT_EMAIL`), alle fuenf Rechtsseiten (Impressum, AGB, Datenschutz, /melden, /richtlinien) nutzen sie domainuebergreifend. Support-/Redaktionskontakt bleibt je Brand (CONTACT_EMAIL_*), REPORT_EMAIL_* ist nur noch optionales separates DSA-Postfach. Live-Domain bestaetigt .com (Deployment-Checkliste), nicht .de.
**06.07. — Umami eingebaut + Klaerungsliste KOMPLETT beantwortet:** Umami-Snippets (dev/release/umami.md, sys.adametz.media) je Brand in `config/domains.php` (`brand.umami_website_id`), gerendert via `x-web.umami` im web-master-Layout — per `UMAMI_ENABLED=false` deaktiviert bis zum Go-Live (User-Vorgabe; Checklisten-Punkt in WS-7 ergaenzt). User bestaetigt: Server-Fristen (Logs 14 Tage, Backups 4 Wochen) stimmen, Stripe-Entitaet (Stripe Payments Europe, Dublin) passt. **Inhaltliche Freigaben erteilt:** AGB par. 1 (3) Portalliste via Hub-#familie ok · AGB par. 11 (3) Kuendigungsseiten-Ergaenzung ok · Depublikations-Preis neutral ohne Betrag ok (bis T12) · Medienprivileg-Zitierung bleibt vorsichtig (par. 57 Abs. 1 MStV) bis anwaltliche Praezisierung · /melden-Aenderungsweg ueber Magic-Links fuer Launch ok. Damit sind die Rechtstexte inhaltlich final; offen nur noch [EXTERN] (anwaltliche Freigabe, Postfach info@pressekonto.com).
**06.07. — R3.1-Restbacklog KOMPLETT umgesetzt (Suite: 956 gruen):** (a) E3-Versionierung: `legal_documents`-Tabelle (type/version/effective_from, Fassungen unloeschbar, zukuenftige erst ab Stichtag; `LegalDocument::current()`, Seeder mit den 5 aktuellen Fassungen) + `legal_document_id` an `booking_confirmations` (T1neu referenziert jetzt die konkrete AGB-Fassung; config/legal.php nur noch Fallback). (b) `rejection_categories`-DB: /richtlinien rendert aktive Kategorien live (Seeder K1–K6; deaktivieren statt loeschen). (c) T13: Melde-Zeile sichtbar unter jedem Artikel. (d) T10: Formulare /melden/rechtswidrig (DSA Art. 16 inkl. Wahrheitsversicherung) + /melden/kontaktdaten (DSGVO) mit URL-Feld und automatischem PM-Match; Vorgangsnummer M-{id}; unverzuegliche Eingangsbestaetigung + internes Postfach-Mail (auch im Per-PM-Flow); Admin-Queue zeigt Vorgangsnummer/URL/Name. (e) T12: Depublikations-Checkout (Panel auf der Kunden-PM-Seite mit T1neu-Checkbox + Doppelausweis, Stripe-Ad-hoc-Charge, Webhook depubliziert → Status archived + `depublished_at`, oeffentliche URL zeigt Tombstone mit 410). **Preis entschieden (O6, User 06.07.): 35 EUR netto** — Default 3500 in config/billing.php, per BILLING_DEPUBLICATION_PRICE_CENTS ueberschreibbar (0 deaktiviert). Go-Live: beide Seeder in WS-7-Checkliste.
**06.07. — Spoke-Frontend-Audit umgesetzt (Fake raus, Newsletter zurueckgebaut, Boersendaten echt, EN-Lokalisierung):** Ergebnis des businessportal24-Frontend-Audits vollstaendig abgearbeitet: (a) **Fake-Inhalte entfernt** — Fake-Anzeigen (`focus-ad`, `feed-ad`, Inline-Ad + Studie-Box in release-detail) geloescht; alle Mock-/Fallback-Daten raus (focus-hero, feed, most-read, active-newsrooms, industry-spotlight, industry-index rendern jetzt nur noch mit echten Daten oder gar nicht); Legacy-Mock-Komponenten geloescht (`featured-releases`, `press-releases-grid`, `highlight-card`, `press-release-card`); tote Links/Buttons ersetzt oder entfernt (Newsroom-Link, Richtlinien-Link, Print statt Permalink, „Newsroom folgen" raus, RSS-Erwaehnung raus, ⌘K funktional). (b) **Newsletter zurueckgebaut** — `newsletter-strip` aus allen Spoke-Seiten + Newsletter-Box aus release-detail entfernt (Feature nachgelagert, s. unten; Backend/DOI-Hinweis in R6.1 bleibt). (c) **Boersendaten echt** — neuer `MarketDataService` (Yahoo-Finance-Quotes, `config/market.php`, Cache) + Artisan-Command `market:refresh` alle 15 Min. im Scheduler; `live-ticker` konsumiert nur noch echte Daten und blendet sich ohne Daten aus. (d) **EN-Lokalisierung** — alle UI-Texte der Kern-Seiten (Header/Footer, Home-Sektionen, release-detail, kategorie, suche, newsrooms, newsroom, Pagination) in `lang/de/web.php` + `lang/en/web.php` ausgelagert; `Carbon::setLocale('de')`-Hardcodes auf `app()->getLocale()` umgestellt. **Langform-Seiten (veroeffentlichen, faq, hilfe, api) bleiben vorerst deutsch** — hreflang="en" dort entfernt; EN-Uebersetzung nachgelagert.
**06.07. — Zwei Legacy-Befunde des Users gefixt:** (1) **Buchungs-Gate-Bug:** `grandfatheredNow` verlangte ein gesetztes `grandfathered_until` — das ist aber das explizite Legacy-Vertragsende und im Import-Regelfall NULL; dadurch hatte praktisch kein Bestandskunde eine aktive Zahlungsoption („Buchung erforderlich"). Jetzt deckelt `grandfathered_until` nur, wenn gesetzt; sonst zaehlt die laufende, vom MAN-Lauf fortgerollte Periode (`current_period_end`). Lokal: 15/22 Vereinbarungen wieder aktiv, Limits/unbegrenztes Kontingent greifen. (2) **Legacy-API-Uebernahme (User-Entscheidung, ersetzt „OUT" aus der Scope-Doku):** `legacy:import-api-keys` uebernimmt die api_keys der Altportale als Sanctum-Tokens mit identischem Secret (nur berechtigte Nutzer; Dry-Run lokal: 406 Keys); die Auth-Middleware uebersetzt X-ApiKey/api_key fuer gueltige Keys in Bearer (unbekannte weiter 410+Hinweis); die dokumentierten /service/…-Pfade sind Aliasse auf die v1-Controller (nicht uebernommene Alt-Endpoints antworten 410 mit Hinweis). Go-Live-Kette: Import laeuft NACH dem Grandfathering (WS-7 ergaenzt). Ausserdem R6.1-Vorpruefung: /thumbnails-Redirect nachgeruestet (fehlte trotz „ANGEPASST"-Vermerk), QA-Checkliste `dev/release/qa-checkliste.md` erstellt.
**06.07. — Bestandskunden end-to-end verifiziert + Adress-Luecke geschlossen (Suite: 993 gruen):** Nach dem Buchungs-Gate-Fix zeigte sich die naechste Luecke der Kette: Der MAN-Rechnungslauf ueberspringt Vereinbarungen ohne Rechnungsadresse — und der Grandfather-Import nahm Adressen nie mit, weil die Altportale sie nur als Freitext-Blob fuehren. Neu: `legacy:import-billing-addresses` (LegacyAddressParser strukturiert die Blobs best-effort, raet nie; Report der manuell nachzupflegenden Faelle; nie ueberschreibend; CY in config/countries.php ergaenzt). Lokal: 11/21 Bestandskunden mit Adresse, MAN-Lauf rechnet ab (Zypern-Rechnungen exakt wie Legacy-Brutto, kein Preissprung), 9 manuell zu klaeren (7 leere Alt-Adressen). API-Key-Import echt gelaufen (406 Tokens), connektar-Key end-to-end gegen /service und /api/v1 verifiziert (200). **Git-Hygiene vorgezogen:** Users Frontend-Umbau committet (eigener Commit), Produktiv-SQL-Dumps enttrackt + .gitignore (User-Entscheidung: ohne History-Bereinigung, Repo bleibt privat; Dumps liegen weiter lokal fuer R6.3).
**07.07. — QA-Abschnitt A abgenommen + Billing/USt-Haerten + Tarifwechsel/Downgrades:** QA-Checkliste Abschnitt A (Login & Konto) komplett manuell abgenommen; dabei 3 2FA-Befunde gefixt: 2FA-Einrichtung verlangt jetzt Code-Bestaetigung (vorher keine Login-Challenge), Recovery-Codes nur noch einmalig sichtbar, falscher Challenge-Code crasht nicht mehr (fehlende Route `two-factor.login`); E-Mail-Wechsel jetzt als Pending-Flow mit Bestaetigungslink an die neue Adresse. **Stripe-USt vervollstaendigt:** `automatic_tax` in der Checkout-Session aktiviert (USt fehlte vorher in der Session), STR-Rechnungsspiegelung liest USt aus `total_taxes` (Stripe-API liefert kein `tax`-Feld), Profil-Rechnungsadresse als Stripe-Rechnungsempfaenger (Wallet-Daten ueberschreiben sie nicht mehr); Rechnungsseite listet neue STR/MAN-Rechnungen (STR verlinkt ins Stripe-Portal), Archiv-Filter entfernt, Altsystem-Archiv nur noch fuer Bestandskunden. **Tarifwechsel im Buchungs-Modal:** Abo-Swap mit anteiliger Verrechnung; Downgrades ohne Gutschrift erst zum Periodenende, Kontingent-Sperre beim Wechsel. **UX-Runde:** Volltext-Suchindex (+ Fix doppelte Alpine-Instanz), PM-Vorschau im echten Portal-Design mit Portal-Switch, Ablehnungsbegruendung direkt im Editor, Einreichen-Modal-Panelstruktur + fixierter Kontingent-Badge, Add-ons-Modal statt Toast bei fehlendem Guthaben, Depublikations-Sektion ans PM-Seitenende + Direktlinks je Portal, `single_purchases`-ENUM um `depublication` erweitert, abgebrochener Depublikations-Checkout blockiert nicht mehr.
**08.07. — Agentur-Attribution + Depublikations-Kauf + eVatR-USt-ID-Pruefung:** Agentur-Attribution neu geloest — Uebermittler kommt aus neuem Profilfeld `users.agency_name` statt eigener Agentur-Firma; PM-Detailseite zeigt Urheber/Uebermittler-Zeile; `legacy:migrate-agency-names` uebertraegt die Alt-Agenturnamen; `companies:retire-agency-type` schafft den Firmen-Typ „Agentur" ab; Firmen-Typ-Auswahl aus der Profil-UI entfernt (Plan abgehakt, Abnahme 08.07. dokumentiert). **Depublikation end-to-end:** Kauf wird als eingeloest markiert, erzeugt Rechnung + Bestaetigungs-Mail; Buchungsseiten-Verlauf zeigt den Kauftyp, Erfolgsmeldungen gruen. **USt-ID-Pruefung (neu):** vor jeder Buchung per eVatR (EU-VIES) gegengeprueft, Stripe-Tax-IDs abgeglichen; eigene USt-IdNr. aus `BILLING_OWN_VAT_ID`. Deploy-Runbook §3a ergaenzt: FULLTEXT-Migrations-Wartungsfenster fuer `press_releases` (bei importiertem Bestand faellt jede Spaltenaenderung auf ALGORITHM=COPY = Stunden; Ablauf Indizes droppen -> migrieren -> nacheinander neu bauen = ~6 Min).
**09.07. — KI-Kennzeichnung (Art. 50 KI-VO) + PM-Editor-UX + Tages-Fixes (Suite: 1142 gruen):** KI-Kennzeichnung als **Pflicht-Deklaration fuer Text und Bilder** umgesetzt (Enums `AiTextDeclaration`/`AiImageDeclaration`, Model `PressReleaseAiDeclaration` + Migrations, Concern `InteractsWithAiDeclaration`, `AiDeclarationRequiredException`, oeffentliches Label `portal/ai-public-label`, Test `PressReleaseAiDeclarationTest`) — EU-KI-VO Art. 50 Transparenzpflicht. PM-Editor-UX: Kategorie in die Schreibflaeche, Bild-Upload als Modal-Flow. **Tages-Fixes:** OpenAPI-Route `/docs/api/v1` auf `public/api/v1.yml` umgebogen (der `docs/`-Ordner ist ein nicht mitgekommener Mount; Route lief sonst 500) + 404-Guard; `depublish`-Credits `25 -> 35` (Entscheidung O6) in config bestaetigt und die zwei stehen gebliebenen Preis-Tests nachgezogen. Suite wieder komplett gruen (1142).
**09.07. abends — R5.3 Monitoring + Buchungsdaten + kompletter WIP in 7 Commits committet (Suite: 1149 gruen):** (a) **R5.3 Monitoring** umgesetzt (Details in R5.3): `OperationalAlert` (immer `Log::critical` + Best-Effort-Mail an `MONITORING_ALERT_EMAIL`), alle 6 Scheduler-Tasks mit `->onFailure()`, Queue-`failing`-Listener, `LOG_STACK=daily` als Prod-Soll. (b) **Buchungs-/Verlaengerungsdatum** des Abos auf der Buchungsseite (`SubscriptionPeriodResolver` holt `start_date` + `current_period_end` gecacht aus Stripe, da Cashier die Periode nicht lokal spiegelt). (c) Den kompletten bis dahin uncommitteten Arbeitsbaum in **7 fokussierte Commits** zerlegt (Branch jetzt **~187 vor `main`**): OpenAPI-Route auf `public/api/v1.yml` (500-Fix) · Depublish-Credit 35 · Buchungs-/Verlaengerungsdatum · R5.3 Monitoring · Release-Doku · Backend-WIP (Kontakt-Queue, Page-Cache, Validierungs-Feedback, Company-Portal-Restriction, i18n-Auslagerung) · Web-Frontend-Umbau (separat, User-Bereich; Kontakt-Modal durch `contact-launcher` ersetzt). **Bewusst uncommittet belassen:** `sidebar.blade.php` (User-Regel, aus allen Commits ausgeschlossen), der geloeschte `docs/`-Mount + `config/pressekonto.code-workspace` (Mount nicht mitgekommen — die einzige code-relevante Datei `docs/api/v1.yml` liegt jetzt als `public/api/v1.yml` vor), zwei Dev-Screenshots in `dev/frontend/booking/`.
**10.07. — PM-Tracking (User-Einschub, `docs/weiteres/Pm Tracken.md`):** Ereignis-Log `press_release_events` (type view/share, channel, ohne Personenbezug) + Model/Enums/Factory. Aufrufe: Legacy-`hits`-Zaehler bleibt die angezeigte Wahrheit (bewusst einfacher Page-Request-Zaehler, User-Vorgabe), zusaetzlich View-Event je Detailaufruf; oeffentliche Detailseite zeigt Aufrufe wieder in der Meta-Zeile (wie im Altsystem, beide Hero-Varianten, nicht in der Vorschau). Shares: `POST …/press-release/{slug}/share` (throttle 30/min, nur archiv-sichtbare PMs) loggt LinkedIn/X/E-Mail/Link-kopiert-Klicks der Teilen-Buttons (fetch keepalive + CSRF-Meta); Kundenpanel-PM-Seite zeigt neue Kachel „Geteilt" mit Gesamtzahl + Kanal-Aufschluesselung. Tests: `Web/PressReleaseTrackingTest` (7). Hinweis: Branch war zu Sessionbeginn bereits vollstaendig gepusht; die „drei user_filter_presets-Migrations" (R6.5 optional) existieren nicht mehr — es gibt nur noch eine konsolidierte, Punkt gegenstandslos.
**10.07. nachmittags — R2.5 + QA-Nachpruefung + R4.3 + KI-Queue-Fix + API-KI-Deklaration (Suite: 1165 gruen):** R2.5 erledigt (legal-request-Texte aus freigegebenem Meldeverfahren, s. R2.5) · QA-Checkliste B–G vertieft (s. R6.1) · R4.3 erledigt (Karten-Helper am Model, s. R4.3). **Befund KI-Pruefung:** Auto-Routing (Rot → Ablehnung, Gelb/Gruen → Auto-Publish) war laengst gebaut, lief lokal aber nie — `composer run dev` startete den Worker ohne `--queue=default,classification`; gefixt, Backlog abgearbeitet (Pipeline live verifiziert; Prod-Runbook war korrekt). **Befund + Fix API (Entscheidung User 10.07.):** v1-API hatte keine KI-Deklarationsfelder → Submit lief seit 09.07. immer auf 422 (haette alle 406 Legacy-API-Kunden blockiert; Suite uebersah es, weil die Factory deklariert). Jetzt: `ai_text_declaration` Pflicht im v1-Submit (Call gilt dokumentiert als verbindliche Bestaetigung + Archiv-Kenntnisnahme AGB § 13), `ai_declaration` Pflicht je Bild-Upload; Legacy-/service-Pfade defaulten auf none/original (Mailing R6.4 weist darauf hin, dass die weitere Nutzung diese Erklaerung darstellt); OpenAPI + /api-Seite aktualisiert. Tests: Submit-/Image-/Legacy-API-Tests erweitert. **Beobachtung fuer QA/Launch:** Test-Kauderwelsch („asdas dsada…") wurde Gruen klassifiziert und auto-publiziert — vor Go-Live Prompt/Schwelle pruefen bzw. `CLASSIFICATION_GREEN_DELAY` als Sicherheitsfenster setzen [USER-ENTSCHEIDUNG].
**10.07. abends — API-Legacy-Paritaet (neues Arbeitsdokument `dev/release/api-legacy-paritaet.md`):** User-Vorgabe: /service-API muss beim Cutover verhaltensgleich zum Altsystem laufen. Alt-Vertrag vollstaendig aus dem Symfony-Code (`_businessportal24.com/`) extrahiert; Prod-Aktivitaets-Logs (User, `dev/api/` — enttrackt via .gitignore, Kundendaten!) ausgewertet: **ein echter Client (connektar), 5 Endpoints, Sofort-Publish beim POST belegt; 2 der 5 Endpoints (Company-/Kontakt-Create) laufen heute auf 410.** Entscheidungen: Sofort-Publish nachbilden + Admin-Schalter fuer KI-Pruefung der Legacy-Einlieferungen; Legacy-API und v1 bleiben getrennt; Ablehnungs-Rueckkanal spaeter in v1. **Naechster Schritt: S1+S2 aus der Paritaets-Doku implementieren (Compat-Controller + Statusverhalten), dann S4 Testdaten (User-Vorgaben folgen).**
**Wiedereinstieg / naechste Schritte:**
1. ~~Klaerungsliste Rechtstexte~~ **erledigt 06.07.**; ~~R3.1-Restbacklog~~ **erledigt 06.07.** (siehe oben).
2. **[EXTERN]:** Postfach `info@pressekonto.com` anlegen (Haupt-Rechts-Mail, 06.07.); CONTACT_EMAIL_*-Support-Postfaecher je Brand; REPORT_EMAIL_* optional · R1.2 Stripe-Live · R1.4 Preisfreigabe · R5.4 Favicons · anwaltliche Freigabe AGB v0.6/Datenschutz v0.3. (~~Depublikations-Preis~~ entschieden: 35 EUR netto.)
3. **Phase-2-Rest (bewusst nach Launch):** T11-Ausbau DSA-Queue (Basis existiert) · englische Rechtstexte (O-C, nach Sprachvarianten-Entscheidung) · oeffentliche Versionshistorie der Rechtstexte (O-D) · Ablehnungs-Mails mit Kategorie-Link (rejection_categories im Reject-Flow verdrahten).
4. **Dann:** R6.1 manuelle QA-Durchgaenge (User, per qa-checkliste.md), R6.3 Staging-Rehearsal [EXTERN], R6.4 Go-Live-Kette, R6.5 Git-Hygiene-Rest: Branch (~187 Commits vor main, Stand 09.07.) pushen + mergen + Release-Tag, sobald freigegeben (~~vorher WIP zerlegen~~ **erledigt 09.07., 7 Commits**); optional die drei user_filter_presets-Migrations zusammenfuehren. (~~SQL-Dump-Entscheidung~~ erledigt 06.07.: enttrackt + ignoriert.)
---
## ▶ Wo es morgen weitergeht (Stand 09.07.2026 abends)
**Ausgangslage:** Arbeitsbaum ist aufgeraeumt — der gesamte WIP ist in 7 Commits auf `fix/zeitzone-europe-berlin` (~187 vor `main`), Suite gruen (1149). Uncommittet bleiben nur bewusst: `sidebar.blade.php` (User), der `docs/`-Mount + `config/pressekonto.code-workspace`, zwei Dev-Screenshots.
**Als Naechstes in meiner Hand (kein externer Input noetig), Empfehlung in dieser Reihenfolge:**
1. ~~**QA-Checkliste B–G vertiefen**~~ **erledigt 10.07.:** alle Beleg-Tests verifiziert (Suite 1156 gruen), B–G um die Features 07.–10.07. ergaenzt (KI-Kennzeichnung, Tracking, Kontakt-Queue, Tarifwechsel, eVatR, Monitoring u. a.), Frontend-Umbau-Vorbehalt in F aufgehoben. Neuer (unkritischer) Befund: Page-Data-Cache ohne Publish-Invalidierung, max. 5 Min. Verzug auf Home/Kategorie — dokumentiert, kein Blocker. Jetzt sind die manuellen Browser-/Staging-Durchgaenge (User) dran.
2. **R4.3 Dedup** (optional, „nur wenn Zeit") — Release-Card-Varianten (feed-item, focus-hero, focus-side-item, feed-top-item) vereinheitlichen, Inline-SVGs (13 Web-Komponenten) → Icon-Set; Industrie-Icon-Map hat der Frontend-Umbau bereits erledigt. Kein Blocker.
3. ~~**R6.5 optional:** die drei `user_filter_presets`-Migrations zusammenfuehren~~ **gegenstandslos (10.07.):** es existiert nur noch eine konsolidierte Migration.
**Wartet auf Dich / extern (nicht durch mich abschliessbar):** R6.5 Branch merge + Release-Tag (Dein Go; Push ist erfolgt) · R1.2 Stripe-Live · R1.4 Preisfreigabe · R1.5 Refund-Entscheidung · (~~R2.5 legal-request-Texte~~ erledigt 10.07., Wortlaut aus freigegebenem Meldeverfahren) · R5.4 Favicons · R6.3 Staging-Rehearsal · R6.4 Go-Live-Kette · Postfach `info@pressekonto.com` · anwaltliche Freigabe.
**Bewusst nachgelagert (nicht Teil dieses Release):** Sentry/APM · User-Panel-Vollflow · Newsletter-DOI · EN-Rechtstexte · T11-DSA-Queue-Ausbau.
---
## 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.
- [x] **R2.4 SEO-Basics** — Erledigt 03.07.: Host-aware `sitemap.xml` (Hub: Landing + Rechts-/Info-Seiten; Spokes: zusätzlich Kategorien, öffentliche Newsrooms, alle im Archiv sichtbaren PMs des Portals; 1h-Cache pro Host). `robots.txt` jetzt dynamische Route mit Sitemap-Verweis + Disallow (/admin, /login, /register, Suche) — die statische `public/robots.txt` wurde entfernt (**Deploy-Hinweis:** nicht wieder anlegen, sie würde die Route verschatten). karriere/partner/presse/team: Brand pro Request via `WebPortalContext` (statt hartcodiert „Business Portal 24") + Meta-Descriptions; bp24-Home auf config-getriebenes meta_title/meta_description-Muster vereinheitlicht. Sitemap listet bewusst nur die de-Edition (en-Entscheidung offen, s. Rechtstexte-Doku O3) und lässt Suche + Marketing-Platzhalterseiten (R3.2) draußen. Tests: `SitemapRobotsTest`.
- [x] **R2.5 legal-request-Hinweistexte finalisieren** — Erledigt 10.07.: Die drei Hinweistexte (Meldung/DSGVO/Persönlichkeitsrecht) aus dem am 06.07. inhaltlich freigegebenen Meldeverfahren v0.1 (`static.report.*`) abgeleitet und auf den echten Flow gebracht (Vorgangsnummer M-{id}, unverzügliche Eingangsbestätigung nach DSA Art. 16 Abs. 4 sofern E-Mail angegeben, kostenlose manuelle Prüfung, DSGVO ohne pauschale 30-Tage-Zusage, Querverweis auf /melden). ENTWURF-Marker entfernt; Render-Test erweitert (`LegalRequestTest`). Die ausstehende anwaltliche Freigabe des Rechtstexte-Pakets [EXTERN] deckt diese Texte mit ab.
---
## Phase R3 — Inhalte [EXTERN, früh anstoßen, parallelisierbar]
- [x] **R3.0 Online-Widerruf (gesetzlicher Widerrufsbutton)** — Umgesetzt 03.07., **danach per Entscheidung E2 (B2B-only, `docs/legal/Entscheidung.md` v2.0) zurückgebaut:** Das Angebot richtet sich ausschließlich an Unternehmer (§ 14 BGB), ein Widerrufsrecht besteht nicht — Button + Modal aus Hub-Footer/Static-Shell entfernt, Widerrufsbelehrung archiviert. Backend (`POST /widerruf`, `withdrawal_requests`, Mails, Admin-Queue) bleibt schlafend erhalten und ist bei B2C-Öffnung reaktivierbar.
- [x] **R3.0b Kündigungsbutton** — Erledigt 03.07.: „Verträge hier kündigen"-Button (Hub-Footer + jetzt auch Spoke-Footer) → öffentliche Bestätigungsseite `/de/kuendigung` ohne Login → persistiert `termination_requests` + sofortige Zugangsbestätigung per Mail + Betreiber-Mail; Admin-Queue mit K-Vorgängen. **Einordnung nach E2:** § 312k ist im B2B keine Pflicht — der Selfservice bleibt bewusst als Anti-Zombie-Standard (T3neu).
- [x] **R3.0c Erlöschens-Checkbox → Archiv-Hinweis (T2neu)** — Die § 356-Erlöschens-Bestätigung entfiel mit E2 (B2B-only); an ihrer Stelle verlangt das Einreichungs-Modal jetzt die von AGB § 13 Abs. 1 geforderte Bestätigung der dauerhaften Archivierung (Depublikation nur als kostenpflichtiger Service, gesetzliche Ansprüche unberührt). Zeitpunkt wird weiter als `withdrawal_waiver_consented_at` protokolliert (Spaltenname historisch — Umbenennung optional). Index-Schnell-Submit (wire:confirm) bleibt durch das gemeinsame Modal ersetzt.
- [x] **R3.1 Rechtstexte final** (Code komplett; Rest nur [EXTERN]) — **Inhalte eingebaut 03.07. (Quelle: `docs/legal/*`, untracked):** Impressum (echte Anbieterdaten adametz.media/Bielefeld, DDG, MStV, DSA-Kontaktpunkt via neuer `REPORT_EMAIL_*`-Keys), AGB v0.6 (B2B-Fassung, §§ 1–16, interne Anwalts-Anmerkungen entfernt, Version zentral in `config/legal.php`), **Datenschutzerklärung v0.3** (host-aware Bausteine: Hub Kundenkonto/Login/Stripe, Spokes Medienprivileg/Newsroom/Änderungslinks; Magic-Link-TTL 15 Min. aus dem Code, Logs 14 Tage, Stripe Payments Europe), neue Seiten `/richtlinien` (Rahmentext + K1–K6 statisch) und `/melden` (DSA/DSGVO/Änderung/Depublikation, verdrahtet mit den bestehenden Melde-Links je PM); **Cookie-Seite zurückgebaut** (User-Entscheidung: Cookies in Datenschutz Abschnitt 4, kein Banner; 301 auf /datenschutz). **T1neu erledigt:** Unternehmer-Pflicht-Checkbox im Buchungs-Modal, protokolliert in `booking_confirmations` (Timestamp, IP, AGB-Version); CheckoutController verlangt serverseitig eine zeitnahe Bestätigung (30 Min.) für Abo/Einzel-PM/Topup. Footer + Sitemap ergänzt; Preise-Seite nach Leistungsbeschreibung v0.2 (B2B-Satz, T9-Credit-Anker, Slots/Credits/Boost/Partner-Blöcke, T16-Wording inkl. PlanSeeder). **Restbacklog erledigt 06.07.** (Details im Stand-Block oben): legal_documents-Versionierung + legal_document_id an Buchungen (E3), rejection_categories-DB live auf /richtlinien, T10-Meldeformulare mit Vorgangsnummer + Eingangsbestätigung, T12-Depublikations-Checkout mit Tombstone (config-gated), T13-Melde-Zeile an jeder PM; Umami eingebaut (aus bis Go-Live), zentrale Rechts-Mail info@pressekonto.com. **Noch offen [EXTERN]:** anwaltliche Freigabe AGB v0.6/Datenschutz v0.3 · Postfach info@pressekonto.com. (Depublikations-Preis entschieden: 35 EUR netto, O6.)
- [x] **R3.2 Marketing-Seiten: Inhalt oder Rückbau** — Entschieden + umgesetzt 03.07. (User: Rückbau): `presse`, `team`, `karriere`, `partner` und (2. Runde) `kontakt`, `ueber-uns` samt Routen entfernt (erfundene Adresse/Telefon/Anfahrt bzw. Team/Kennzahlen/Timeline); GET-Alt-Pfade → 301 Startseite, `kontakt.store`-POST bleibt fürs Hub-Modal, Spoke-Footer-Kontakt als mailto (Fallback Betreiber-Postfach bis R2.1). `hilfe` und `faq` inhaltlich auf den echten Funktionsstand gebracht (tote #-Links raus, echte Limits/Features), `veroeffentlichen` vom Fantasie-Preismodell („ab 89 €", Credits je PM, Cross-Publishing separat) auf echte Konditionen umgestellt (datengetrieben via `VeroeffentlichenPageData`). `api`-Seite komplett neu als echte Referenz + OpenAPI `docs/api/v1.yml` (Route lief vorher auf nie existierende Datei → 500 aus Hub-Footer/FAQ).
---
## 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).
- [x] **R4.1 Tote Dateien entfernen** — Erledigt 03.07. (User-Freigabe): `web/examples/` (4 Demo-Views), `welcome`, `home` („B2IN"-Fragment), `brand-mark`-View (die gleichnamige, viel genutzte *Komponente* bleibt), `layouts/web-master-test`, altes engl. `layouts/header`+`footer` — alle per grep verifiziert (inkl. dynamischer Auflösung).
- [x] **R4.2 Tote Komponenten entfernt** — Erledigt 03.07.: die 12 gelisteten `x-web`-Komponenten + 7 zusätzlich gefundene Chain-Dead-Komponenten (`main-navigation`, `breadcrumb`, `page-header`, `content-layout`, `article-card`, `section-header`, `sidebar-widget` — nur von examples/ bzw. anderen toten Kandidaten referenziert). Verwaiste `.highlights-slider`-CSS-Regeln mit entfernt, Web-Build gegengeprüft. Suite grün.
- [x] **R4.3 Dedup** — Erledigt 10.07. (angepasster Zuschnitt nach dem Frontend-Umbau): Die 5× kopierte Karten-Metadaten-Logik (Kategorie-Übersetzung mit Locale-Fallback, card-Bild-URL, Teaser, Lesezeit, Kompakt-Zeitstempel) in Präsentations-Helper am `PressRelease`-Model gezogen (`localizedCategoryName`, `cardImageUrl`, `teaserText`, `wordCount`, `readTimeMinutes`, `compactPublishedLabel`); feed-item, feed-top-item, focus-side-item, focus-hero, kategorie, newsroom, release-detail, veroeffentlichen + `HomePageData` umgestellt — Markup unverändert. Lesezeit-Formel vereinheitlicht (2 Stellen nutzten `ceil` statt `round`). Tests: `Web/PressReleaseCardHelpersTest`. **Bewusst gelassen:** Inline-SVGs → Icon-Set (max. 2–3 echte Dubletten in 13 Komponenten, hoher Churn im frischen User-Frontend, kein funktionaler Gewinn); Industrie-Icon-Map hatte der Umbau bereits erledigt.
---
## Phase R5 — Deploy-Readiness
- [x] **R5.1 `.env.example` vervollständigen** — Erledigt 03.07.: alle projektspezifischen Keys ergänzt und dokumentiert (Multi-Domain `APP_PORTAL_*`/`APP_PRESSEECHO_*`/`APP_BUSINESSPORTAL_*`/`APP_PROTOCOL`, `SANCTUM_STATEFUL_DOMAINS`, Legacy-DBs, Stripe/Cashier/Billing inkl. `STRIPE_PRICE_SINGLE_PM` + `BILLING_OWN_VAT_ID`, KI `OPENAI_*`/`CLASSIFICATION_*`/`CONTENT_SCORE_*`, `NEWSLETTER_SYNC_*`, `VITE_DEV_SERVER_URL`, `SESSION_SECURE_COOKIE`-Prod-Hinweis). Werte selbst (Live-Keys, Adressen) bleiben [EXTERN].
- [x] **R5.2 Deploy-Runbook schreiben** — Erledigt 03.07.: `dev/release/deploy-runbook.md` — Server-Voraussetzungen, Prod-`.env`-Solltabelle, Build-/Release-Schritte (composer, `npm run build`, storage:link, migrate --force, Stammdaten-Seeder, Caches, queue:restart), Queue-Worker (Queue `classification`, systemd-Beispiel), Cron/Scheduler (5 Tasks mit Ausfall-Folgen), Stripe-Webhook, Erst-Einrichtung (Legacy-Import-Reihenfolge), Smoke-Test-Checkliste, Rollback. Enthält den robots.txt-Deploy-Hinweis aus R2.4.
- [x] **R5.3 Monitoring/Alerting** — Umgesetzt 09.07. (Entscheidung: Mail-Alerts + Log-Rotation, ohne neues Dependency): zentraler `OperationalAlert`-Helper (immer `Log::critical`, zusätzlich Best-Effort-Mail an `MONITORING_ALERT_EMAIL`, Fallback `LEGAL_CONTACT_EMAIL`, feature-flagged via `MONITORING_ALERTS_ENABLED`); alle 6 Scheduler-Tasks mit `->onFailure()` verdrahtet, Queue-`failing`-Listener in `AppServiceProvider`; `.env.example`/Runbook: `LOG_STACK=daily` als Prod-Sollwert (Rotation 14 Tage). Tests: `OperationalAlertTest`. **Bewusst offen (nachgelagert):** echtes APM/Sentry (neues Dependency + DSN [EXTERN]) — der Log-+Mail-Weg deckt Ausfall-Erkennung fürs Release ab.
- [ ] **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** — **Vorprüfung + aktualisierte Checkliste erledigt 06.07.:** `dev/release/qa-checkliste.md` ersetzt §15 der Scope-Doku (jeder Punkt mit Beleg-Tests bzw. konkreten manuellen Schritten; Testzugänge, Reihenfolge lokal → Staging). **Befunde:** (1) /thumbnails-Redirect fehlte trotz „ANGEPASST"-Vermerk → gebaut (`LegacyMediaRedirectController` + Tests, 301 auf neue Storage-URLs für PM-Bilder/Logos). (2) Newsletter-DOI unvollständig → bewusst vertagt, kein Launch-Blocker (kein öffentliches Formular verlinkt), vor Newsletter-Aktivierung DOI-Flow bauen. **Offen:** manuelle Browser-Durchgänge (User) — Kategorieseite/Veröffentlichen-Landing erst nach Abschluss des laufenden Frontend-Umbaus abnehmen; Stripe-/Scheduler-/Mail-Punkte beim Staging-Rehearsal (R6.3).
- [x] **R6.2 Security-Review** — Audit + Härtung erledigt 03.07. **Solide befunden:** CSRF (Stripe-Webhook via Signatur, keine Ausnahmen), Magic-Link-Krypto (64-Zeichen-Token, sha256-gehasht, atomare Einmalverwendung), HTMLPurifier-Sanitizing der PM-Texte, Raw-Queries durchgängig mit Bindings, IDOR-Schutz doppelt (Scope + Policy), BasicAuth timing-sicher, Session host-only korrekt fürs Hub-and-Spoke-Setup. **Gefixt:** Security-Header-Middleware (app-seitig), Logo-Upload im Company-Create über ImageService (vorher SVG/XSS möglich), Rate-Limits für Passwort-Reset/Registrierung/Consume-Routen, `EnsureUserIsCustomer` als persistente Livewire-Middleware. Tests: `SecurityHardeningTest`. **Offen/bewusst:** CSP separat einführen (Livewire/Alpine-Inline-Strategie nötig); Token-Abilities werden auf API-Routen nicht feingranular geprüft (ein Scope für alles — ok, solange keine eingeschränkten Tokens ausgegeben werden); Draft-PM-Anhänge nur per URL-Obscurity (dokumentierter MVP-Tradeoff); HSTS am Proxy setzen; **[USER-ENTSCHEIDUNG] Legacy-SQL-Dumps (`dev/migration 2026/sql/*.sql`, Produktivdaten!) sind im Git getrackt — enttracken + ggf. History bereinigen.**
- [ ] **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` (**~180 Commits vor `main`**, Stand 09.07.) pushen und nach `main` mergen; danach Release-Tag. **Vorher:** den uncommitteten Arbeitsbaum-WIP (Kontakt-Nachrichten, Validierungs-Feedback, Page-Cache, Company-Portal-Restriction, Lang-Auslagerungen; s. Stand-Block) in fokussierte Commits zerlegen. Die drei `user_filter_presets`-Migrations zusammenführen (rev-5, „Hygiene vor Go-Live") optional davor.
- [x] **R6.6 Doku-Sync** — Erledigt 03.07.: `12-NAECHSTE-SCHRITTE.md` + `08-PROGRESS.md` tragen deutliche Verweis-Banner auf den aktiven Release-Plan (Phase 8/Stripe als erledigt markiert, Test-Stand korrigiert).
---
## 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).
- **Newsletter-Frontend (User-Entscheidung 06.07.):** `newsletter-strip` + Newsletter-Box (release-detail) aus dem Web-Frontend entfernt. Vor Reaktivierung: DOI-Flow bauen (s. R6.1), dann Komponente `components/web/newsletter-strip.blade.php` aus der Git-Historie wiederherstellen und einbinden.
- **EN-Uebersetzung der Langform-Seiten** (veroeffentlichen, faq, hilfe, api, Rechtstexte O-C): Kern-UI ist lokalisiert (lang/{de,en}/web.php), Langform-Inhalte folgen nachgelagert; bis dahin dort kein `hreflang="en"`.
- 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.