press-releases: Mail "wird persoenlich geprueft" beim Block, Blade-Guard fuer @php-Bloecke (Roadmap 1d, Nachtrag)

Der Autor bekommt beim Block nach dem letzten Rot (oder Gelb mit
eingeschalteter Queue) eine kurze Mail statt Stillstand: was passiert ist,
dass nichts zu tun ist, und dass das Ergebnis per Mail kommt. Laeuft ueber
notifyAuthor() wie Veroeffentlichung und Ablehnung (API-Regel, Sperrliste,
adressbezogene Abmeldung, Bounce-Referenz); Opt-out am Typ "abgelehnt".
Neue ConversionSource mail_review fuer den Link ins Konto.

BladePhpBlockGuardTest wendet das Compiler-Muster auf alle Views an und
faengt inline @php( vor einem spaeteren @endphp ab — fand den eigenen
Erklaer-Kommentar im Modal, der nur zufaellig funktionierte. Regel in
CLAUDE.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-16 15:05:47 +00:00
parent 9380937562
commit 4dffb1368f
11 changed files with 278 additions and 24 deletions

View file

@ -147,7 +147,7 @@ Für selbst angelegte Firmendaten trägt der Nutzer die Verantwortung. Für die
| ~~1d.1~~ | Hilfeseite ohne kommerziellen Anteil — **gebaut 16.09.2026**: `/{edition}/gute-pressemitteilung` (DE/EN), Anlass, Aufbau, Sprache, Prüfablauf, sieben Qualitätsdimensionen offen, Pressebilder; Sitemap + Hilfe-Center | S | keine |
| ~~1d.2~~ | Textbaustein in die Ablehnungsmail — **16.09.2026**: Link auf dem Portal der Meldung, Herkunft `mail_reject`, nichts Kommerzielles (E6) | S | 1d.1 |
| ~~1d.3~~ | Abmeldemöglichkeit für Benachrichtigungen — **16.09.2026**: für Empfänger ohne Konto (Pressekontakt, Firmen-E-Mail) adressbezogener Abmeldelink, Zustand als `Unsubscribed` in der Sperrliste; selbst angeforderte Anmeldelinks gehen weiter durch. Vorher zeigte der Link in API-Benachrichtigungen auf das Konto des Einlieferers | S | Bounce-Suppression live |
| ~~1d.4~~ | Prüfwerkzeug — **E3 entschieden 16.09.2026: kein eigenständiges Werkzeug.** Prüfung nur beim Freigeben, Ergebnis am Entwurf; „Zur Prüfung freigeben" mit Erklärung, was danach passiert; automatische Prüfung je Meldung `max_automatic_attempts` (3), danach geblockt in die Admin-Queue („Prüfung nötig"), Freischalten oder Kommentar, Automatik für die Meldung ab dann aus | M | 1d.1 |
| ~~1d.4~~ | Prüfwerkzeug — **E3 entschieden 16.09.2026: kein eigenständiges Werkzeug.** Prüfung nur beim Freigeben, Ergebnis am Entwurf; „Zur Prüfung freigeben" mit Erklärung, was danach passiert; automatische Prüfung je Meldung `max_automatic_attempts` (3), danach geblockt in die Admin-Queue („Prüfung nötig"), Freischalten oder Kommentar, Automatik für die Meldung ab dann aus; Autor erhält beim Block die Mail „wird persönlich geprüft" (Nachtrag 16.09.) | M | 1d.1 |
| ~~1d.5~~ | Bewertung einer bestehenden Meldung über Magic Link — **mit 1c.2 erledigt**: der Beansprucher sieht Ablehnungsgrund, KI-Stufe und Content-Score auf der Meldungsseite | S | 1d.4, 1b.2 |
| ~~1d.6~~ | Partnerbereich am Seitenende als BALD — **16.09.2026** am Ende von 1d.1 | S | 1d.1 |

View file

@ -1384,9 +1384,9 @@ dem Portal der Meldung mit `src=mail_reject&pr=<id>`.
Status-Log „wartet auf manuelle Entscheidung". Content-Score läuft weiter.
- `routeByClassification()`: Rot beim N-ten Lauf → `holdForManualReview()`
statt Ablehnung (bleibt `review`, Log „Automatische Prüfung erschöpft
(N von N): <Grund>", ActivityLog). Gelb → Schalter. Keine Mail an den
Autor für den Block — er sieht den Stand im Konto (offen: ob eine kurze
Mail „ein Mensch prüft" gewünscht ist).
(N von N): <Grund>", ActivityLog). Gelb → Schalter. Der Autor bekommt
beim Block die Mail „Ihre Pressemitteilung wird persönlich geprüft"
(Nachtrag unten).
- Admin ▸ Pressemitteilungen: Ansicht „Prüfung nötig" (Zähler rot, wenn >
0), Filteroption, Badges „Prüfung nötig" / „nur manuell" in der Liste;
Detailseite zeigt alle KI-Begründungen chronologisch und beschriftet die
@ -1398,7 +1398,8 @@ dem Portal der Meldung mit `src=mail_reject&pr=<id>`.
mit Link auf 1d.1; geblockte Meldung: „wird von einem Menschen geprüft".
- Nebenbefund Blade: ein inline `@php(...)` wird bis zum nächsten
`@php … @endphp` als Rohblock gelesen — vier Stellen auf Blockform
umgestellt, eine davon Bestand (Modal).
umgestellt, eine davon Bestand (Modal). Seit dem Nachtrag unten durch
einen Test abgesichert.
Tests: `ManualReviewGateTest` (5), `StaticPagesTest` (+2),
`ConversionFunnelTest` (erweitert). 1d.5 ist mit 1c.2 erledigt (der
@ -1431,6 +1432,42 @@ fordert die Person selbst an. Harte Bounces sperren weiterhin alles.
Tests: `AddressUnsubscribeTest` (5). Admin ▸ Mail-Sperrliste zeigt den
Grund „abgemeldet" ohne weitere Änderung.
**Damit ist Block 1d komplett.** Offen aus dem Block: ob der Autor beim
Block nach dem N-ten Rot eine kurze Mail bekommen soll („ein Mensch
prüft"); heute sieht er es nur im Konto.
## Nachtrag 1d (16.09.2026) — Mail beim Block, Blade-Guard
Beide offenen Punkte aus dem Block auf Wunsch des Nutzers umgesetzt.
**Mail „ein Mensch prüft jetzt".** Neue Mailable
`PressReleaseHeldForReview`, ausgelöst aus `holdForManualReview()` über
denselben `notifyAuthor()`-Pfad wie Veröffentlichung und Ablehnung — also
mit der API-Regel (Pressekontakt → Firmen-E-Mail → sonst gar nicht, nie an
connektar), Sperrliste, adressbezogener Abmeldung (1d.3) und
Bounce-Referenz. Zwei Textvarianten: Automatik erschöpft („auch im N.
Durchlauf nicht freigeben … statt einer weiteren Ablehnung sieht sich jetzt
ein Mensch die Mitteilung an") und Gelb-Queue („zur Sicherheit
zurückgehalten"). Kern der Mail: *Sie müssen nichts tun*, die Meldung ist
nicht öffentlich, das Ergebnis kommt als Veröffentlichungs- oder
Ablehnungsmail. Ein Button „Stand der Prüfung ansehen" führt ins Konto
(`src=mail_review`, neue `ConversionSource::MailReview`, damit der Klick im
Funnel unterscheidbar bleibt). Kein Ablehnungsgrund in der Mail — die
KI-Begründungen stehen im Konto, und die Mail soll beruhigen, nicht
nachtreten.
Opt-out: kein neuer Präferenz-Typ. Der Zwischenstand hängt am Typ
„abgelehnt" — wer keine Prüfergebnisse will, will auch den nicht. Die drei
Texte des Typs (Einstellung, Footer-Begründung, Abmelde-Label) sprechen
jetzt von „Prüfergebnis" statt nur „Ablehnung".
**Blade-Guard.** `BladePhpBlockGuardTest` läuft über alle Views und wendet
exakt das Compiler-Muster an (`/(?<!@)@php(.*?)@endphp/s`,
`BladeCompiler::storePhpBlocks`): Jeder Treffer, dessen Inhalt mit `(`
beginnt, ist ein inline `@php(`, das einen späteren Block verschluckt. Der
Test fand sofort eine Stelle: den eigenen Erklär-Kommentar im Modal, der
`@php(` und `@endphp` wörtlich enthielt. Blade liest die Rohblöcke *vor*
den Kommentaren — die Stelle funktionierte nur, weil der Kommentar den
Platzhalter anschließend mit entfernte. Kommentar umformuliert; Regel in
CLAUDE.md festgehalten.
Tests: `ManualReviewGateTest` (+1 → 6, Mail beim Block, Textvarianten,
Opt-out), `BladePhpBlockGuardTest` (1).
**Damit ist Block 1d komplett, ohne offene Punkte.**