recht: Meldeverfahren v2 Phasen 5+7 — DSGVO-Strukturformular, 10-€-Checkout mit KI-Vorprüfung, Triage & Panel-Modal
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled

Phase 7 (Spur D, E2 revidiert): KI-Vorprüfung VOR der Zahlung im Modal —
rot lehnt ohne Zahlung ab, gelb/grün führt zum Stripe-Checkout
(SinglePurchaseType::Change, 10 € netto), nach Zahlungseingang übernimmt
der Webhook die geprüfte Fassung sofort (applyPaid: Snapshot, Sperre,
Verlauf). Nur einmal je PM; Obergrenze legal.change_max_distance_percent
(50 %) verhindert die verdeckte Selbst-Depublizierung.

Phase 5 (Spur B): strukturiertes Schwärzungsformular mit Pflicht-Vorschau
im verifizierten Web-Bereich UND als Modal im Kunden-Panel; Admin-Editor
wird aus payload.redaction vorbefüllt. Umsetzungsmail LegalRequestExecuted
an Antragsteller, Bestätigungsmail PressReleaseChangeApplied (Spur A/D,
neuer abbestellbarer Typ press_release_corrected).

Außerdem:
- Re-Sync-Sperre + Sitemap-Invalidierung fest in depublish() verankert
  (Lücke im bezahlten Webhook-Pfad geschlossen)
- Öffentliche „Rechtliches"-Seite als zweistufige Triage: primär der
  Portal-Anmeldelink, Formular nur Fallback mit Identifizierungs-Hinweis;
  Store auf report/dsgvo/personal_rights gehärtet
- Panel-Button „Ändern/Melden" öffnet Anliegen-Modal (4 Spuren) statt
  des Web-Formulars
- Pressekontakt-Fallback für Legacy-Bestände (30k PMs ohne Verknüpfung):
  Detailseite + pressContactEmail() nutzen PM-Kontakt → Firmen-Kontakt →
  Firmendaten
- Korrektur-Gate entity-fest (Editor-Normalisierung zählt nicht als
  Änderung), toEditorHtml() in Admin-Edit + Korrektur-Panel,
  Wochenlimit-Hinweis in Text und Bremsen-Meldung

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-23 13:02:57 +00:00
parent 04b49c567d
commit e6eca9c85f
40 changed files with 2507 additions and 169 deletions

View file

@ -37,9 +37,9 @@ Phase 1 Datenmodell + Re-Sync-Sperre ✅ umgesetzt 22.07.2026
Phase 2 Anonymisierungs-Engine + Admin-Ausführung ✅ umgesetzt 22.07.2026
Phase 3 Magic-Link-Verifikation + Intake-Trichter ✅ umgesetzt 22.07.2026
Phase 4 Spur A — Kleine Korrektur (self-service) ✅ umgesetzt 22.07.2026 (panel-first)
Phase 5 Spur B — DSGVO-Einreichung (self-service → Admin-Gate)
Phase 5 Spur B — DSGVO-Einreichung (self-service → Admin-Gate) ✅ umgesetzt 23.07.2026
Phase 6 Spur C — Depublizierung (Gast-Checkout + Reversibilitätsfenster)
Phase 7 Spur D — Änderung (Gast-Checkout + KI-Freigabelauf)
Phase 7 Spur D — Änderung (Checkout + KI-Vorprüfung) ✅ umgesetzt 23.07.2026
Phase 8 Querschnitt-Abschluss: Kommunikation, Auslieferungs-Checks, Doku
```
@ -49,13 +49,14 @@ Jede Phase ist eigenständig deploybar; nach Phase 2 ist der Interims-Triage-Pro
**Phasen 1–4 sind umgesetzt und getestet** (Details in den Phasen-Abschnitten). Offen:
1. **Phase 5 — Spur B strukturiert:** Das DSGVO-Anliegen im verifizierten Web-Bereich ist bisher Freitext; geplant ist das strukturierte Schwärzungsformular (Felder + Varianten) mit Pflicht-Diff aus `AnonymizationService::preview()`, das den fertigen Schwärzungsauftrag in die Admin-Queue legt (Admin-Editor vorbefüllt).
2. **Phase 6 — Spur C Gast-Checkout:** 35-€-Checkout für Magic-Link-Verifizierte (ohne Login); Reversibilitätsfenster-Hinweis („umkehrbar bis …", `legal.reversal_window_days`); **`lockSync()` auch im bestehenden Webhook-Fulfillment `fulfillDepublication()` nachrüsten** (bezahlte Panel-Depublizierung setzt die Sperre bisher nicht!).
3. **Phase 7 — Spur D Checkout:** 10 € (`billing.change_price_cents` anlegen), Gast + Panel; nach Zahlung KI-Freigabelauf auf Pending-Payload (grün/gelb → live, rot → kein Verbrauch, erneut einreichbar). Ersetzt den Interim-Weg „Change-Anfrage in die Queue".
4. **Spur A im Web-Pfad:** Korrektur-Formular (CorrectionService-Engine) auch für Magic-Link-Verifizierte statt Queue-Anfrage; Bestätigungsmail an die Kontaktadresse.
1. ~~**Phase 5 — Spur B strukturiert**~~ ✅ **umgesetzt 23.07.** (Details im Phase-5-Abschnitt).
2. **Phase 6 — Spur C:** ✅ **Re-Sync-Sperre nachgerüstet (23.07.):** `PressReleaseService::depublish()` setzt die Sperre jetzt IMMER selbst (kein Aufrufer kann sie vergessen) und invalidiert die Sitemap-Caches; der Admin-Pfad gibt seine Vorgangsnummer als Sperrgrund mit. **Gast-Checkout zurückgestellt (Entscheidung 23.07.):** Magic-Link-Login ins Panel deckt Pressekontakte ab — dort existiert die bezahlte Depublikation bereits. Noch offen aus Phase 6: Reversibilitätsfenster-Hinweis („umkehrbar bis …", `legal.reversal_window_days`) in Panel/Mails.
3. ~~**Phase 7 — Spur D Checkout**~~ ✅ **Panel-Pfad am 23.07. umgesetzt** — mit geändertem Flow (E2 revidiert, siehe Phase-7-Abschnitt): KI-Vorprüfung **vor** der Zahlung im Modal, rot → Ablehnung ohne Zahlung, je PM nur einmal möglich; Obergrenze `legal.change_max_distance_percent` (50 %). Offen: Gast-Pfad für Magic-Link-Verifizierte, Bestätigungsmail nach Ausführung.
4. ~~**Spur A im Web-Pfad**~~ ✅ **erledigt per Entscheidung 23.07.:** Kein eigener Web-Korrektur-Pfad nötig — hinterlegte Pressekontakte loggen sich per bestehendem Magic-Link-Login ins Panel ein und nutzen dort Spur A/D. Bestätigungsmail umgesetzt: `PressReleaseChangeApplied` (Typ `press_release_corrected`, abbestellbar) nach Spur-A-Korrektur (sofort) und Spur-D-Änderung (nach Webhook-Ausführung).
5. **Phase 8 — Querschnitt:** connektar-Template-Stopp in allen Texten prüfen, `noindex` im Tombstone verifizieren, zweistufige Eskalations-Mailtexte (Ablehnung mit Aufsichtsbehörden-Hinweis), Doku-Abgleich.
6. **Ops:** Dev-DB-Migration (`sync_locked_at`-ALTER auf `press_releases`, FULLTEXT-bedingt langsamer Tabellen-Copy) lief am Abend des 22.07. noch; danach `php artisan migrate` für die restlichen Migrationen (`magic_links`-Enum) ausführen. Test-DB ist vollständig migriert, alle 41 Legal-Tests grün.
7. **Konfig-Feinjustierung (22.07. abends):** `correction_max_distance_percent` auf **5 %** und `corrections_per_week` auf **1** verschärft (statt 15 %/2 aus E5). Dazu im Service die **Mini-Edit-Ausnahme**: Änderungen ≤ 2 Zeichen gelten immer als klein — sonst würde bei kurzen Titeln ein einzelner Tippfehler die Prozent-Grenze reißen.
6. ~~**Ops:** Dev-DB-Migration~~ ✅ **erledigt 23.07.:** Das ALTER war serverseitig fertig (Migration manuell nachregistriert), alle restlichen Migrationen gelaufen — der komplette Flow ist auf pressekonto.test browser-testbar.
7. ✅ **Öffentliche Triage-Seite (23.07.):** `/release/{slug}/rechtliches` ist jetzt zweistufig — Stufe 1 wählt das Anliegen (Absender-Selbstservice / DSGVO / Persönlichkeitsrechte / Meldung), Stufe 2 leitet Absender-Anliegen und DSGVO/Persönlichkeitsrechte primär auf den Magic-Link-Weg (Deep-Link zum `/melden/pm`-Trichter mit vorbefüllter PM-URL); das Kontaktformular ist dort nur der Fallback mit Pflicht-Hinweis auf die persönliche Identifizierung. Meldungen rechtswidriger Inhalte gehen direkt ins Formular (DSA). Der Store-Endpoint akzeptiert nur noch `report`/`dsgvo`/`personal_rights` — Absender-Spuren können nicht mehr als anonyme Queue-Anfrage einlaufen.
8. **Konfig-Feinjustierung (22.07. abends):** `correction_max_distance_percent` auf **5 %** und `corrections_per_week` auf **1** verschärft (statt 15 %/2 aus E5). Dazu im Service die **Mini-Edit-Ausnahme**: Änderungen ≤ 2 Zeichen gelten immer als klein — sonst würde bei kurzen Titeln ein einzelner Tippfehler die Prozent-Grenze reißen.
---
@ -161,14 +162,15 @@ Link geht an hinterlegte, nie an Formular-Adresse (maskiert); unbekannte URL abg
- ✅ Tests (11 neue, alle grün): Tippfehler klein / Umschreibung groß / Markup-only = keine Änderung, Sofort-Live mit Snapshot+Sperre+Verlauf, Zu-groß-Abwehr, Wochen-Bremse, Restore (Service + Admin-UI), kein Credit-Bezug, Panel-Happy-Paths, Vorschau-Pflicht.
- ℹ️ **Noch offen aus Phase 4:** dieselben Formulare im verifizierten Web-Bereich (Magic-Link-Besucher) — aktuell erzeugt Spur A dort noch eine Queue-Anfrage; die `CorrectionService`-Engine ist dafür wiederverwendbar. Nutzer-Bestätigungsmail nach Korrektur bewusst weggelassen (Owner sieht das Ergebnis sofort im Panel), für den Web-Pfad nachrüsten.
## Phase 5 — Spur B: DSGVO-Einreichung self-service → Admin-Gate
## Phase 5 — Spur B: DSGVO-Einreichung self-service → Admin-Gate ✅ **umgesetzt (23.07.2026)**
- Formular: Strukturfelder zum Leeren angeboten + Freitext-Schwärzwerte inkl. Varianten → Pflicht-Diff (Preview aus `AnonymizationService::preview()`) → **Einreichung** (nicht Ausführung): `LegalRequest` `type=dsgvo`, payload = Schwärzungsauftrag, Status `open`.
- Admin-Queue zeigt den vorbereiteten Diff (Phase-2-Editor, vorbefüllt) → Admin bestätigt **anonymisieren** oder wählt **depublizieren** → `AnonymizationService::execute()` bzw. `depublish()` + Snapshot.
- Bestätigungsmail an Antragsteller bei Einreichung (Fristbeginn dokumentiert, Vorgangsnummer `M-{id}`) und bei Ausführung.
- **Wording:** In der UI „Schwärzung/Entfernung personenbezogener Daten", nicht „Anonymisierung im DSGVO-Vollsinn" (Guardrail — nicht überversprechen).
- Bremse: 1 offene Anfrage pro PM/Typ (Logik existiert konzeptionell in `LegalRequestStatus::isOpen()` — beim Store durchsetzen).
- Tests: Einreichung erzeugt keinen Datenbank-Write an der PM; Ausführung nur durch Admin; nie Credits.
- ✅ **Strukturformular** im verifizierten Web-Bereich (`melden-pm-anliegen`, Alpine-Toggle bei Spur-Auswahl „DSGVO"): Schwärzbegriffe zeilenweise (Hinweis auf Varianten/Genitiv), Checkboxen „Pressekontakt-Daten entfernen" und „Bilder mit Personenbezug entfernen" (Bildauswahl trifft der Admin), Freitext-Begründung bleibt Pflicht.
- ✅ **Pflicht-Diff:** Erster POST rendert die Vorschau aus `AnonymizationService::preview()` (Treffer je Feld, geschwärzte Fassung als Klartext) — erst „Verbindlich einreichen" erzeugt die Anfrage. Begriffe ohne Treffer werden mit Schreibweisen-Hinweis abgewiesen; leeres Formular (keine Begriffe, keine Option) ebenso.
- ✅ **Einreichung ≠ Ausführung:** `LegalRequest` `type=dsgvo`, Status `open`, `payload.redaction` = {terms, detach_contacts, remove_images_requested, preview_total_hits}; an der PM ändert sich nichts, keine Credits. Bremse 1 offene Anfrage pro PM/Typ greift weiter.
- ✅ **Admin-Editor vorbefüllt:** `admin.legal-requests.show` übernimmt Begriffe + Kontakt-Option aus `payload.redaction` und zeigt einen Hinweis-Kasten (inkl. Bild-Entfernungswunsch). Admin prüft, ergänzt, führt aus oder depubliziert.
- ✅ **Mails:** Eingangsbestätigung existierte (Phase 3); neu die **Umsetzungsbestätigung** `LegalRequestExecuted` (transaktional, nicht abbestellbar) an die Antragsteller-Adresse nach `executeAnonymization` („anonymized") und `depublishRelease` („depublished").
- ✅ **Wording-Guardrail** eingehalten: überall „Schwärzung/Entfernung", inkl. Hinweis auf Suchmaschinen-/Drittarchiv-Kopien.
- ✅ Tests: Pflicht-Vorschau ohne DB-Write, Treffer-Validierung, bestätigte Einreichung mit strukturiertem Payload, Admin-Prefill, Umsetzungs-Mail.
## Phase 6 — Spur C: Depublizierung (35 €, Gast-Checkout, umkehrbar)
@ -179,15 +181,20 @@ Link geht an hinterlegte, nie an Formular-Adresse (maskiert); unbekannte URL abg
- Preis: 35 € live via `config('billing.depublication_price_cents')` (existiert). Die systemische 25-Credit-Variante für eingeloggte Kunden bleibt unberührt — aber Test sichert ab, dass der **DSGVO-Pfad (Spur B) nie** in diesen Checkout mündet.
- Tests: Gast-Checkout-Fulfillment, Reversibilitätsfenster, Tombstone + Sitemap-Ausschluss.
## Phase 7 — Spur D: Änderung (10 €, KI-Freigabelauf)
## Phase 7 — Spur D: Änderung (10 €, KI-Vorprüfung) ✅ **Panel-Pfad umgesetzt (23.07.2026)**
- Preis: **10 €** (E1), neuer Config-Wert `billing.change_price_cents` = 1000.
- Formular: neuen Text/Feldwerte eingeben (Voll-Editor light, analog `customer/press-releases/edit`-Formularregeln aus `ProvidesPressReleaseFormRules`) → Preis anzeigen → Gast-Checkout (`SinglePurchaseType`-Case `Change`, `adHocLineItem`-Muster).
- Nach Zahlung: Änderung in **Entwurfs-Kopie/Pending-Payload** halten (nicht direkt live), dann `ClassifyPressRelease` auf den neuen Inhalt:
- **grün/gelb** → Änderung anwenden, PM bleibt/wird published, `lockSync()`, Kauf auf `Consumed`, Mail „live".
- **rot** → abgelehnt, Änderung verworfen, **kein Verbrauch** (E2): Kauf bleibt un-konsumiert, Antragsteller kann mit überarbeitetem Text erneut einreichen ohne erneut zu zahlen; Mail mit Ablehnungsgrund.
- KiAudit-Trail entsteht automatisch über den bestehenden Job.
- Tests: rot verwirft ohne PM-Änderung; grün wendet an; Webhook-Idempotenz.
**Flow-Entscheidung 23.07. (revidiert E2):** Die KI-Prüfung läuft **VOR der Zahlung** als einmaliger Zwischenschritt im Modal — nicht mehr nach Zahlung auf einem Pending-Payload. Rot → Einreichung wird direkt abgelehnt, es kommt gar nicht erst zur Zahlung (damit entfällt der „kein Verbrauch"-Fall aus E2). Gelb/Grün → Checkbox (§ 14 BGB/AGB, wie Depublikation) + direkter Stripe-Checkout; nach Zahlungseingang geht die Änderung **sofort live**. Der Vorgang ist **je PM nur einmal möglich** (auch nach Ablehnung kein zweiter Anlauf).
- ✅ **Obergrenze:** `legal.change_max_distance_percent` = **50 %** (env `LEGAL_CHANGE_MAX_DISTANCE_PERCENT`) — darüber ist auch die kostenpflichtige Änderung nicht buchbar (sonst verdeckte Selbst-Depublizierung); UI verweist auf Depublikation + Neuveröffentlichung. `CorrectionService::classify()` liefert dafür `exceeds_paid_limit`.
- ✅ **Preis:** `billing.change_price_cents` = 1000 (E1); 0/leer deaktiviert den Weg (wie Depublikation).
- ✅ **Vorprüfung:** `CorrectionService::precheckProposedContent()` klassifiziert eine NICHT gespeicherte PM-Kopie mit den neuen Werten über den `ClassificationManager` (KI-Provider, Fallback deterministisch/Blacklist). Ergebnis + Provider landen in `payload.ki_check` der Change-`LegalRequest` (rot → Status `Rejected`, sonst `Open`).
- ✅ **Checkout:** `CheckoutController::change()` (Route `me.checkout.change`, `checkout/aenderung/{id}`) verlangt die offene Change-Anfrage mit gelb/grünem `ki_check` als Nachweis; `SinglePurchaseType::Change` (`press_release_change`, Enum-Migration), Pending-Wiederverwendung wie Depublikation; Anfrage wird über `single_purchase_id` verknüpft. `StripeCheckoutService::forChange()` (adHoc-Muster).
- ✅ **Fulfillment:** `ProcessStripeWebhook::fulfillChange()` → `CorrectionService::applyPaid()`: Snapshot, Felder schreiben (Text durch Sanitizer), `lockSync()`, Verlauf, Re-Score; Anfrage `Resolved`/`executed_at`, Kauf `Consumed`. Reißt die Obergrenze doch (Payload-Manipulation), bleibt der Kauf unkonsumiert zur Admin-Klärung.
- ✅ **Panel-UI:** Modal `paid-change` mit Zwischenerklärung (einmalige Prüfung, rot/gelb-grün-Folgen), Loading-State, Ablehnungsansicht mit Gründen, Bestätigungs-Switch (`BookingConfirmation` Typ `press_release_change`) + Stripe-Button. Abgebrochene Zahlung: Modal springt direkt wieder zum Zahlungs-Schritt der bereits geprüften Fassung.
- ✅ **Tests:** Panel (grün → Zahlungs-Schritt, rot → Ablehnung + Einmal-Regel, Obergrenze), Service (`applyPaid`, `precheck`, `exceeds_paid_limit`), Checkout (Nachweis-Pflicht, Pending-Reuse, rot blockiert), Webhook (Ausführung + Replay-Idempotenz).
- ✅ **Bestätigungsmail:** `PressReleaseChangeApplied` an den Auftraggeber nach Spur-A-Korrektur und Spur-D-Ausführung (neuer `EmailNotificationType::PressReleaseCorrected`, abbestellbar, erscheint automatisch in den Mail-Präferenzen).
- **Entscheidung 23.07.:** Kein separater Gast-Pfad — hinterlegte Pressekontakte nutzen den bestehenden Magic-Link-Login ins Panel und bearbeiten dort. Der `/melden/pm`-Trichter bleibt für Dritte/DSGVO/Depublikations-Anliegen.
- **Kleinigkeit offen:** KiAudit-Eintrag für die Vorprüfung (Ergebnis liegt bisher nur in `payload.ki_check` der Anfrage).
## Phase 8 — Querschnitt-Abschluss
@ -204,7 +211,7 @@ Link geht an hinterlegte, nie an Formular-Adresse (maskiert); unbekannte URL abg
| # | Entscheidung | Umsetzung im Plan |
|---|---|---|
| **E1** | Zwei getrennte Preise: **35 €** = komplette Depublizierung einer PM (Spur C), **10 €** = Änderung einer PM (Spur D) | Spur C: `billing.depublication_price_cents` (existiert); Spur D: neuer Config-Wert `billing.change_price_cents` = 1000 → Phase 7 |
| **E2** | Bei KI-„rot" **kein Verbrauch** — es wird nichts abgezogen | Kauf bleibt un-konsumiert (Status nicht `Consumed`); der Antragsteller kann mit überarbeitetem Text erneut in den Freigabelauf, ohne erneut zu zahlen → Phase 7 |
| **E2** | ~~Bei KI-„rot" kein Verbrauch~~ **Revidiert 23.07.:** KI-Prüfung läuft **vor** der Zahlung (einmaliger Zwischenschritt im Modal). Rot → Ablehnung ohne Zahlung; Gelb/Grün → Zahlung, danach sofort live. Je PM **nur einmal möglich**. | Umgesetzt in Phase 7 (`precheckProposedContent`, Modal `paid-change`); der „kein Verbrauch"-Fall entfällt, weil vor Zahlung geprüft wird |
| **E3** | Reversibilitätsfenster als **Config-Variable, Standard 14 Tage** | `legal.reversal_window_days` = 14 → Phase 6 |
| **E4** | Snapshot-Löschfrist als **Config-Variable, Standard 30 Tage** | `legal.snapshot_retention_days` = 30; bestimmt `purge_after` → Phasen 1.1 / 2.3 |
| **E5** | Levenshtein-Schwellwert Spur A als Config-Variable; Start 15 %, am 22.07. abends auf **5 %** verschärft (+ Mini-Edit-Ausnahme ≤ 2 Zeichen) | `legal.correction_max_distance_percent` = 5, `legal.corrections_per_week` = 1 → Phase 4 |
@ -236,3 +243,11 @@ Link geht an hinterlegte, nie an Formular-Adresse (maskiert); unbekannte URL abg
| 22.07.2026 (rev. 5) | Admin-Schwärzungs-Editor: kompletter PM-Inhalt als kopierbare Vorschau (vorher/nachher in einem Block), Ersetzungswert vorbefüllt. **Phase 3 umgesetzt:** Intake `melden/pm` (Kosten-Tabelle vorab, Honeypot, IP+PM-Rate-Limits), `createReportLink` + Enum-Migration `press_release_report`, Mailable, atomare Verifikation mit Session-Marker, Anliegen-Auswahl erzeugt verifizierte Queue-Anfragen (Bremse 1 offene Anfrage/PM/Typ), toter-Kanal-Fallback auf manuelles Formular, Owner-Einstieg aus dem Kunden-Panel, Lang-Keys de/en, 10 neue Pest-Tests grün |
| 22.07.2026 (rev. 6) | **Phase 4 umgesetzt (panel-first, Entscheidung: sofort live + rückgängig machbar):** `CorrectionService` mit Hybrid-Levenshtein-Gate (Zeichen kurz / Wörter lang, strip_tags-Basis), Panel-Abschnitt „Änderung & Korrektur" über der Depublikation (ein Einstieg, System stuft klein/groß ein; groß = Interim-Queue-Anfrage bis Phase-7-Checkout), Wochen-Bremse per Config, Snapshot-Restore im Admin (Korrektur + Anonymisierung), `ActivityType::Correction`, `WebCaches::forgetSitemaps()` extrahiert, 11 neue Pest-Tests grün |
| 22.07.2026 (rev. 7) | Konfig verschärft (5 % / 1 Korrektur pro Woche) + Mini-Edit-Ausnahme ≤ 2 Zeichen im Gate; Abschnitt „Stand & was noch fehlt" für den Wiedereinstieg ergänzt; Tagescommit |
| 23.07.2026 (rev. 8) | Phase 7 Panel-Pfad umgesetzt mit revidiertem E2 (KI-Vorprüfung VOR Zahlung, rot → Ablehnung ohne Zahlung, nur einmal je PM; Obergrenze 50 %). Außerdem: Vergleichsbasis entity-fest (Editor-Normalisierung ≠ Änderung), `toEditorHtml()` in Admin-Edit + Korrektur-Panel (Legacy-Plaintext-Umbrüche), Wochenlimit-Hinweis in Panel-Text und Bremsen-Meldung, Dev-DB vollständig migriert |
| 23.07.2026 (rev. 9) | Entscheidung: kein separater Web-Korrektur-Pfad — Magic-Link-Login ins Panel deckt Pressekontakte ab. Bestätigungsmail `PressReleaseChangeApplied` (Spur A sofort, Spur D nach Webhook) mit neuem abbestellbarem Typ `press_release_corrected`; Phase 7 damit vollständig |
| 23.07.2026 (rev. 10) | Phase 5 umgesetzt: strukturiertes DSGVO-Schwärzungsformular mit Pflicht-Diff im verifizierten Web-Bereich, Admin-Editor-Prefill aus `payload.redaction`, Umsetzungsbestätigung `LegalRequestExecuted` an Antragsteller |
| 23.07.2026 (rev. 11) | Gast-Checkout zurückgestellt (Magic-Link-Login deckt Pressekontakte ab). Re-Sync-Sperre + Sitemap-Invalidierung fest in `depublish()` verankert — schließt die Lücke im bezahlten Webhook-Pfad; Vollsuite 1418 Tests grün |
| 23.07.2026 (rev. 12) | Öffentliche „Rechtliches"-Seite an der PM zur zweistufigen Triage umgebaut: Anliegen-Karten, Magic-Link-Deep-Link mit vorbefüllter URL, Formular nur als Fallback (mit Identifizierungs-Hinweis bei DSGVO/Persönlichkeitsrechten), Meldung direkt; Store-Endpoint auf die drei öffentlichen Typen gehärtet |
| 23.07.2026 (rev. 13) | Pressekontakt-Lücke der Legacy-Bestände geschlossen: 30.422 von 30.433 veröffentlichten PMs haben keine PM↔Kontakt-Verknüpfung (im Altsystem hingen Kontakte an der FIRMA). Detailseite zeigt jetzt Fallback Firmen-Kontakt → Firmendaten; `pressContactEmail()` (Magic-Link-Kanal) nutzt dieselbe Kette PM-Kontakt → Firmen-Kontakt → Firmen-E-Mail |
| 23.07.2026 (rev. 14) | Entscheidung: Die Triage-Buttons führen NICHT in den Web-Melde-Trichter (`/melden/pm`), sondern zum passwortlosen **Portal-Anmeldelink** (`pressekonto /anmeldelink`) — dort werden die PMs der Kontaktadresse im Konto zusammengeführt und alle Selbstservice-Funktionen stehen bereit. Der Web-Trichter bleibt als eigenständiger Weg bestehen (u. a. verifizierte DSGVO-Struktureinreichung) |
| 23.07.2026 (rev. 15) | Panel: „Ändern/Melden"-Button leitet nicht mehr in den Web-Trichter, sondern öffnet ein Anliegen-Modal (4 Spuren). Korrektur/Änderung und Depublizierung springen zu den Panel-Abschnitten; DSGVO hat jetzt das strukturierte Schwärzungsformular (Pflicht-Vorschau, Einreichung ≠ Ausführung, Payload wie Web-Formular → Admin-Editor-Prefill) direkt als Modal im Panel |