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

43 KiB
Raw Blame History

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)

  • 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.
  • 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)
  • 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.
  • 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.
  • 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)

  • 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]
  • 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

  • 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].
  • 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)
  • 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 — 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.
  • 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]

  • 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.
  • 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).
  • 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.
  • 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.)
  • 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).

  • 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).
  • 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.
  • 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

  • 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].
  • 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.
  • 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).
  • 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.
  • 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.