Doku: Status-Sync 11./12.06., Decision-Update Preisstruktur und Phase-9-Plan

- Decision-Update Preisstruktur & Veroeffentlichungs-Flow aufgenommen
  (Launch-Tarife, Slot-Verbrauch bei Veroeffentlichung, Submit-Gate,
  Launch-Credits) inkl. Klarstellung 12.06.: Gelb geht direkt live,
  keine manuelle Pruef-Queue, nur Rot wird abgelehnt
- Alle Status-Dokumente auf den Code-Stand gezogen: README-Index,
  STATUS-ABGLEICH (KI-Pipeline, Bilder/Lizenzen, Pricing), Checkliste
  (KI- und Titelbild-Bloecke, Launch-To-dos), Admin-User,
  user-zusammenhaenge (Datenmodell-Delta), Entwicklungsplan KI-Pruefung
  (Phase 0 abgehakt, Decision-Abgleich)
- Ueberschriebene Tarif-Abschnitte in Konzept-Update 1/2 und
  Relaunch-Konzept mit Superseded-/IST-Hinweisen markiert
- Neues Plan-Dokument PHASE-9-FLOW-UND-TARIFE-PLAN.md (9A-9J)
- Phase-8-Roadmap-Doku (20-PHASE-8-USER-PANEL.md) + PROGRESS-Eintraege

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-06-12 09:20:22 +00:00
parent a000238ca8
commit 8d8d957884
17 changed files with 2231 additions and 172 deletions

View file

@ -0,0 +1,103 @@
# Phase 8 · User-Panel-Konsolidierung & PM-Lifecycle
Stand: 2026-05-29 · **abgeschlossen**
Plan-Doc: [`docs/PHASE-8-USER-PANEL-PLAN.md`](../../../docs/PHASE-8-USER-PANEL-PLAN.md)
Abgleich: [`docs/STATUS-ABGLEICH-USER-PANEL.md`](../../../docs/STATUS-ABGLEICH-USER-PANEL.md)
Folge-Initiative nach Phase 7 (PM-Form-Refactor). Ziel: das User-Panel
produktionsreif abrunden — Show-Page-Lücken, Firmen-Liste auf
Mockup-Niveau, durchgängige PM-Titelbilder, rechtssichere Bild-Lizenzen
und ein bewusster Veröffentlichungs-Flow mit Kontingent-Vorbereitung.
## Päckchen-Übersicht
| ID | Thema | Status |
|---|---|---|
| 8A | Show-Page-Lücken (subtitle, scheduling, embargo, boilerplate_override) — Customer + Admin | ✅ |
| 8B | Listen-Indikatoren für Scheduling/Embargo | ✅ |
| 8C | Pressekontakt-Warn-Box in der Form-Sidebar | ✅ |
| 8D | Doku-Sync (`docs/user-admin/*`, `STATUS-ABGLEICH`) | ✅ |
| 8E | Firmen-Liste auf Mockup-Niveau (Counter-Strip, Saved-Views, Filter-Chips, Toggle, Rollen-Legende) | ✅ |
| 8F | SVG-Titelbild-Platzhalter-Set + Anzeige-Komponente + Picker-Modal | ✅ |
| 8G | Titelbild-Schema (`placeholder_variant`) + Cover-Resolver | ✅ |
| 8H | Bild-Upload mit Lizenz-Pflichtfeldern | ✅ |
| 8I | Veröffentlichungs-Modal (Rechtshinweis + Kontingent) | ✅ |
| 8J | Quota-Stub im Datenmodell + monatlicher Reset-Command | ✅ |
| 8K | Tests, Pint, Build, Doku-Abschluss | ✅ |
## Wichtigste Code-Artefakte (8F8J, neu in dieser Phase)
**Enums**
- `app/Enums/PressReleasePlaceholder.php` — 9 SVG-Varianten (Default,
Seed-deterministisch, Labels, Asset-Pfad).
- `app/Enums/ImageLicenseType.php` — 5 Lizenztypen, `requiresLicenseUrl()`.
**Assets / Komponenten**
- `public/images/press-release-placeholders/01..09-*.svg` (1600×900,
3 Muster × 3 Hub-Farben).
- `resources/views/components/portal/press-release-placeholder.blade.php`
rendert Bild/Platzhalter mit optionalem Titel-Overlay.
- `resources/views/livewire/components/press-release-placeholder-picker.blade.php`
FluxUI-Modal mit 3×3-Grid, dispatcht `placeholder-selected`.
**Services**
- `app/Services/PressRelease/PressReleaseCoverImage.php``coverUrl()`,
`coverIsPlaceholder()`, `placeholder()`. Bevorzugt `is_preview`-Bild,
fällt sonst auf den SVG-Platzhalter zurück.
**Schema (additive, nullable/Default-Migrationen)**
- `press_releases.placeholder_variant` (string 32, nullable).
- `press_release_images`: `author`, `license_type`, `license_url`,
`persons_consent` (default false), `rights_confirmed_at`.
- `users`: `press_release_quota` (default 3),
`press_release_quota_used_this_month` (default 0).
**Models**
- `PressRelease`: Cast + `creating`-Hook setzt deterministisch eine
Platzhalter-Variante, wenn keine gesetzt ist.
- `PressReleaseImage`: Lizenz-Felder + `license_type`-Enum-Cast.
- `User`: `pressReleaseQuotaRemaining()`.
**Service-Hook & Command**
- `PressReleaseService::submitForReview()` zählt
`press_release_quota_used_this_month` des Autors hoch (Stub).
- `app/Console/Commands/ResetMonthlyPressReleaseQuota.php` +
Scheduler-Eintrag (`monthlyOn(1, '00:05')`) in `routes/console.php`.
**Views**
- Customer-Show + Admin-Show: Hero-Titelbild via Cover-Resolver.
- Customer Create/Edit: Platzhalter-Vorschau + Picker-Einbindung
(`#[On('placeholder-selected')]`).
- Customer-Show: Veröffentlichungs-Modal (`confirm-submit-review`) mit
Rechts-Platzhalter, Kontingent-Badge und 3 Bestätigungs-Checkboxen
(Submit-Button via Alpine disabled bis alle gesetzt).
- Image-Manager: Lizenz-Felder + Anzeige in der Bild-Kachel.
## Tests (neu)
- `tests/Feature/PressReleasePlaceholderTest.php` (8) — Enum, Assets,
Picker, Cover-Resolver (Platzhalter + echtes Bild).
- `tests/Feature/PressReleaseImageLicenseTest.php` (3) — Pflichtfelder,
CC-ohne-URL, vollständiger Upload + `rights_confirmed_at`.
- `tests/Feature/PressReleaseQuotaTest.php` (3) — Remaining-Berechnung,
Increment bei Submit, monatlicher Reset.
- `tests/Feature/PressReleasePublishModalPhase8iTest.php` (2) — Modal-Inhalt
(Rechtshinweis + Kontingent), Submit-Flow.
Gesamt-Suite nach Phase 8: **375 passed, 4 skipped**. Pint clean,
`npm run build:portal` clean.
## Bewusste Abweichungen / offene Folge-Themen
- **8H — Upload-Control**: `flux:input type=file` statt `flux:file-upload`
(Pro-Dropzone mit aufwändigem Slot-Aufbau). Funktion identisch, kein
Risiko für den Upload-Flow. Dropzone-Optik ggf. separat nachziehen.
- **8I — Rechtstext** ist ein **Platzhalter** und vor Go-Live anwaltlich
zu prüfen.
- **8J — Quota** ist ein Stub. Die Schnittstelle
`User::pressReleaseQuotaRemaining()` bleibt stabil; das echte
Tarif-/Credit-Modul löst Spalten + Decrement-Logik später ab.
- Offen (Phase 2/3): Stock-/KI-Bildquellen, Wasserzeichen-Check,
Magic-Link-Flow für Pressekontakte, Statistik-/Abrechnungs-Tabs,
Anhänge-Reaktivierung (Security-Audit).

View file

@ -5,6 +5,67 @@
---
## 2026-05-29 · Phase 8 · User-Panel-Konsolidierung abgeschlossen (8F8K) ✅
Abschluss von Phase 8. Die erste Hälfte (8A8E: Show-Page-Lücken,
Listen-Indikatoren, Pressekontakt-Warnung, Firmen-Liste auf Mockup-Niveau)
war bereits im Commit „Optimierung der User und Admin Panels" enthalten,
aber undokumentiert. Heute der zweite Block plus Doku-Sync.
Roadmap-Doc: `20-PHASE-8-USER-PANEL.md`. Plan: `docs/PHASE-8-USER-PANEL-PLAN.md`.
**8D — Doku-Sync**: `docs/user-admin/checkliste-user-backend.md`,
`docs/STATUS-ABGLEICH-USER-PANEL.md` und `Admin-User.md` auf den
echten IST-Stand gezogen (8A8E waren als „offen" markiert, sind
aber umgesetzt).
**8F — SVG-Titelbild-Platzhalter**
- 9 Varianten (3 Muster × 3 Hub-Farben) in
`public/images/press-release-placeholders/`.
- `App\Enums\PressReleasePlaceholder` (Default, Seed-deterministisch).
- `<x-portal.press-release-placeholder>` + Picker-Modal
(`components.press-release-placeholder-picker`, dispatcht
`placeholder-selected`).
**8G — Titelbild-Schema + Cover-Resolver**
- Migration `placeholder_variant` auf `press_releases` (nullable).
- Model-`creating`-Hook setzt deterministisch eine Variante.
- `App\Services\PressRelease\PressReleaseCoverImage`
(`coverUrl`/`coverIsPlaceholder`).
- Hero-Bild in Customer-/Admin-Show; Vorschau + Picker in Create/Edit.
**8H — Bild-Upload mit Lizenz-Pflichtfeldern**
- Migration: `author`, `license_type`, `license_url`,
`persons_consent`, `rights_confirmed_at` auf `press_release_images`.
- `App\Enums\ImageLicenseType` (CC/kommerziell erzwingen Lizenz-URL).
- Image-Manager: Urheber (Pflicht), Lizenztyp (Pflicht), Lizenz-URL
(bedingt), Personen-Einwilligung, Rechte-Bestätigung (Pflicht).
- Abweichung: Upload-Control bleibt `flux:input type=file` statt
`flux:file-upload` (Stabilität). Lizenzerfassung vollständig.
**8J — Quota-Stub (vor 8I, damit Modal darauf aufsetzt)**
- Migration: `users.press_release_quota` (3),
`..._used_this_month` (0).
- `User::pressReleaseQuotaRemaining()`,
Decrement in `PressReleaseService::submitForReview()`.
- Command `press-releases:reset-monthly-quota` + Scheduler
(`monthlyOn(1, '00:05')`).
**8I — Veröffentlichungs-Modal (Customer-Show)**
- „Zur Prüfung einreichen" öffnet jetzt ein FluxUI-Modal statt
`wire:confirm`: Rechtshinweis (Platzhalter, anwaltlich zu prüfen),
Kontingent-Badge, 3 Bestätigungs-Checkboxen (Submit via Alpine
disabled bis alle gesetzt) → ruft das bestehende `submitForReview()`.
**8K — Abschluss**
- Neue Tests: `PressReleasePlaceholderTest` (8),
`PressReleaseImageLicenseTest` (3), `PressReleaseQuotaTest` (3),
`PressReleasePublishModalPhase8iTest` (2).
- Suite: **375 passed, 4 skipped**. Pint clean.
`npm run build:portal` clean.
---
## 2026-05-29 · Wartung · Test-Regression-Fix + Phase-7-Doku nachgezogen
Review der Gesamt-Umsetzung. Zwei Befunde behoben:

View file

@ -0,0 +1,179 @@
# Decision-Update · Preisstruktur & Veröffentlichungs-Flow (Launch)
**Version:** Juni 2026 **Datum:** 11.06.2026 **Status:** Abgestimmt bereit zur Integration ins Konzept-/Decision-Log **Scope:** Launch-Preisstruktur, PM-Kontingente, Launch-Credit-Umfang, Veröffentlichungs-Flow. Ersetzt die betroffenen Stellen früherer Tarif-Festlegungen (insb. `konzept/Konzept-Update 1` §810 und `user-admin/Presseportal Konzept für Relaunch` §810).
> **IST-Stand 11.06.2026**: Reines Entscheidungs-Dokument, noch nicht
> umgesetzt. Im Code existieren bisher nur der Quota-Stub
> (`users.press_release_quota`, zählt aktuell beim **Einreichen** statt bei
> der Veröffentlichung) und die KI-Klassifikation (Rot/Gelb/Grün, siehe
> `user-admin/Entwicklungsplan KI-Pruefung und Veroeffentlichung.md`).
> Zahlung/Tarife, Submit-Gate hinter Buchung, Slot-Verbrauch bei
> Veröffentlichung, Tageslimit, Einzel-PM und die drei Credit-Posten sind
> offen — siehe Abgleich in `STATUS-ABGLEICH-USER-PANEL.md` §3.5.
---
## 1. Kontext
Dieses Update bündelt die in der Abstimmung getroffenen Entscheidungen zur Preisstruktur und zum Veröffentlichungs-Flow für den Relaunch. Leitlinie blieb durchgängig die Anti-Zombie-Positionierung: keine versteckten Gebühren, keine künstliche Verknappung, kein Bezahlen für Leistungen, die nicht erbracht wurden. Mehrere ältere Festlegungen wurden bewusst überschrieben (siehe Abschnitt 5).
---
## 2. Finalisierte Tarifstruktur (Launch)
|Tier|Monatlich|Jährlich|PMs/Monat|Pro PM|
|---|---|---|---|---|
|**Starter**|29 €|290 €|3|9,67 €|
|**Business**|49 €|490 €|10|4,90 €|
|**Pro**|99 €|990 €|25|3,96 €|
|**Agency**|199 €|1.990 €|60|3,32 €|
**Einzel-PM:** 19 € einmalig geführt als **separater No-Abo-Block** neben dem Tarif-Raster, nicht als linke/billigste Spalte. Kommunikation über das No-Commitment-Argument („Einmal veröffentlichen, kein Abo, keine Kündigung"), nicht über den Preis.
**Enterprise:** sichtbar, aber als **dezenter Sales-Hinweis unterhalb der Tabelle** („Größere Mengen oder mehrere Marken? → Kontakt"). Keine eigene Preisspalte, individuelles Pricing.
---
## 3. Mechaniken & Regeln
### 3.1 Jahrespreis-Kommunikation
Die Jahrespreise entsprechen exakt **10 Monatsbeiträgen** → kommuniziert als **„2 Monate gratis"** statt als Prozent-Rabatt. Numerisch identisch zu den Bestandszahlen, nur die Darstellung ändert sich. Der konkrete Hebel zieht psychologisch stärker und passt zur Ehrlichkeits-Linie.
### 3.2 PM-Kontingent: Verbrauch
**Der PM-Slot zählt ausschließlich bei Veröffentlichung runter, nicht bei der Prüfung.**
- Rot (abgelehnt) → **kein** Slot verbraucht
- Gelb/Grün (veröffentlicht) → Slot zählt runter
Begründung: Wer nichts veröffentlicht bekommt, zahlt keinen Slot. Schützt insbesondere ehrliche Nutzer, deren PM erst nach Nachbesserung durchgeht (relevant ab Phase 2).
### 3.3 Tageslimit (Flut-Schutz)
Schützt die redaktionelle Glaubwürdigkeit des Portals gegen Dumping, nicht den Umsatz. Greift realistisch nur in den oberen Tiers.
|Tier|PMs/Monat|Max./Tag|
|---|---|---|
|Starter|3||
|Business|10|2|
|Pro|25|3|
|Agency|60|5|
Das Tageslimit gilt **auch für nachgekaufte Extra-PMs** sonst würde Extra-PM zum „Spam freikaufen". Höherer Tagesdurchsatz = Enterprise-Fall.
### 3.4 Einzel → Abo-Brücke
Wer als Einzel-Käufer innerhalb von 30 Tagen ein Abo abschließt, bekommt die 19 € auf den ersten Monat angerechnet. Schützt das Einmal-Segment und bietet einen sauberen Upgrade-Pfad.
---
## 4. Launch-Credit-System (klein gehalten)
Zum Launch greifen genau drei Credit-Posten alle ohne KI-Abhängigkeit, alle mit echtem Nutzen ab Tag 1:
|Posten|Status|Mechanik|
|---|---|---|
|**Extra-PM**|✅ Launch|Monatskontingent voll → einzelne PM nachkaufbar (faire Alternative zum Zwangs-Upgrade)|
|**Boost / Platzierung**|✅ Launch|Nur für **grüne** PMs, nachträglich kaufbar|
|**Veröffentlichungsnachweis (PDF)**|✅ Launch|Kleiner Mitnahme-Posten, PR-Beleg fürs Reporting|
**Credit-Anker:** 1 Credit = 1 € (Listenpreis), Volumenrabatt über Pakete.
**Bewusst ausgeschlossen:** Verkaufte Dofollow-Backlinks. Verstoßen gegen Googles Link-Spam-Richtlinien (Presse-Links gehören auf `nofollow`/`sponsored`) und widersprechen der Ehrlichkeits-Positionierung frontal.
---
## 5. Veröffentlichungs-Flow (Launch)
```
Schreiben & „Speichern" → buchen → „Speichern & zur Prüfung einreichen"
(frei) (gegated hinter Buchung)
KI-Prüfung (Red-Flag)
┌──────────────────────────┼──────────────────────────┐
ROT GELB GRÜN
abgelehnt veröffentlicht veröffentlicht
kein Slot weg Slot 1 Slot 1
(Boost nachkaufbar)
```
### 5.0 Klarstellung Gelb-Routing (Entscheidung 12.06.2026)
**Gelb geht zum Launch direkt live — es gibt keine manuelle Prüf-Queue.**
Die Klassifikation kennt nur zwei Ausgänge:
- **Rot** = Inhalte, die rechtlich oder inhaltlich **nicht veröffentlichbar**
sind → Ablehnung mit Meldung/Begründung an den Autor, kein Slot-Verbrauch.
- **Gelb/Grün** = veröffentlichbar → der Beitrag geht in der ersten Phase
direkt online (sofort bzw. zum geplanten Termin), Slot 1.
Gelb bleibt als interne Markierung erhalten (z. B. nicht boostbar, Signal
für den Admin), löst aber **keinen** manuellen Review-Schritt aus. Nach dem
Relaunch sind **Vorabprüfungen** geplant (Phase 2, siehe Abschnitt 7), die
Usern die Möglichkeit geben, ihren Beitrag vor der Einreichung zu
korrigieren.
### 5.1 Zwei-Button-Logik
- **„Speichern"** immer frei, auch ohne Buchung. Entwürfe schreiben/ablegen reibungslos, auch _vor_ der Buchung (Conversion-Vorteil: fertige PM senkt Kaufhürde).
- **„Speichern & zur Prüfung einreichen"** sichtbar, aber gegated. Ohne aktive Buchung öffnet das Modal einen Buchungs-Hinweis statt des Prüf-Flows. Der Button konvertiert, er verschwindet nicht.
Begründung für den Gate: Die Prüfung ist die erste kostenpflichtige KI-Ressource. Kein gebuchtes Produkt → kein Ressourcenverbrauch.
### 5.2 Kein Re-Check zum Launch
Einreichen ist zum Launch eine **Einbahnstraße**: Die PM geht durch (gelb/grün → live) oder wird abgelehnt (rot). Es gibt **keinen** „nachbessern und erneut prüfen"-Loop, weil Redigieren/Vorab-Prüfung erst Phase 2 sind.
Konsequenz: Pro PM gibt es genau **eine** Prüfung, untrennbar an die Veröffentlichung gekoppelt. Eine eingereichte PM = eine Prüfung = (bei gelb/grün) eine Veröffentlichung. Damit existiert zum Launch **kein Prüf-Abuse-Vektor** → der komplette Prüfzähler-Mechanismus ist zum Launch nicht nötig.
### 5.3 Keine Gratis-Test-Prüfung
Harter Gate zum Launch. Eine kostenlose Vorab-Prüfung würde den Flow nur verkomplizieren (wenn eine PM durchgeht, wird sie ohnehin veröffentlicht) und einen Abuse-Vektor öffnen (Wegwerf-Accounts). Eine kontrollierte Test-Prüfung (z. B. pro verifizierter Domain) bleibt als spätere Option offen.
---
## 6. Überschriebene Entscheidungen
|Bereich|Alt|Neu|Grund|
|---|---|---|---|
|**PM-Kontingent Pro**|60/Monat|**25/Monat**|60 unrealistisch hoch → Overage-System griff nie, Kontingent wirkte faktisch „unbegrenzt"|
|**PM-Kontingent Agency**|150/Monat|**60/Monat**|dito; Kontingente jetzt an realistischer PR-Frequenz kalibriert|
|**Jahrespreis-Kommunikation**|„ca. 17 % Rabatt"|**„2 Monate gratis"**|gleicher Preis, stärkerer psychologischer Hebel, klarer|
|**Bonus-Credits in Tarif-Tabelle**|12/30/60/120 als Tarif-Argument|**entfernt** (→ Phase 2 als Prüf-Kontingent)|bewarb zum Launch eine Leistung ohne Verbrauchsmöglichkeit|
---
## 7. Auf Phase 2 verschoben
|Punkt|Warum verschoben|
|---|---|
|**Vorab-KI-Prüfung**|erzeugt erst die Situation „prüfen ohne (noch) zu veröffentlichen"|
|**Redigieren / Nachbearbeiten**|setzt Re-Check-Loop voraus|
|**Prüfzähler** (freie Prüfungen/Monat, z. B. 12/30/60/120, eigener Zähler)|erst mit Re-Check relevant; deckelt dann „prüfen ohne veröffentlichen"|
|**Credit-Overflow für Prüfungen**|Prüfzähler leer → weitere Prüfungen ziehen aus echter Credit-Wallet|
|**Klon-/Abuse-Schutz über Account-Monatslimit**|aggregiertes Limit pro Account statt Klon-Erkennung; greift erst bei Re-Check|
|**Score-Feinstufung für Boost**|„nur Geprüft/Hochwertig boostbar" setzt vollen Content-Score voraus|
|**Tier-gestaffelte Prüf-Versuche**|als „BALD" markiert; zum Launch flach|
**Designprinzip für Phase 2 festgehalten:** Eigener **Prüf-Zähler** (getrennt von der Credit-Wallet), damit „Prüfungen inklusive" ein sauberes Versprechen bleibt und Prüf-Budget nicht versehentlich für Boost/PDF verbraucht wird. Abuse-Schutz über aggregiertes Account-Monatslimit + Prüf-Tageslimit nicht über Klon-Erkennung.
---
## 8. Offene Stellschrauben (vor Phase-2-Bau zu entscheiden)
- **Boost-Nachkaufpreis** relativ zum inkludierten PM-Preis klar darüber (treibt Upgrade) oder nur leicht darüber (bequemer, schwächerer Upgrade-Sog).
- **Höhe des Prüf-Kontingents** je Tier final bestätigen, sobald Vorab-Prüfung gebaut wird (Ausgangsvorschlag 12/30/60/120).
- **Credit-Paketliste** auf Konsistenz prüfen (vom Nutzer angekündigt, separat einzubringen).
---
## 9. Anti-Zombie-Check (dieser Stand)
- ✅ Keine versteckten Gebühren Extra-PM und Boost sind sichtbare, optionale Zukäufe
- ✅ Keine künstliche Verknappung Kontingente decken den Normalfall bequem; Limits greifen nur bei echtem Power-/Abuse-Verhalten
- ✅ Kein Bezahlen für nicht erbrachte Leistung rot abgelehnte PM verbraucht keinen Slot
- ✅ Tageslimit als Qualitätsschutz fürs Portal begründet, nicht als Verkaufstrick
- ✅ Kein verkaufter Dofollow-Backlink
- ✅ Free schreiben, Gate erst beim Einreichen Friktion an der richtigen Stelle

View file

@ -1,8 +1,15 @@
# Phase 8 · User-Panel-Konsolidierung & Pressemitteilungs-Lifecycle
Stand: 2026-05-21
Stand: 2026-05-29 — **abgeschlossen** (alle Päckchen 8A8K umgesetzt).
Vorgänger: Phase 7 (Press-Release-Form-Refactor — abgeschlossen)
Abgleich-Doku: [`docs/STATUS-ABGLEICH-USER-PANEL.md`](./STATUS-ABGLEICH-USER-PANEL.md)
Roadmap-Abschluss: [`dev/frontend/hub-flux/20-PHASE-8-USER-PANEL.md`](../dev/frontend/hub-flux/20-PHASE-8-USER-PANEL.md)
> **Status 29.05.2026**: Alle Sub-Päckchen abgeschlossen. Bewusste
> Abweichung in 8H: Upload-Control bleibt `flux:input type=file` statt
> `flux:file-upload` (Stabilität); die Lizenz-Pflichtfelder sind vollständig
> umgesetzt. Der Rechtstext im Veröffentlichungs-Modal (8I) ist ein
> Platzhalter und vor Go-Live anwaltlich zu prüfen.
---
@ -579,18 +586,18 @@ und Schema-Änderungen mitbringen.
## 6. Akzeptanzkriterien Phase 8 gesamt
- [ ] Customer-Show + Admin-Show stellen alle Phase-7-Felder dar
- [ ] PM-Listen markieren Scheduling und Embargo
- [ ] Pressekontakt-Sidebar warnt bei leerer Auswahl
- [ ] `docs/user-admin/*` ist mit dem Code synchron
- [ ] Firmen-Liste entspricht dem Mockup zu ≥ 90 %
- [ ] Jede PM hat ein sichtbares Hero-Bild (echtes oder Platzhalter)
- [ ] Image-Upload erfasst Urheber + Lizenz-Typ + Rechte-Bestätigung
- [ ] „Zur Prüfung einreichen" erfordert eine bewusste Modal-Bestätigung
- [ ] Quota-Counter inkrementiert pro Einreichung, resettet monatlich
- [ ] Tests grün (außer pre-existing `ApiDocumentationTest`)
- [ ] Pint clean, Build clean
- [ ] Roadmap-Eintrag und `PROGRESS.md`-Block geschrieben
- [x] Customer-Show + Admin-Show stellen alle Phase-7-Felder dar
- [x] PM-Listen markieren Scheduling und Embargo
- [x] Pressekontakt-Sidebar warnt bei leerer Auswahl
- [x] `docs/user-admin/*` ist mit dem Code synchron
- [x] Firmen-Liste entspricht dem Mockup zu ≥ 90 %
- [x] Jede PM hat ein sichtbares Hero-Bild (echtes oder Platzhalter)
- [x] Image-Upload erfasst Urheber + Lizenz-Typ + Rechte-Bestätigung
- [x] „Zur Prüfung einreichen" erfordert eine bewusste Modal-Bestätigung
- [x] Quota-Counter inkrementiert pro Einreichung, resettet monatlich
- [x] Tests grün (375 passed, 4 skipped — inkl. pre-existing `ApiDocumentationTest`)
- [x] Pint clean, Build clean
- [x] Roadmap-Eintrag und `PROGRESS.md`-Block geschrieben
---

View file

@ -0,0 +1,224 @@
# Phase 9 · Veröffentlichungs-Flow (Launch) & Tarif-Modul
Stand: 2026-06-12 — **in Umsetzung** (Block 1: 9A9C zuerst, dann Review-Stopp,
dann Block 2: 9D9J).
Vorgänger: Phase 8 (User-Panel-Konsolidierung) + KI-Prüf-Pipeline (beide abgeschlossen).
Verbindliche Entscheidungen: [`docs/Decision-Update Preisstruktur & Veröffentlichungs-Flow.md`](./Decision-Update%20Preisstruktur%20&%20Ver%C3%B6ffentlichungs-Flow.md)
Abgleich-Doku: [`docs/STATUS-ABGLEICH-USER-PANEL.md`](./STATUS-ABGLEICH-USER-PANEL.md)
---
## 0. Worum es geht
Phase 9 setzt das Decision-Update vom 11./12.06.2026 um — in zwei Blöcken:
1. **Block 1 — Veröffentlichungs-Flow (9A9C)**: Die Flow-Regeln, die
unabhängig vom Tarif-Modul gelten und auf denen das Tarif-Modul aufsetzt.
Funktioniert vollständig mit dem vorhandenen Quota-Stub.
2. **Block 2 — Tarif-Modul (9D9I)**: Zahlung, Tarife, Einzel-PM, Tageslimit
und die drei Launch-Credit-Posten. Löst den Quota-Stub ab.
**Leitplanken aus dem Decision-Update:**
- Gelb geht zum Launch **direkt live** wie Grün — keine manuelle Prüf-Queue.
Nur Rot wird abgelehnt (Meldung mit Begründung an den Autor).
- Der PM-Slot zählt **bei Veröffentlichung** runter, nicht bei der Prüfung.
Rot verbraucht keinen Slot.
- „Speichern" bleibt immer frei; „Speichern & zur Prüfung einreichen" ist
hinter eine aktive Buchung gegated (der Button konvertiert, er verschwindet
nicht).
- Kein Re-Check zum Launch: eine Einreichung = eine Prüfung = (bei Gelb/Grün)
eine Veröffentlichung. Vorab-Prüfung/Redigieren sind Phase 2.
---
## 1. Sub-Päckchen-Übersicht
| ID | Thema | Größe | Risiko |
|---|---|---|---|
| **9A** | Gelb-Routing auf Direkt-Live umstellen (Routing, Scheduler, Tests) | S | gering |
| **9B** | Slot-Verbrauch von Einreichung auf Veröffentlichung umstellen (Rot = kein Slot) | M | mittel (Idempotenz) |
| **9C** | Submit-Gate-Schnittstelle (`hasActiveBooking()`-Stub, Modal-Hinweis, Server-Guard) | M | gering |
| — | **Review-Stopp mit User** | | |
| **9D** | Tarif-Datenmodell: Pläne, Subscriptions, Einzel-PM-Käufe; Quota-Stub ablösen | L | hoch (Datenmodell) |
| **9E** | Stripe-Anbindung (Laravel Cashier — **Dependency-Freigabe nötig**) | L | mittel |
| **9F** | Tarif-Seite + Checkout-UI (Raster, Einzel-PM-Block, „2 Monate gratis", Enterprise-Hinweis) | M | gering |
| **9G** | Tageslimit je Tier (Business 2 / Pro 3 / Agency 5; gilt auch für Extra-PMs) | S | gering |
| **9H** | Einzel-PM-Kauf (19 €) + Einzel→Abo-Brücke (Anrechnung 30 Tage) | M | mittel |
| **9I** | Launch-Credits: Extra-PM, Boost (nur Grün), Veröffentlichungsnachweis-PDF | L | mittel |
| **9J** | Abschluss: Tests, Pint, Build, Doku-Sync, PROGRESS-Eintrag | S | keine |
Nach jedem Päckchen Review-Stopp mit dem User; vor 9D ein größerer
(Datenmodell-Entscheidungen + Cashier-Freigabe).
---
## 2. Block 1 — Veröffentlichungs-Flow
### 9A · Gelb-Routing auf Direkt-Live
**Entscheidung (12.06.2026)**: Rot = nicht veröffentlichbar (rechtlich/
inhaltlich) → Ablehnung mit Meldung. Gelb/Grün = veröffentlichbar → geht in
der ersten Phase direkt online. Gelb bleibt als interne Markierung erhalten
(nicht boostbar, Admin-Signal), löst aber keine manuelle Prüfung aus.
**Anpassungen:**
- `PressReleaseService::routeByClassification()`: Gelb durchläuft denselben
Auto-Publish-Pfad wie Grün (`autoPublishGreen()` → generalisiert zu
`autoPublishApproved()`); Verzögerungsfenster
(`scoring.classification.green_delay_minutes`) gilt für beide.
- `PublishScheduledPressReleases`: Kandidaten-Query von
`classification = green` auf `classification IN (green, yellow)`.
- Admin-Review-Queue bleibt als **Fallback** bestehen: unklassifizierte PMs
(Job noch nicht gelaufen / KI-Ausfall ohne Fallback-Ergebnis) bleiben in
`review` und sind manuell behandelbar. KI-Badge und Klassifikations-Filter
im Admin bleiben unverändert.
**Tests:** `PressReleaseClassificationJobTest` (Gelb-sofort → published,
Gelb-geplant → bleibt review bis Termin), `PressReleaseSchedulingTest`
(gelbe fällige PM wird publiziert).
### 9B · Slot-Verbrauch bei Veröffentlichung
**Regel:** Der Slot zählt genau einmal pro PM, beim **ersten** Übergang zu
`published`. Rot abgelehnte PMs verbrauchen nichts.
**Anpassungen:**
- `submitForReview()`: Increment von `press_release_quota_used_this_month`
**entfernen**. Stattdessen Guard: Einreichen erfordert
`pressReleaseQuotaRemaining() > 0` (sonst würde eine grüne PM ohne
verfügbaren Slot veröffentlicht).
- `publish()`: Increment beim Statuswechsel auf `published`, idempotent —
nur wenn die PM zuvor noch nie veröffentlicht war (Prüfung über
`press_release_status_logs`, kein neues Schema-Feld). Zählt auf den
PM-Eigentümer (`user_id`).
- Veröffentlichungs-Modal: Text von „wird bei Einreichung verbraucht" auf
„wird bei Veröffentlichung verbraucht; abgelehnte PMs kosten keinen Slot".
**Tests:** Submit verbraucht keinen Slot; Publish (Admin, Auto-Publish,
Scheduler) verbraucht genau einen; Rot → kein Verbrauch; Archivieren +
erneutes Publizieren zählt nicht doppelt; Submit bei 0 Rest-Slots blockiert.
### 9C · Submit-Gate-Schnittstelle
**Ziel:** Das Gate aus dem Decision-Update §5.1, gebaut gegen eine schmale
Schnittstelle, die zunächst ein Stub bedient und in 9D/9E vom Tarif-Modul
implementiert wird — Modal und Service müssen dann nicht mehr angefasst werden.
**Anpassungen:**
- `User::hasActiveBooking(): bool` — Launch-Schnittstelle. Stub-Verhalten
über `config/billing.php` (`billing.enforce_booking`, Default `false`):
solange das Tarif-Modul fehlt, gibt die Methode `true` zurück; mit
aktiviertem Flag (und später echter Subscription-Prüfung) greift das Gate.
- Einreichungs-Modal (`press-release-submit-modal`): ohne aktive Buchung
zeigt das Modal statt des Prüf-Flows einen Buchungs-Hinweis mit CTA
(„Buchung erforderlich" → Tarif-Seite). Der Button bleibt sichtbar.
- Server-Guard: `submitForReview()` wirft ohne aktive Buchung eine Exception
(UI allein reicht nicht); API-Submit-Route antwortet mit **402**.
**Tests:** Gate aus (Default) → Verhalten unverändert; Gate an →
Modal-Hinweis statt Checkboxen, `submitForReview` wirft, API gibt 402.
---
## 3. Block 2 — Tarif-Modul (nach Review-Stopp)
### 9D · Tarif-Datenmodell
- Tabellen (Arbeitsstand, final beim Review-Stopp vor 9D):
`plans` (Starter/Business/Pro/Agency: Preis mtl./jährl., PMs/Monat,
Tageslimit), `subscriptions` (User, Plan, Zyklus, Status, Periodenstart/-ende),
`single_purchases` (Einzel-PM, Extra-PM, Boost, PDF — Typ, Preis, Status,
`applied_to_press_release_id`).
- `User::hasActiveBooking()` prüft echte Subscription oder offenen Einzel-PM-Kauf.
- Slot-Logik wechselt von `users.press_release_quota` auf Plan-Kontingent +
Periodenzähler; Stub-Spalten werden nach Migration entfernt.
- Kontingent-Anzeige (Modal, Editor) liest aus der neuen Quelle —
Schnittstelle `pressReleaseQuotaRemaining()` bleibt stabil.
### 9E · Stripe (Laravel Cashier)
- **Vor Start freizugeben:** `laravel/cashier` als neue Dependency.
- Checkout für Abo (monatlich/jährlich) und Einmalzahlung (Einzel-PM, Credits).
- Webhooks (Subscription-Status, Zahlungsausfall) + lokale Spiegelung.
- Rechnungen an bestehende `invoices`-Struktur anbinden (Klärung beim Review).
### 9F · Tarif-Seite + Checkout-UI
- Raster mit 4 Tiers; Einzel-PM als separater No-Abo-Block (nicht als
billigste Spalte); Enterprise als dezenter Sales-Hinweis unter der Tabelle.
- Jahrespreis kommuniziert als „2 Monate gratis".
- Einstieg aus dem Submit-Gate-Hinweis (9C) und aus „Buchungen & Add-ons".
### 9G · Tageslimit
- `plans.daily_limit` (Starter ohne Limit); Prüfung beim Veröffentlichen
(nicht beim Einreichen), zählt veröffentlichte PMs des Users pro Kalendertag
(Europe/Berlin); gilt auch für Extra-PMs. Überschreitung → PM bleibt in
`review` mit Hinweis, Veröffentlichung am Folgetag durch den Scheduler.
### 9H · Einzel-PM + Abo-Brücke
- Einzel-PM-Kauf 19 € → genau eine Einreichung/Veröffentlichung.
- Brücke: Abo-Abschluss innerhalb 30 Tagen rechnet 19 € auf den ersten
Monat an (Stripe-Coupon oder Rabatt-Position).
### 9I · Launch-Credits
- Credit-Wallet (1 Credit = 1 € Listenpreis, Pakete mit Volumenrabatt).
- Posten: **Extra-PM** (Kontingent voll → einzelne PM nachkaufen),
**Boost** (nur für grün klassifizierte PMs, nachträglich),
**Veröffentlichungsnachweis-PDF**.
- Kein Dofollow-Backlink-Verkauf (bewusst ausgeschlossen).
### 9J · Abschluss
- Volle Suite grün, Pint clean, `npm run build` clean.
- Doku-Sync: `STATUS-ABGLEICH`, `checkliste-user-backend.md`, dieses Dokument,
`PROGRESS.md`-Eintrag.
---
## 4. Was außerhalb von Phase 9 bleibt
- Vorab-KI-Prüfung, Redigieren/Re-Check-Loop, Prüfzähler, Credit-Overflow
(Decision-Update §7 — Phase 2)
- Score-Feinstufung für Boost („nur Geprüft/Hochwertig boostbar")
- Magic-Link-Flow, Statistik-/Abrechnungs-Tabs, Anhänge-Reaktivierung,
Trust-Score, Notice-and-Action
---
## 5. Risiken & Annahmen
- **Idempotenz Slot-Verbrauch (9B)**: Prüfung über Status-Logs statt neuem
Feld — bei Alt-Daten mit unvollständigen Logs schlimmstenfalls ein
doppelter Zähler; akzeptabel für den Stub, wird mit 9D-Periodenzähler
sauber.
- **Gate-Stub (9C)**: `enforce_booking=false` als Default hält das System
bis zum Tarif-Modul voll funktionsfähig; das Flag erlaubt Tests und
frühe Aktivierung.
- **9D/9E Datenmodell + Cashier**: größter Block, eigener Review-Stopp davor;
Stub-Ablösung (`press_release_quota`-Spalten entfernen) erst nach
verifizierter Migration.
- **Rechtstexte** (Einreichungs-Modal) sind weiterhin Platzhalter —
anwaltliche Prüfung läuft parallel, unabhängig von Phase 9.
- **Betrieb**: Queue-Worker für `classification` in Produktion bleibt
Go-Live-Voraussetzung (unabhängig von Phase 9).
---
## 6. Akzeptanzkriterien Phase 9 gesamt
- [ ] Gelb klassifizierte PMs gehen ohne manuelle Prüfung live (sofort/Termin)
- [ ] Rot verbraucht keinen Slot; Slot zählt genau einmal, bei Veröffentlichung
- [ ] Einreichen ohne aktive Buchung zeigt Buchungs-Hinweis (UI) und wird
serverseitig abgelehnt (Gate aktiviert)
- [ ] Tarife buchbar (4 Tiers, monatlich/jährlich), Einzel-PM kaufbar
- [ ] Tageslimit greift je Tier, auch für Extra-PMs
- [ ] Extra-PM, Boost (nur Grün) und PDF-Nachweis als Credits kaufbar
- [ ] Quota-Stub vollständig abgelöst, `pressReleaseQuotaRemaining()` stabil
- [ ] Tests grün, Pint clean, Build clean, Doku synchron

View file

@ -1,6 +1,8 @@
# `docs/` — Konzept- und Status-Dokumente
Stand: 21.05.2026 — nach Phase 7 (PM-Form-Refactor) und vor Phase 8 (User-Panel-Konsolidierung).
Stand: 11.06.2026 — Phase 8 (User-Panel-Konsolidierung) und die KI-Prüf-Pipeline
(Klassifikation + Content-Score, Phasen 05) sind abgeschlossen. Nächster großer
Block: Zahlung/Tarife + Veröffentlichungs-Flow laut Decision-Update.
Diese README ist der schnellste Einstieg in den `docs/`-Ordner.
Sie verlinkt die zentralen Dokumente und sortiert sie nach „Was ist der aktuelle Stand?" vs. „Was ist konzeptueller Zielzustand?".
@ -10,55 +12,67 @@ Sie verlinkt die zentralen Dokumente und sortiert sie nach „Was ist der aktuel
| Frage | Doku |
|---|---|
| Was ist im Code, was ist Konzept, was fehlt? | [`STATUS-ABGLEICH-USER-PANEL.md`](./STATUS-ABGLEICH-USER-PANEL.md) |
| Wie geht es als Naechstes weiter? | [`PHASE-8-USER-PANEL-PLAN.md`](./PHASE-8-USER-PANEL-PLAN.md) |
| Was ist Phase 1 + Phase 7 (User Backend, Pressemitteilungs-Form)? | [`user-admin/checkliste-user-backend.md`](./user-admin/checkliste-user-backend.md) |
| Was gilt für Preise, Kontingente und den Veröffentlichungs-Flow zum Launch? | [`Decision-Update Preisstruktur & Veröffentlichungs-Flow.md`](./Decision-Update%20Preisstruktur%20&%20Ver%C3%B6ffentlichungs-Flow.md) |
| Wie wird das umgesetzt (aktueller Plan)? | [`PHASE-9-FLOW-UND-TARIFE-PLAN.md`](./PHASE-9-FLOW-UND-TARIFE-PLAN.md) |
| Wie funktioniert die KI-Prüfung (Klassifikation, Score, Audit)? | [`user-admin/Entwicklungsplan KI-Pruefung und Veroeffentlichung.md`](./user-admin/Entwicklungsplan%20KI-Pruefung%20und%20Veroeffentlichung.md) |
| Was ist pro Phase erledigt, was offen? | [`user-admin/checkliste-user-backend.md`](./user-admin/checkliste-user-backend.md) |
| Welche Hub-Flux-Phasen sind durch? | [`../dev/frontend/hub-flux/PROGRESS.md`](../dev/frontend/hub-flux/PROGRESS.md) |
| Was ist die Phase-7-Detail-Doku? | [`../dev/frontend/hub-flux/19-PHASE-7-PRESS-RELEASE-FORM.md`](../dev/frontend/hub-flux/19-PHASE-7-PRESS-RELEASE-FORM.md) |
## Aufbau
### `user-admin/`
### Top-Level — Status & Entscheidungen
Konzept und Status-Dokumentation fuer das User- und Admin-Backend.
Jede Seite hat oben einen Verweis auf den aktuellen Code-Stand und referenziert den Abgleich.
- [`STATUS-ABGLEICH-USER-PANEL.md`](./STATUS-ABGLEICH-USER-PANEL.md) — Konzept-vs-Code-Vergleich pro Page. **Erste Anlaufstelle.**
- [`Decision-Update Preisstruktur & Veröffentlichungs-Flow.md`](./Decision-Update%20Preisstruktur%20&%20Ver%C3%B6ffentlichungs-Flow.md) — **Verbindlicher Launch-Stand** für Tarife, PM-Kontingente, Credits und Veröffentlichungs-Flow. Überschreibt die Tarif-Abschnitte (§810) in `Konzept-Update 1` und im Relaunch-Konzept.
- [`PHASE-9-FLOW-UND-TARIFE-PLAN.md`](./PHASE-9-FLOW-UND-TARIFE-PLAN.md) — **Aktueller Umsetzungsplan**: Veröffentlichungs-Flow (9A9C) + Tarif-Modul (9D9J).
- [`PHASE-8-USER-PANEL-PLAN.md`](./PHASE-8-USER-PANEL-PLAN.md) — Plan der Phase 8 (abgeschlossen 29.05.2026, als Referenz erhalten).
- [`Echte öffentliche Unterseiten.md`](./Echte%20%C3%B6ffentliche%20Unterseiten.md) — Sitemap-Konzept, jede Seite mit IST-Notiz.
- [`KI-UND-ENTWICKLER-WORKFLOW.md`](./KI-UND-ENTWICKLER-WORKFLOW.md) — Workflow für KI-/Entwickler-Sessions.
- [`Admin-User.md`](./user-admin/Admin-User.md) — Hauptdokument zum User-/Admin-Backend, Phase 1 + Phase 7 zusammengefasst, Phase 8 verlinkt.
- [`checkliste-user-backend.md`](./user-admin/checkliste-user-backend.md) — Erledigt/Offen-Liste pro Phase.
### `user-admin/` — User-/Admin-Backend
Konzept und Status-Dokumentation für das User- und Admin-Backend.
- [`Admin-User.md`](./user-admin/Admin-User.md) — Hauptdokument zum User-/Admin-Backend (Navigation, Firmen-Detail, Rollen).
- [`checkliste-user-backend.md`](./user-admin/checkliste-user-backend.md) — Erledigt/Offen-Liste pro Phase (1, 7, 8, KI-Pipeline).
- [`Entwicklungsplan KI-Pruefung und Veroeffentlichung.md`](./user-admin/Entwicklungsplan%20KI-Pruefung%20und%20Veroeffentlichung.md) — KI-Klassifikation (Rot/Gelb/Grün), Content-Score, Audit-Log; Phasen 05 umgesetzt (11.06.2026).
- [`Umsetzung Pressemitteilung Bearbeitung Titelbild Veroeffentlichung.md`](./user-admin/Umsetzung%20Pressemitteilung%20Bearbeitung%20Titelbild%20Veroeffentlichung.md) — Umsetzungs-Notiz (11.06.2026): Titelbild/Cover, Lizenzformular, Zeitzonen-Handling, vereinfachte Veröffentlichungs-Box.
- [`Lizenztyp Bildupload.md`](./user-admin/Lizenztyp%20Bildupload.md) — Fachvorgabe für die Lizenz-/Rechtefelder beim Bildupload (umgesetzt).
- [`user-zusammenhaenge.md`](./user-admin/user-zusammenhaenge.md) — Datenmodell-Mapping, Models, Services und Commands.
- [`Presseportal Konzept für Relaunch.md`](./user-admin/Presseportal%20%E2%80%93%20Konzept%20f%C3%BCr%20Relaunch.md) — Zielzustand der Plattform (KI-Workflow, Bilder, Notice-and-Action, DSGVO, Magic-Link, Tarife, Korrektur-Modell). Jeder Abschnitt hat eine **IST-Stand-Box**.
- [`Presseportal Konzept für Relaunch.md`](./user-admin/Presseportal%20%E2%80%93%20Konzept%20f%C3%BCr%20Relaunch.md) — Zielzustand der Plattform (KI-Workflow, Bilder, Notice-and-Action, DSGVO, Magic-Link, Tarife, Korrektur-Modell). Jeder Abschnitt hat eine **IST-Stand-Box**; die Tarif-Abschnitte sind durch das Decision-Update überschrieben.
### `konzept/`
### `konzept/` — Strategie & Marke
Strategische Konzepte und Updates. Sie beschreiben Themen, die teilweise oder noch gar nicht gebaut sind. Jedes Update hat oben einen IST-Stand-Hinweis.
- [`Konzept Presseportal Marktposition & Hebel.md`](./konzept/Konzept%20Presseportal%20%E2%80%93%20Marktposition%20&%20Hebel.md) — Marktanalyse und Positionierung (Anti-Zombie-Linie).
- [`Entwicklungs-Konzept - Frontend-Komponenten Multi-Brand.md`](./konzept/Entwicklungs-Konzept%20-%20Frontend-Komponenten%20Multi-Brand.md) — Multi-Brand-Architektur (umgesetzt).
- [`Konzept-Update 1 Überarbeitete Abschnitte.md`](./konzept/Konzept-Update%201%20%E2%80%93%20%C3%9Cberarbeitete%20Abschnitte.md) — Tarife, Credits, Score (noch nicht umgesetzt).
- [`Konzept-Update 2 Score-Stufen-System.md`](./konzept/Konzept-Update%202%20%E2%80%93%20Score-Stufen-System.md) — Drei-Stufen-Score (noch nicht umgesetzt).
### Top-Level
- [`STATUS-ABGLEICH-USER-PANEL.md`](./STATUS-ABGLEICH-USER-PANEL.md) — Konzept-vs-Code-Vergleich pro Page.
- [`PHASE-8-USER-PANEL-PLAN.md`](./PHASE-8-USER-PANEL-PLAN.md) — Detail-Plan der naechsten Sub-Paeckchen.
- [`Echte öffentliche Unterseiten.md`](./Echte%20%C3%B6ffentliche%20Unterseiten.md) — Sitemap-Konzept, jede Seite mit IST-Notiz.
- [`KI-UND-ENTWICKLER-WORKFLOW.md`](./KI-UND-ENTWICKLER-WORKFLOW.md) — Workflow fuer KI-/Entwickler-Sessions.
- [`Konzept-Update 1 Überarbeitete Abschnitte.md`](./konzept/Konzept-Update%201%20%E2%80%93%20%C3%9Cberarbeitete%20Abschnitte.md) — Tarife/Credits (§810 **überschrieben durch Decision-Update**), Score-Architektur §15 (Klassifikation + Content-Score umgesetzt, Trust-Score offen), Boost §16, Tool-Loop §17.
- [`Konzept-Update 2 Score-Stufen-System.md`](./konzept/Konzept-Update%202%20%E2%80%93%20Score-Stufen-System.md) — Drei-Stufen-Score (Backend umgesetzt; öffentliche Badges im Web-Frontend offen).
- [`Konzept-Update 3 Multi-Brand-Architektur (Hub & Spoke).md`](./konzept/Konzept-Update%203%20%E2%80%93%20Multi-Brand-Architektur%20(Hub%20&%20Spoke).md) — Hub-&-Spoke-Markenarchitektur.
- [`Konzept-Update 4 - Positionierung + Markenversprechen.md`](./konzept/Konzept-Update%204%20-%20Positionierung%20+%20%20Markenversprechen.md) — Positionierung und Markenversprechen.
- [`Konzept-X - Brand-Landing.md`](./konzept/Konzept-X%20-%20Brand-Landing.md) — Brand-Landing-Konzept.
## Lesehilfe
In den ueberarbeiteten Dokumenten finden sich folgende Markierungen:
In den überarbeiteten Dokumenten finden sich folgende Markierungen:
| Marker | Bedeutung |
|---|---|
| **IST-Stand JJJJ-MM-TT** | Kompakte Notiz oben am Abschnitt, was im Code tatsaechlich umgesetzt ist. |
| Phase 1 / Phase 7 / Phase 8 | Verweis auf die aktuelle Roadmap. Phase 1 = Grund-User-Backend; Phase 7 = PM-Form-Refactor; Phase 8 = User-Panel-Konsolidierung. |
| **IST-Stand JJJJ-MM-TT** | Kompakte Notiz oben am Abschnitt, was im Code tatsächlich umgesetzt ist. |
| Phase 1 / Phase 7 / Phase 8 | Abgeschlossene Roadmap-Blöcke: Grund-User-Backend, PM-Form-Refactor, User-Panel-Konsolidierung. |
| KI-Pipeline (Phasen 05) | Klassifikation, Routing, Content-Score — abgeschlossen 11.06.2026, siehe Entwicklungsplan. |
| Hub-Flux | Visuelle Migrationsphase des User Backends, gepflegt in `dev/frontend/hub-flux/`. |
| Phase 2 / Phase 3 | Spaeter — Magic-Link-Flow, KI-Vorpruefung, Tarif-Modul, Score, Notice-and-Action. |
| Phase 2 / Phase 3 | Später — Magic-Link-Flow, Re-Check/Redigieren, Trust-Score, Notice-and-Action, Statistik. |
| Launch-Block (offen) | Zahlung/Tarife, Submit-Gate, Slot-Verbrauch bei Veröffentlichung — siehe Decision-Update. |
## Wie pflegen wir die Doku?
- Wenn sich der Code so weit aendert, dass ein Konzept-Abschnitt nicht mehr stimmt, kommt eine **IST-Stand-Box** an den Abschnitt, statt den Konzept-Text zu loeschen. So bleibt die urspruengliche Zielvorstellung lesbar.
- Wenn sich der Code so weit ändert, dass ein Konzept-Abschnitt nicht mehr stimmt, kommt eine **IST-Stand-Box** an den Abschnitt, statt den Konzept-Text zu löschen. So bleibt die ursprüngliche Zielvorstellung lesbar.
- Entscheidungen, die frühere Konzept-Festlegungen ersetzen, kommen als eigenes **Decision-Update** auf Top-Level; die überschriebenen Abschnitte bekommen einen Verweis darauf.
- Jeder Phasen-Abschluss aktualisiert
- `user-admin/checkliste-user-backend.md` (Erledigt-Block),
- `STATUS-ABGLEICH-USER-PANEL.md` (Abgleich),
- `dev/frontend/hub-flux/PROGRESS.md` (Tagebuch),
- und ggf. die Detail-Doku in `dev/frontend/hub-flux/`.
- Neue grosse Themen bekommen ein eigenes Plan-Dokument auf `docs/`-Top-Level (z. B. `PHASE-8-USER-PANEL-PLAN.md`).
- Neue große Themen bekommen ein eigenes Plan-Dokument auf `docs/`-Top-Level (z. B. `PHASE-8-USER-PANEL-PLAN.md`).

View file

@ -1,6 +1,9 @@
# Status-Abgleich · User Panel
Stand: 2026-05-21
Stand: 2026-06-11 (Phase 8 vollständig abgeschlossen; KI-Prüf-Pipeline
Phasen 05 umgesetzt; Titelbild-/Lizenz-/Zeitzonen-Umbau vom 10./11.06.
eingearbeitet. Preise & Veröffentlichungs-Flow: siehe
[`Decision-Update Preisstruktur & Veröffentlichungs-Flow.md`](./Decision-Update%20Preisstruktur%20&%20Ver%C3%B6ffentlichungs-Flow.md))
> Dieses Dokument vergleicht die Konzept-Dokumente im Ordner `docs/` mit dem
> tatsächlichen Code-Stand. Es dient als Single Source of Truth für die
@ -52,7 +55,7 @@ Stand: 2026-05-21
| Filter ohne Firma, Status, Portal | `statusFilter`, `portalFilter`, `companyFilter` aktiv | ✅ |
| Filter-Presets (`user_filter_presets`) | **fehlt** | 📝 (in Phase 2 lt. Doku — bleibt pending) |
| PM-Detail Tab „Verlauf" aus `press_release_status_logs` | als „Status & Verlauf"-Card eingebaut, nicht als eigener Tab | 🔄 (Doku-Anpassung: Card statt Tab; funktional gleichwertig) |
| Hinweis Scheduling/Embargo in der Liste | **fehlt** | 📝 (s. eigener Gap-Block unten) |
| Hinweis Scheduling/Embargo in der Liste | umgesetzt (Sub-Label „geplant · …" / „Embargo bis …" in der Datums-Spalte, `index.blade.php` Z. 505514) | ✅ (Phase 8B) |
### Pressemitteilungs-Forms
@ -62,10 +65,12 @@ Stand: 2026-05-21
| Pflichtfeld `company_id` für Customer | Validation `required` | ✅ |
| Portal aus Firma abgeleitet (Customer) | `updatedCompanyId()` setzt `portal` aus `company->portal` | ✅ |
| `subtitle`-Feld | seit Phase 7 da | ❓ (im Konzept nicht erwähnt, aber sinnvoll) |
| `scheduled_at`, `embargo_at`-Felder im Form | seit Phase 7F da | ❓ (im Konzept nicht beschrieben) |
| `scheduled_at`, `embargo_at`-Felder im Form | `scheduled_at` da (Datum via `flux:date-picker` + Uhrzeit via `flux:time-picker`, Eingabe/Anzeige in Europe/Berlin, Speicherung UTC). **Embargo aus der Form-UI entfernt** (11.06.) — `embargo_at` bleibt im Schema, wird beim Speichern auf `null` geführt | 🔄 (bewusste Vereinfachung; Doku: `Umsetzung Pressemitteilung Bearbeitung Titelbild Veroeffentlichung.md`) |
| Titelbild pro PM | ein einzelnes Cover-Bild (1280×580) oder SVG-Platzhalter; Upload-Form einklappbar, Platzhalter-Picker | ✅ (Phase 8F/8G + Umbau 11.06.) |
| Einreichungs-Modal in allen Customer-Ansichten | `confirm-submit-review`-Modal in Show, Create **und** Edit (KI-Plan Phase 0) | ✅ |
| HTML-Sanitizer auf Save | `PressReleaseHtmlSanitizer` (mews/purifier) | ❓ (Konzept-Punkt 2/Bilder nennt KI-Check, aber keinen HTML-Sanitizer — sollte dokumentiert werden) |
| Boilerplate-Override pro PM | seit Phase 7 als optionaler Override-Text | ❓ (im Konzept nicht erwähnt) |
| Pressekontakt-Zuordnung Single-Select (1 pro PM, n:m beibehalten) | seit Phase 7, jetzt optional/Warnung | 🔄 (Konzept-Punkt: Pressekontakt war ursprünglich „mehrere möglich", jetzt 1 pro PM optional) |
| Pressekontakt-Zuordnung Single-Select (1 pro PM, n:m beibehalten) | seit Phase 7, jetzt optional; Warn-Box in der Sidebar-Card, wenn kein Kontakt gewaehlt (`create`/`edit.blade.php`) | ✅ (Phase 8C; Konzept-Punkt: war ursprünglich „mehrere möglich", jetzt 1 pro PM optional) |
| Attachment-Manager | **temporär deaktiviert wegen Security-Review** | ⚠️ (Konzept beschreibt Anhänge, Code hat es auskommentiert) |
### Pressemitteilungs-Detail (Customer Show)
@ -76,20 +81,20 @@ Stand: 2026-05-21
| Zugeordnete Pressekontakte | umgesetzt | ✅ |
| Rejection-Begründung sichtbar | umgesetzt | ✅ |
| Vorschau-Link für externe Reviewer | `generateShareLink` via Magic-Link-Token | ✅ |
| Anzeige Subtitle / `scheduled_at` / `embargo_at` / `boilerplate_override` | **fehlt** (nur Admin-Show hat scheduled/embargo) | 📝 (offener Punkt aus letzter Diskussion) |
| Anzeige Subtitle / `scheduled_at` / `embargo_at` / `boilerplate_override` / `no_export` | umgesetzt — Subtitle unter H1, Scheduling/Embargo als Cards im „Status & Verlauf"-Block, Boilerplate-Override als eigene Card (`customer/press-releases/show.blade.php`) | ✅ (Phase 8A; Admin-Show analog) |
### Firmen-Liste (`customer/press-kits/index.blade.php`)
| Konzept-Aussage / Mockup | IST | Status |
|---|---|---|
| Karten-Grid pro Firma mit Logo, Status, Portal, Rolle, KPIs | Karten vorhanden, aber **deutlich schlichter** als Mockup | 📝 (Hauptthema Phase 8) |
| Counter-Strip (X Firmen, X aktiv, X PMs total, X Kontakte) | **fehlt** | 📝 |
| Saved-View-Tabs (Alle / Aktiv / In Anlage / Inaktiv / Mit mir geteilt) | **fehlt** | 📝 |
| Filter-Chips (Status / Portal / Rolle / Branche) | **nur Volltext-Suche** | 📝 |
| Seg-Toggle Karten/Liste | **fehlt** | 📝 |
| Empty-States (keine Firma / Filter ohne Treffer) | nur generischer Empty-State | 📝 |
| Rollen-Legende (Admin / Redakteur / Beobachter) | **fehlt** | 📝 |
| „Firma anlegen"-CTA | derzeit zeigt nur „Firma anlegen anfragen" → Profil; Mockup hat direkten Anlage-Flow | 🔄 (Firma-Self-Service ist Phase-2-Thema laut Doku, im Mockup aber wie Phase-1 dargestellt) |
| Karten-Grid pro Firma mit Logo, Status, Portal, Rolle, KPIs | umgesetzt auf Mockup-Niveau (`.firm-card`, deterministische Logo-Varianten, Status-Badge, Portal-Pills, Rolle-Pill, KPIs) | ✅ (Phase 8E) |
| Counter-Strip (X Firmen, X aktiv, X PMs total, X Kontakte) | umgesetzt | ✅ (Phase 8E) |
| Saved-View-Tabs (Alle / Aktiv / In Anlage / Inaktiv / Mit mir geteilt) | umgesetzt mit Live-Counts; „In Anlage" bewusst noch leer (Phase-2-Heuristik) | ✅ (Phase 8E) |
| Filter-Chips (Status / Portal / Rolle / Branche) | Portal + Rolle via FluxUI-Dropdown + URL-Sync umgesetzt | ✅ (Phase 8E) |
| Seg-Toggle Karten/Liste | umgesetzt (`?mode=list`) | ✅ (Phase 8E) |
| Empty-States (keine Firma / Filter ohne Treffer) | umgesetzt (3-Schritt-Onboarding + Reset-CTA) | ✅ (Phase 8E) |
| Rollen-Legende (Admin / Redakteur / Beobachter) | umgesetzt als `panel-warm` | ✅ (Phase 8E) |
| „Firma anlegen"-CTA | zeigt „Firma anlegen anfragen" → Profil (Add-Tile); Self-Service-Anlage bleibt Phase-2-Thema | 🔄 (bewusst, Firma-Self-Service ist Phase 2) |
### Firmen-Detail (`customer/press-kits/show.blade.php`)
@ -129,17 +134,26 @@ Stand: 2026-05-21
### 3.1 KI-Freigabe-Workflow
**Konzept-Stand**: `Presseportal Konzept für Relaunch.md` Abschnitt 1.
**Konzept-Stand**: `Presseportal Konzept für Relaunch.md` Abschnitt 1 + §15.
**Umsetzungs-Doku**: `user-admin/Entwicklungsplan KI-Pruefung und Veroeffentlichung.md` (Phasen 05 ✅, 11.06.2026).
| Punkt | Code-Stand |
|---|---|
| KI-Vorprüfung mit JSON-Antwort | **nicht implementiert** |
| Drei-Stufen-Ergebnis grün/gelb/rot | nur „review"/„published"/„rejected" via Admin-Flow |
| Logging der KI-Antworten | **fehlt** |
| Trust-Score | **fehlt** |
| Blacklist-Wort-Check | **vorhanden** über `PressReleaseService::submitForReview` mit `BlacklistViolationException` |
| KI-Prüfung mit JSON-Antwort | **umgesetzt**`ClassifyPressRelease`-Job (Queue `classification`), OpenAI-Treiber + deterministischer Fallback, provider-agnostische Architektur unter `app/Services/PressRelease/Classification/` |
| Drei-Stufen-Ergebnis grün/gelb/rot | **umgesetzt**`press_releases.classification`; Routing aktuell: Rot → `rejected` + Mail, Gelb → manuelle Admin-Queue, Grün → Auto-Publish. ⚠️ **Entscheidung 12.06.2026**: Gelb geht zum Launch **direkt live** wie Grün (Umstellung in Phase 9A) |
| Logging der KI-Antworten | **umgesetzt**`ki_audits`-Tabelle (append-only, inkl. Provider/Modell/Begründung/Raw-Response) |
| Content-Score 0100 → Stufe | **umgesetzt**`content_score`/`content_tier` (`ScorePressRelease`-Job), Editor-Panel, Admin-Badges, öffentliches Stufen-Badge in Customer-Show |
| Re-Klassifikation bei Änderung | **umgesetzt**`reclassifyIfClassified()`/`rescoreIfScored()` bei Titel-/Text-Änderung (Customer, Admin, API) |
| Admin-On-Demand-Prüfung | **umgesetzt** — „Prüfung"-Button + Modal im Admin-Editor (Re-Check ohne Statusänderung) |
| API-Absicherung | **umgesetzt** — API kann `status` nicht mehr setzen; eigene Submit-Route läuft durch denselben Funnel |
| Trust-Score | **fehlt** (Phase 3 / KI-Plan Phase 6) |
| Blacklist-Wort-Check | **vorhanden** als synchroner Hard-Filter vor der KI-Klassifikation |
**Bewertung**: 📝 — Konzept-Vision für Phase 2/3, im Code nur die rudimentäre Blacklist-Variante.
**Bewertung**: ✅ — Kern-Pipeline produktionsbereit. ⚠️ Betriebs-Voraussetzung:
Queue-Worker für `classification` in Produktion (Test-Drain:
`php artisan classification:work`). 📝 verbleibend: Trust-Score, Live-Update
des Ergebnisses in der UI (aktuell erst nach Reload sichtbar), Stufen-Badges
im öffentlichen Web-Frontend.
### 3.2 Bilder & Lizenzen
@ -147,16 +161,16 @@ Stand: 2026-05-21
| Punkt | Code-Stand |
|---|---|
| Upload-Workflow (Eigenes / Stock / KI) | Nur „Eigenes Bild" via `press-release-images-manager` |
| Pflichtfelder (Urheber, Lizenztyp, Lizenz-URL, Personen-Einwilligung, Rechte-Bestätigung) | Nur `title` + `copyright` (Freitext) — **deutlich unter Konzept** |
| Upload-Workflow (Eigenes / Stock / KI) | Nur „Eigenes Bild" via `press-release-images-manager`; auf **ein Titelbild pro PM** begrenzt, Cover-Variante 1280×580, Original wird nach Variantenerzeugung gelöscht (Stock/KI weiterhin offen) |
| Pflichtfelder (Urheber, Lizenztyp, Lizenz-URL, Personen-Einwilligung, Rechte-Bestätigung) | umgesetzt (Phase 8H, erweitert 10./11.06. nach `Lizenztyp Bildupload.md`) — `author`, `license_type` (7 Typen, `App\Enums\ImageLicenseType`), `license_detail`, `license_url` (bedingt Pflicht), `source_url`, `people_rights_status`, `property_rights_status`, `rights_notes`, `rights_confirmed_at`; Risikohinweise bei unklaren Lizenzfällen |
| KI-Wasserzeichen-Check | **fehlt** |
| Unsplash/Pexels-API | **fehlt** |
| KI-Bildgenerierung | **fehlt** |
| `is_preview`-Flag für Titelbild | im Modell vorhanden, im Manager toggelbar |
| Bild-Varianten (thumb/medium/large) | `ImageService::PRESS_RELEASE_IMAGE_VARIANTS` generiert sie automatisch |
| SVG-Platzhalter, falls keine Bilder | **inline in Landing-Page-Komponenten (z. B. `focus-hero`, `feed-top-item`), kein zentrales Set** |
| SVG-Platzhalter, falls keine Bilder | umgesetzt (Phase 8F/8G) — zentrales Set in `public/images/press-release-placeholders/`, `App\Enums\PressReleasePlaceholder`, `PressReleaseCoverImage`-Resolver, Hero in Customer-/Admin-Show |
**Bewertung**: 📝 — Großthema für Phase 8 (siehe Plan). Lizenzfelder + SVG-Platzhalter sind Pflicht, bevor Bild-Upload produktiv geht.
**Bewertung**: ✅ für Lizenzfelder + SVG-Platzhalter (Phase 8). 📝 verbleibend: Stock-/KI-Quellen, Wasserzeichen-Check (Phase 2/3).
### 3.3 Notice-and-Action (Meldung durch Dritte)
@ -187,19 +201,27 @@ Stand: 2026-05-21
### 3.5 Pricing / Tarife / Credits
**Konzept-Stand**: `Presseportal Konzept für Relaunch.md` Abschnitt 8 + 9, `Konzept-Update 1.md`.
**Verbindlicher Konzept-Stand**: [`Decision-Update Preisstruktur & Veröffentlichungs-Flow.md`](./Decision-Update%20Preisstruktur%20&%20Ver%C3%B6ffentlichungs-Flow.md)
(11.06.2026 — überschreibt §810 in `Konzept-Update 1` und im Relaunch-Konzept).
| Punkt | Code-Stand |
| Punkt (laut Decision-Update) | Code-Stand |
|---|---|
| Tarif-Tabellen (Einzel/Starter/Business/Pro/Agency) | **nicht im Datenmodell** |
| PM-Kontingent pro Tarif | **fehlt** |
| Bonus-Credits monatlich | **fehlt** |
| Credit-Pakete | **fehlt** |
| Auto-Refill | **fehlt** |
| Stripe-Integration | **fehlt** |
| Tarif-Raster Starter/Business/Pro/Agency (29/49/99/199 €, 3/10/25/60 PMs) | **nicht im Datenmodell** |
| Einzel-PM 19 € (No-Abo-Block) + Einzel→Abo-Brücke | **fehlt** |
| Zahlung/Checkout (Stripe) | **fehlt** |
| Slot-Verbrauch **bei Veröffentlichung** (Rot = kein Slot) | ⚠️ **abweichend** — Quota-Stub zählt aktuell beim **Einreichen** (`submitForReview`); muss auf Veröffentlichung umgestellt werden |
| Submit-Gate: „Zur Prüfung einreichen" gegated hinter Buchung | **fehlt** — Einreichen ist aktuell frei (Quota-Stub 3/Monat) |
| Tageslimit (Business 2 / Pro 3 / Agency 5) | **fehlt** |
| Launch-Credits: Extra-PM, Boost (nur grün), Veröffentlichungsnachweis-PDF | **fehlt** |
| Jahrespreis als „2 Monate gratis" | Kommunikations-Regel, greift mit Tarif-UI |
| `user_payment_options`-Tabelle | **vorhanden** (Pivot zu Companies da, aber kein aktiver Flow) |
**Bewertung**: 📝 — Phase 2/3, größtes ungebautes Feature. Für Phase 8 ist relevant: bei PM-Einreichung wird **konzeptuell** Quota dekrementiert; die UI-Anzeige im Veröffentlichungs-Modal kann darauf vorbereitet werden, das echte Decrement-Verhalten kommt aber erst mit dem Tarif-Modul.
**Bewertung**: 📝 — der **Launch-Block** und damit das größte ungebaute Feature.
Vorhandene Anschlusspunkte: Quota-Stub (`users.press_release_quota`,
`pressReleaseQuotaRemaining()`), Veröffentlichungs-Modal (zeigt Kontingent),
KI-Klassifikation (liefert das Rot/Gelb/Grün für den Slot-Verbrauch).
Bewusst **nicht** zum Launch: Re-Check-Loop, Vorab-Prüfung, Prüfzähler
(alles Phase 2, siehe Decision-Update §7).
### 3.6 Korrektur-Modell & Tombstones
@ -221,11 +243,14 @@ Stand: 2026-05-21
| Punkt | Code-Stand |
|---|---|
| User-Score-Tabelle | **fehlt** |
| Firmen-Score | **fehlt** |
| Auto-Publishing in Abhängigkeit vom Score | **fehlt** |
| Content-Score 0100 → Stufe (Standard/Geprüft/Hochwertig) | **umgesetzt** (KI-Plan Phase 5) — `content_score`/`content_tier`, Schwellen kalibrierbar in `config/scoring.php` (Geprüft ≥ 60, Hochwertig ≥ 80) |
| Stufen-Badges im Backend + Customer-Ansicht | **umgesetzt** (Standard wird laut Konzept nicht beworben) |
| Stufen-Badges im öffentlichen Web-Frontend | **fehlt** (Folgearbeit) |
| Trust-Score (User-/Firmen-Ebene) | **fehlt** (Phase 3 / KI-Plan Phase 6) |
| Auto-Publishing in Abhängigkeit vom Score | Klassifikations-basiert umgesetzt (Grün → Auto-Publish); Trust-Score-Lockerung fehlt |
| Boost-Eligibilität nach Stufe | **fehlt** — zum Launch gilt laut Decision-Update: Boost nur für **grüne** PMs, Score-Feinstufung ist Phase 2 |
**Bewertung**: 📝 — Phase 3, vollständig im Konzept.
**Bewertung**: ✅ Content-Score-Kern da; 📝 Trust-Score + öffentliche Badges + Boost-Stufung.
---
@ -236,7 +261,9 @@ Stand: 2026-05-21
| Phase-7-Schema-Erweiterungen (`press_releases.subtitle`, `scheduled_at`, `embargo_at`, `boilerplate_override`, `no_export`) | Migrationen `2026_05_20_*` | Im Konzept ergänzen, dass PMs Untertitel + Scheduling/Embargo unterstützen |
| `mews/purifier` für HTML-Sanitization | `PressReleaseHtmlSanitizer` | Im Konzept-Abschnitt zu Editor erwähnen |
| `press_release_attachments`-Tabelle + Model | Migration `2026_05_20_143424_*` | UI auskommentiert, Tabelle bleibt → Doku-Anker für spätere Reaktivierung |
| Background-Job für scheduled publishing | `app/Console/Commands/PublishScheduledPressReleases.php`, alle 5 Min via Scheduler | Im Konzept als „automatische Veröffentlichung zum geplanten Termin" hinzufügen |
| Background-Job für scheduled publishing | `app/Console/Commands/PublishScheduledPressReleases.php`, alle 5 Min via Scheduler; publiziert seit der KI-Anbindung nur noch **grün klassifizierte** fällige PMs | Im Konzept als „automatische Veröffentlichung zum geplanten Termin" hinzufügen |
| Zeitzonen-Handling für geplante Termine | `PressRelease::DISPLAY_TIMEZONE` (Europe/Berlin), `scheduledAtLocal()`/`embargoAtLocal()`; Eingabe Berlin, Speicherung UTC | dokumentiert in `Umsetzung Pressemitteilung Bearbeitung Titelbild Veroeffentlichung.md`; `published_at`/`created_at` weiterhin UTC-Anzeige (Folgeschritt) |
| Monatlicher Quota-Reset | `press-releases:reset-monthly-quota` (Scheduler, 1. des Monats) | Stub — wird vom Tarif-Modul (Decision-Update) abgelöst |
| FluxUI Toast für UX-Feedback | `Flux::toast()` durchgehend in Customer-Forms | Konzept-übergreifend, kein Konzept-Update nötig |
| Smooth-Scroll zu Validation-Errors | `resources/js/portal-form-hooks.js` | UX-Detail, keine Konzept-Doku |
| Pre-Submit-Check-Liste in PM-Forms | computed `presubmitChecks` | Im Konzept als „Pre-Submit-Check senkt Support-Aufwand" ergänzen |
@ -251,14 +278,14 @@ Stand: 2026-05-21
Diese Punkte habe ich beim Review der Phase-7-Forms gefunden, sie sind weder
in den Konzept-Dokumenten erfasst noch in einem Plan:
| Lücke | Betroffene Dateien | Empfehlung |
| Lücke | Betroffene Dateien | Status |
|---|---|---|
| Customer-Show zeigt weder `subtitle` noch `scheduled_at`/`embargo_at`/`boilerplate_override` | `customer/press-releases/show.blade.php` | Phase 8 |
| Admin-Show zeigt weder `subtitle` noch `boilerplate_override` | `admin/press-releases/show.blade.php` | Phase 8 |
| Liste-Indikator für Scheduling/Embargo | `customer/press-releases/index.blade.php`, `admin/press-releases/index.blade.php` | Phase 8 |
| Pressekontakt-Sidebar zeigt keine Warn-Box, wenn kein Kontakt gewählt | `customer/press-releases/create.blade.php`, `edit.blade.php` | Phase 8 |
| Anhang-Tests laufen ins Leere | `tests/Feature/PressReleaseAttachmentsManagerTest.php`, Teile von `PressReleasePhase7SchemaTest.php` | Phase 8 → `->skip(...)` mit Verweis auf Security-Review |
| Roadmap-Doku `19-PHASE-7-PRESS-RELEASE-FORM.md` ist nicht mehr aktuell | Letzte 3 große Änderungen fehlen | Phase 8-Doku-Block |
| Customer-Show zeigt weder `subtitle` noch `scheduled_at`/`embargo_at`/`boilerplate_override` | `customer/press-releases/show.blade.php` | ✅ erledigt (8A) |
| Admin-Show zeigt weder `subtitle` noch `boilerplate_override` | `admin/press-releases/show.blade.php` | ✅ erledigt (8A) |
| Liste-Indikator für Scheduling/Embargo | `customer/press-releases/index.blade.php`, `admin/press-releases/index.blade.php` | ✅ erledigt (8B) |
| Pressekontakt-Sidebar zeigt keine Warn-Box, wenn kein Kontakt gewählt | `customer/press-releases/create.blade.php`, `edit.blade.php` | ✅ erledigt (8C) |
| Anhang-Tests laufen ins Leere | `tests/Feature/PressReleaseAttachmentsManagerTest.php`, Teile von `PressReleasePhase7SchemaTest.php` | ✅ via `->skip(...)` mit Verweis auf Security-Review |
| Roadmap-Doku `19-PHASE-7-PRESS-RELEASE-FORM.md` ist nicht mehr aktuell | Letzte 3 große Änderungen fehlen | offen → wird im Phase-8-Abschluss (8K) als `20-PHASE-8-…md` dokumentiert |
---

View file

@ -1,17 +1,22 @@
Stand: Mai 2026 Zweck: Ersatz bzw. Ergänzung der Abschnitte 8, 9, 10 sowie neue Abschnitte zur Score-Architektur, Boost-Eligibilität und zum Tool-Loop. Datenmodell-Ergänzungen am Ende.
> **IST-Stand 21.05.2026**: Dieses Update beschreibt Phase-2/3-Themen.
> Aktuell ist im Code **nichts** davon umgesetzt:
> **IST-Stand 11.06.2026**:
>
> - Keine Tarif-Stufen, kein Kontingent, keine Stripe-Anbindung.
> - Kein Score, keine Boost-Eligibilitaet, kein Tool-Loop.
> - Kein Auto-Refill, keine Credit-Pakete.
>
> Phase 8 baut lediglich einen **Quota-Stub** auf `users.press_release_quota`
> und `press_release_quota_used_this_month` als Vorbereitung fuer das
> Veroeffentlichungs-Modal. Das echte Tarif-Modul ersetzt diese Felder
> spaeter. Plan-Doku: `docs/PHASE-8-USER-PANEL-PLAN.md`.
> - **§810 (Tarife, Credits, Preisliste) sind ueberschrieben** durch das
> [`Decision-Update Preisstruktur & Veröffentlichungs-Flow`](../Decision-Update%20Preisstruktur%20&%20Ver%C3%B6ffentlichungs-Flow.md)
> (11.06.2026): neue Kontingente (Pro 25 statt 60, Agency 60 statt 150),
> Jahrespreis als „2 Monate gratis", Bonus-Credits aus der Tarif-Tabelle
> entfernt, Launch-Credits auf Extra-PM/Boost/PDF-Nachweis reduziert.
> Die Abschnitte unten bleiben als urspruengliche Zielvorstellung lesbar.
> - **§15.1 (Klassifikations-Score) und §15.2 (Content-Score) sind umgesetzt**
> (11.06.2026, siehe `docs/user-admin/Entwicklungsplan KI-Pruefung und
> Veroeffentlichung.md`). §15.3 (Trust-Score), §16 (Boost) und §17
> (Tool-Loop) sind weiterhin offen.
> - Zahlung/Stripe, Tarif-Datenmodell, Credit-Pakete und Auto-Refill sind
> **nicht** umgesetzt. Im Code existiert nur der Phase-8-**Quota-Stub**
> (`users.press_release_quota`, zaehlt beim Einreichen — laut
> Decision-Update kuenftig bei Veroeffentlichung).
---
@ -23,13 +28,13 @@ Alle Tarife enthalten ein Kontingent an Pressemitteilungen sowie monatlich ausge
### Tier-Struktur
|Tier|Preis|PMs|Bonus-Credits/Mo.|Effektiver PM-Preis|Besonderheiten|
|---|---|---|---|---|---|
|**Einzel**|19 € / Stück|1|4 (verfallend nach 30 T)|19,00 €|Pay-as-you-go|
|**Starter**|19 €/Mo. (190 €/Jahr)|3|12|6,30 €|Free-Stock, KI-Quality-Check|
|**Business**|49 €/Mo. (490 €/Jahr)|10|30|4,90 €|Erweiterte Statistiken, optionaler Newsroom|
|**Pro**|99 €/Mo. (990 €/Jahr)|unbegrenzt (Fair Use)|60|< 2 |Eigener Newsroom, Priority, volles Statistik-Dashboard|
|**Agency**|199 €/Mo. (1.990 €/Jahr)|unbegrenzt für 5 Marken|120|< 1 |Multi-Redakteur-Workflow, API-Zugang, je weitere Marke 29 /Mo.|
| Tier | Preis | PMs | Bonus-Credits/Mo. | Effektiver PM-Preis | Besonderheiten |
| ------------ | ------------------------ | ----------------------- | ------------------------ | ------------------- | --------------------------------------------------------------- |
| **Einzel** | 19 € / Stück | 1 | 4 (verfallend nach 30 T) | 19,00 € | Pay-as-you-go |
| **Starter** | 29 €/Mo. (290 €/Jahr) | 3 | 12 | 9,67 € | Free-Stock, KI-Quality-Check |
| **Business** | 49 €/Mo. (490 €/Jahr) | 10 | 30 | 4,90 € | Erweiterte Statistiken, optionaler Newsroom |
| **Pro** | 99 €/Mo. (990 €/Jahr) | unbegrenzt (Fair Use) | 60 | < 2 | Eigener Newsroom, Priority, volles Statistik-Dashboard |
| **Agency** | 199 €/Mo. (1.990 €/Jahr) | unbegrenzt für 5 Marken | 120 | < 1 | Multi-Redakteur-Workflow, API-Zugang, je weitere Marke 29 /Mo. |
Jahrespreise mit ca. 17 % Rabatt eingebaut. Fair Use im Pro-Tarif: Soft-Cap 50 PMs/Monat.

View file

@ -2,9 +2,15 @@
Stand: Mai 2026 Zweck: Ersetzt die Außenkommunikation des Content-Scores durch ein dreistufiges System. Aktualisiert Abschnitt 15.2 (Content-Score) und Abschnitt 16 (Boost-Eligibilität) aus dem ersten Konzept-Update.
> **IST-Stand 21.05.2026**: Score-System und Stufen-Anzeige sind nicht
> implementiert. Im Code gibt es weder ein `user_score`- noch ein
> `company_score`-Modell. Das Thema bleibt fuer Phase 3.
> **IST-Stand 11.06.2026**: Der Content-Score mit Stufen-System ist
> **umgesetzt** (siehe `docs/user-admin/Entwicklungsplan KI-Pruefung und
> Veroeffentlichung.md`, Phase 5): `content_score`/`content_tier` auf
> `press_releases`, Schwellen Geprueft ≥ 60 / Hochwertig ≥ 80 kalibrierbar
> in `config/scoring.php`, Editor-Score-Panel, Admin-Badges und
> oeffentliches Stufen-Badge in der Customer-Ansicht (Standard ohne Badge).
> Offen: Stufen-Badges im oeffentlichen Web-Frontend, Boost-Eligibilitaet
> nach Stufe (zum Launch laut Decision-Update: Boost nur fuer gruene PMs)
> sowie User-/Firmen-Trust-Score (Phase 3).
---

View file

@ -0,0 +1,327 @@
Stand: Mai 2026 Zweck: Festlegung der Plattform-Architektur mit zentralem Hub (presseportale.com) und mehreren öffentlichen Brand-Portalen. Dokumentation der strategischen, technischen und Branding-Entscheidungen für die Entwicklung.
---
## Architektur-Entscheidung
Die Plattform folgt einem **Hub-and-Spoke-Modell**:
- **Ein zentraler Hub** für alle Verwaltungs-, Veröffentlichungs- und Abrechnungs-Funktionen
- **Mehrere öffentliche Brand-Portale**, die unabhängige redaktionelle Marken mit eigener Zielgruppe und eigener Editorial-Anmutung darstellen
- **Eine gemeinsame Codebase und Datenbank** im Hintergrund
Das Modell entspricht der Architektur, mit der etablierte Verlagsgruppen (Axel Springer, Hubert Burda Media) ihre Markenportfolios technisch organisieren: ein zentrales Redaktions- und Tool-System, viele Frontend-Marken.
### Strategische Vorteile
- **Effiziente Entwicklung:** Eine Codebase für alle Portale, Updates an Tools/Editor/Credit-System wirken portal-übergreifend
- **Multi-Portal-Publishing:** Publisher können Pressemitteilungen mit einem Klick auf mehreren Portalen veröffentlichen (verkaufbares Premium-Feature)
- **Datenkonsistenz:** Ein Account, ein Credit-Stand, eine Statistik-Aggregation über alle Portale
- **Skalierbarkeit:** Weitere Portale (z.B. branchenspezifisch) können als reine Frontend- und Konfigurations-Erweiterung hinzugefügt werden
- **Saubere Trennung Marke vs. Funktion:** Brand-Portale optimieren für Editorial-Glaubwürdigkeit, Hub für Funktion und Effizienz
---
## Domain- und Verantwortungs-Aufteilung
### presseportale.com Hub (Publisher Hub)
**Marke:** Publisher Hub (mit Subline "Mein Pressekonto")
**Funktion:**
- User-Panel: Editor, Dashboard, Statistiken, Credit-Verwaltung, Newsroom-Konfiguration
- Admin-Panel: Review-Queue, Moderation, Inventory-Verwaltung, Editorial-Picks, User-Verwaltung
- Magic-Link-Bereich für Pressekontakte
- Account-Setup und Tarif-Auswahl (zentraler Veröffentlichungs-Funnel)
- Stripe-Integration, Rechnungen, Buchhaltung
- Alle KI-Tools (Lektorat, Pressetext-Optimierung, Bildgenerierung, etc.)
**Branding:** Neutrale, eigenständige Marke. Sauberes Tool-Design (aktuell Flux UI). Funktionsfokussiert. Brand-Kontext der Portale wird über Banner/Hinweise vermittelt, nicht über Farbadaption.
**Zielgruppe:** Publisher (Unternehmen, PR-Agenturen, Pressekontakte), Admins.
---
### businessportal24.com Brand-Portal
**Marke:** businessportal24
**Funktion:**
- Öffentliche Pressemitteilungs-Plattform
- Editorial-Anmutung mit Fokus auf Wirtschaft, B2B, Branchen-Tiefe
- Kein eigener User-Login-Bereich
- Reichweiten-Generierung über Newsletter, SEO, Branchenseiten
**Branding:** Eigenständige Editorial-Identität (Anthrazit + Orange-Akzent). Wirkt wie ein Wirtschaftsmedium, nicht wie ein Pressedienst.
**Zielgruppe:** Wirtschaftsjournalisten, Mediaplaner, B2B-Entscheider, Branchen-Experten.
---
### presseecho.de Brand-Portal
**Marke:** presseecho
**Funktion:** Wie businessportal24, aber mit anderer Markenidentität und potentiell anderer Zielgruppen-Ausrichtung. Konzeption folgt in eigener Iteration.
**Branding:** Eigenständig, klar unterscheidbar von businessportal24 (eigener Akzentton, eventuell anderer Editorial-Schwerpunkt).
**Zielgruppe:** noch zu definieren / komplementär zu businessportal24.
---
## Login- und Session-Mechanik
### Grundregel
**Alle Authentifizierung läuft ausschließlich über presseportale.com.** Brand-Portale haben keine eigenen Login-Formulare oder Auth-Bereiche.
### Verhalten in den Brand-Portalen
- "Anmelden"-Button im Header eines Brand-Portals → Redirect auf presseportale.com (Login-Seite mit Rück-Redirect nach erfolgreicher Anmeldung)
- "Veröffentlichen"-Button → kurzer Brand-spezifischer Landing-Inhalt, dann Übergang auf presseportale.com für Account-Setup und Veröffentlichungs-Funnel
- Wenn der User über die Brand-Domain eingeloggt erkannt wird (über Cross-Domain-Mechanismus, siehe unten), erscheint im Header ein "Mein Account"-Element, das auf presseportale.com führt
### Cross-Domain-Session
Da die Brand-Portale und der Hub auf unterschiedlichen Top-Level-Domains laufen (.com / .de), ist Cookie-basiertes Session-Sharing nicht möglich. Notwendige Lösung:
**Variante A (empfohlen):** Token-basierter Auth-Mechanismus über Laravel Sanctum
- Hub gibt nach Login ein API-Token aus
- Brand-Portale prüfen über API gegen den Hub den Login-Status
- Vorteil: sauber, standardkonform, skalierbar
**Variante B:** Lightweight-Cookie-Sync über Cross-Domain-Redirect bei Pageload (analog zu wie Single-Sign-On-Lösungen es machen)
- Komplexer, fehleranfälliger
- Nur zu empfehlen, falls Variante A nicht umsetzbar
Empfehlung: Variante A, da sie zum Laravel-Stack ohnehin passt und auch für die API-Anbindung von Distribution-Partnern (connektar etc.) wiederverwendbar ist.
### Magic-Link-Flow
Magic-Links für Pressekontakte zeigen _immer_ auf presseportale.com mit Brand-Kontext-Hinweis:
> _„Sie verwalten eine Pressemitteilung, die auf businessportal24 veröffentlicht wurde."_
Brand-Logo und -Name werden im Hub-Header angezeigt, damit der Pressekontakt versteht, wo seine PM erscheint. Funktional bleibt der Flow zentral.
---
## E-Mail-Strategie
Saubere Trennung nach Funktion:
### System-Mails (von presseportale.com)
- Login, Password-Reset, Account-Bestätigung
- Magic-Link für Pressekontakte
- Stripe-Zahlungs-Bestätigungen, Rechnungen
- Credit-Aufladung-Bestätigungen, Auto-Refill-Hinweise
- Wartungs-/System-Benachrichtigungen
**Absender:** `noreply@presseportale.com` oder `support@presseportale.com`
### Editorial- und Brand-Mails (von der jeweiligen Brand-Domain)
- "Ihre Pressemitteilung wurde auf businessportal24 veröffentlicht"
- Branchen-Newsletter (Tageszusammenfassung, Wochenrückblick, Branchen-Alerts)
- Newsroom-Update-Benachrichtigungen
- Reichweiten-Statistiken pro PM
**Absender:** `redaktion@businessportal24.com`, `newsletter@businessportal24.com`, analog für presseecho.de
### Begründung
Diese Trennung stärkt das Branding der Portale (Editorial-Mails kommen "vom Magazin"), während Verwaltungs-Funktionen klar dem zentralen Hub zugeordnet bleiben. Funktional sind beide Domains technisch identisch hinterlegt (gleicher Mail-Service, gleiche Templates), nur die Absender-Konfiguration unterscheidet sich.
---
## Datenmodell-Implikationen
Die Hub-and-Spoke-Architektur erfordert eine zentrale Tabelle für die Brand-/Portal-Zugehörigkeit:
```
brands (oder portals)
- id, slug, name, domain
- primary_color, accent_color
- logo_url
- editorial_email, newsletter_email
- is_active, created_at
press_releases (Ergänzung)
- + brand_id (FK auf brands)
- + cross_published_to (JSON array of brand_ids, für Multi-Portal-Veröffentlichung)
placements (Ergänzung)
- + brand_id (FK auf brands)
- Placements gelten pro Portal, da Inventory portal-spezifisch ist
newsletters (Ergänzung)
- + brand_id
accounts
- Bleiben portal-übergreifend
- Eine Person hat einen Account, kann auf allen Portalen veröffentlichen
- Sub-Berechtigungen pro Brand möglich (für Agency-Tarif: Marke X nur auf Portal Y)
credit_accounts
- Bleiben portal-übergreifend, ein Credit-Pool für alles
```
### Wichtige Logiken
- Pressemitteilungen sind immer einem Brand zugeordnet (`brand_id`), können aber zusätzlich auf andere Brands "cross-published" werden
- Branchen, Kategorien und Tags können entweder portal-spezifisch oder portal-übergreifend definiert sein Empfehlung: portal-übergreifender Stamm, mit Möglichkeit zur portal-spezifischen Untergliederung
- Placements/Boost-Slots sind grundsätzlich portal-spezifisch (jeder Top-Slot auf businessportal24 ist ein anderer Slot als auf presseecho)
- Aggregierte Statistiken im Dashboard zeigen alle Brands eines Publishers zusammen, mit Filter-Möglichkeit pro Brand
---
## Brand-übergreifende Features
### Aktuell (Migrations-Phase)
Im Dashboard werden Pressemitteilungen aktuell **gefiltert nach Portal** angezeigt. Hintergrund: Die beiden Portale kommen aus separater Legacy-Entwicklung, eine getrennte Sicht erleichtert die Migration.
### Mittelfristig
**Cross-Sichtbarkeit als Standard:**
- Dashboard zeigt alle PMs eines Publishers portal-übergreifend
- Filter-Möglichkeit pro Portal vorhanden, aber nicht Standard
- Statistiken aggregieren über alle Portale
**Multi-Portal-Veröffentlichung als Premium-Feature:**
- Beim Einreichen einer PM kann der Publisher auswählen, auf welchen Portalen sie erscheinen soll
- Standard: Hauptportal des Publishers
- Optional: Zusatz-Portale (kostet zusätzliche Credits oder ist in höheren Tarifen inkludiert)
- Wettbewerber können das nicht starkes Verkaufsargument
**Portal-übergreifender Newsroom:**
- Premium-Publisher haben einen Newsroom auf jedem Portal, gepflegt aus einem zentralen Profil im Hub
- Logo, Beschreibung, Kontakt einmal pflegen auf allen Portalen aktuell
---
## Implikationen für die Veröffentlichen-Landingpage
Aus der Architektur folgt die Aufteilung der Veröffentlichen-Seite in zwei Ebenen:
### Auf businessportal24.com/veroeffentlichen (Brand-Landing)
- Hero mit _brand-spezifischem_ Wertversprechen (Wirtschafts-Fokus, B2B-Reichweite, Branchen-Tiefe)
- Konkrete Reichweiten-Zahlen _für businessportal24_ (Newsletter-Abos, Branchen-Traffic, ISIN-Coverage)
- Differenzierungs-Punkte speziell für dieses Portal
- Tarif-Teaser ("Ab 19 € pro Pressemitteilung", mit Link auf volle Übersicht)
- Soziale Beweise (Logos von Publishern, die businessportal24 nutzen)
- Direkter CTA "Jetzt veröffentlichen →" → zur zentralen Plattform auf presseportale.com
### Auf presseportale.com/veroeffentlichen (Zentrale Funnel-Seite)
- Volle Tarif-Tabelle (Einzel / Starter / Business / Pro / Agency)
- Tool-Showcase (Lektorat, KI-Bilder, etc.)
- Erklärung des Multi-Portal-Konzepts ("Ein Account, mehrere Portale")
- Portal-Auswahl im Anmelde-Prozess ("Auf welchen Portalen möchten Sie veröffentlichen? businessportal24 / presseecho / beide")
- FAQ
- Account-Setup-Funnel
### Analoge Struktur für presseecho.de
presseecho.de/veroeffentlichen folgt demselben Pattern, mit brand-spezifischem Inhalt und Übergang zum zentralen Funnel.
---
## Footer-Verlinkung zwischen Hub und Brand-Portalen
### Auf Brand-Portalen (Footer)
Im Footer-Bereich von businessportal24 und presseecho ein dezenter Link:
> **Für Publisher** → Publisher Hub | Pressemitteilung einreichen | Tarife & Pakete
Bestehende Kunden steigen so direkt in den Hub ein, ohne sich die Hub-Domain merken zu müssen.
### Auf dem Hub (Footer)
Im Footer von presseportale.com Verlinkung auf alle Brand-Portale:
> **Unsere Portale** → businessportal24 (Wirtschaft & Branchen) | presseecho (...)
Schafft Transparenz und Vertrauen sichtbar, dass es eine Plattform-Familie ist.
---
## Branding-Strategie pro Bereich
|Bereich|Primärfarbe|Anmutung|Charakter|
|---|---|---|---|
|**presseportale.com**|neutral (z.B. Anthrazit + zurückhaltender Akzent)|Tool / SaaS|sachlich, funktional, effizient|
|**businessportal24.com**|Anthrazit + Orange|Editorial / Wirtschaftsmedium|seriös, datendicht, B2B|
|**presseecho.de**|eigene Palette (z.B. Anthrazit + Blau oder Bordeaux)|Editorial / anderer Schwerpunkt|klar differenziert von businessportal24|
Wichtig: Die Brand-Portale müssen optisch klar unterscheidbar sein, damit Leser nicht den Eindruck gewinnen, es sei "dasselbe in zwei Versionen". Empfehlung: gemeinsame typografische Sprache (Editorial-Serif für Headlines, gleiche Sans für UI), aber klar unterschiedliche Akzentfarben und sekundäre visuelle Elemente.
Der Hub bekommt eine _eigene_ visuelle Sprache, die sich von beiden Brand-Portalen abhebt. Tendenziell: weniger Farbe, mehr Whitespace, Tool-orientierte Komponenten (Tabellen, Dashboards, Form-Bausteine). Aktuell auf Flux UI basierend soll noch eigene Identität bekommen, ohne den Funktions-Charakter zu verlieren.
---
## Migration und Roadmap
### Phase 1 (laufend)
- Backend-Migration zu Laravel
- Zentrale `brands`-Tabelle als Grundlage anlegen
- Bestehende PMs der beiden Portale werden mit `brand_id` versehen
- Dashboard zeigt portal-getrennt (Migrations-Komfort)
### Phase 2
- Hub auf presseportale.com mit User-Panel produktiv
- Magic-Link-Flow zentral aufgesetzt
- Erste Brand-Portal-Iteration (businessportal24) im neuen Design live
- Cross-Domain-Auth über Sanctum
### Phase 3
- Zweites Brand-Portal (presseecho) im neuen Design live
- Cross-Sichtbarkeit im Dashboard
- Multi-Portal-Veröffentlichung als Feature aktiv
### Phase 4 (mittelfristig)
- Aggregierte Statistiken portal-übergreifend
- Portal-übergreifender Newsroom
- Vorbereitung für drittes Portal (falls relevant)
---
## Skalierungs-Argument
Die Architektur ist explizit auf Wachstum ausgelegt. Wenn in 1224 Monaten ein drittes Portal sinnvoll wird (z.B. ein branchenspezifisches wie "energieportal.com" oder ein regional fokussiertes wie "presseportal-bayern.de"), bedeutet das technisch:
- Keine neue Codebase
- Keine neue Datenbank
- Kein neuer Auth-Mechanismus
- Kein neues Credit-System
- Nur: Frontend, Konfiguration in `brands`-Tabelle, Editorial-Setup
Damit wird die Investition in den Hub heute strukturell verteidigt jede Stunde, die in den Hub investiert wird, zahlt auf jedes zukünftige Portal mit ein.
---
## Offene Punkte / nächste Entscheidungen
- **Cross-Domain-Auth final festlegen:** Sanctum-Implementierung details, Token-Lebensdauer, Refresh-Strategie
- **presseecho-Konzept:** Markenidentität, Zielgruppe, Differenzierung zu businessportal24 klären
- **Multi-Portal-Veröffentlichung Pricing:** wie wird Cross-Publishing verrechnet? Pro zusätzlichem Portal X Credits? In höheren Tarifen inkludiert? Wie sehen die Tier-Grenzen aus?
- **Hub-Design eigenständig schärfen:** aktuelles Flux-UI-Setup soll mehr Eigenständigkeit bekommen, ohne den funktionalen Charakter zu verlieren eigenes Mini-Briefing nötig
- **Footer-Verlinkungen zwischen den Portalen:** konkrete Texte und Platzierungen finalisieren
- **Übergang in den Brand-Portalen markieren:** wenn ein User von businessportal24 auf den Hub springt sichtbarer Übergangs-Indikator (Banner oben "Sie sind im Publisher Hub" mit Rück-Link)? Oder unauffällig? UX-Entscheidung steht aus

View file

@ -1,8 +1,8 @@
# User Backend und Admin Backend
> **Stand der Doku**: 21.05.2026 — Phase 1 + Phase 7 (PM-Form-Refactor) sind umgesetzt.
> **Stand der Doku**: 11.06.2026 — Phase 1, Phase 7 (PM-Form-Refactor), Phase 8 (User-Panel-Konsolidierung) und die KI-Pruef-Pipeline (Klassifikation + Content-Score) sind abgeschlossen.
> Aktueller Code-vs-Konzept-Abgleich: [`docs/STATUS-ABGLEICH-USER-PANEL.md`](../STATUS-ABGLEICH-USER-PANEL.md).
> Plan der naechsten Schritte: [`docs/PHASE-8-USER-PANEL-PLAN.md`](../PHASE-8-USER-PANEL-PLAN.md).
> Naechster Block (Zahlung/Tarife, Veroeffentlichungs-Flow): [`docs/Decision-Update Preisstruktur & Veröffentlichungs-Flow.md`](../Decision-Update%20Preisstruktur%20&%20Ver%C3%B6ffentlichungs-Flow.md).
Dieses Konzept beschreibt das gemeinsame Backend aus zwei Perspektiven:
@ -66,16 +66,27 @@ Zusammenfassung:
- **Background-Job** `php artisan press-releases:publish-scheduled` veröffentlicht geplante PMs (alle 5 Minuten via Scheduler).
- **UX**: `Flux::toast()` für alle Erfolg/Fehler-Meldungen, Smooth-Scroll zum ersten Validation-Fehler nach Save, `presubmitChecks` als kompakte Pflichtfeld-Übersicht im Sidebar.
## Geplante Phase 8
## Phase 8 (abgeschlossen 29.05.2026)
Plan-Doku: `docs/PHASE-8-USER-PANEL-PLAN.md`. Schwerpunkte:
1. Show-Page-Lücken aus Phase 7 schließen (Subtitle, Scheduling, Embargo, Boilerplate-Override).
2. Listen-Indikatoren für geplante Veröffentlichung und Embargo.
3. Firmen-Liste auf Mockup-Niveau (Counter-Strip, Saved-Views, Filter-Chips, Card/List-Toggle, Rollen-Legende).
4. SVG-Platzhalter-Set für PM-Titelbilder + Auswahl-Modal.
5. FluxUI `flux:file-upload` im Image-Manager inkl. Pflichtfeldern für Urheber/Lizenz/Rechte.
6. Veröffentlichungs-Modal mit rechtlichen Hinweisen und einem Kontingent-Stub (das echte Tarif-System kommt später).
1. ✅ Show-Page-Lücken aus Phase 7 schließen (Subtitle, Scheduling, Embargo, Boilerplate-Override) — Customer + Admin (8A).
2. ✅ Listen-Indikatoren für geplante Veröffentlichung und Embargo (8B).
3. ✅ Pressekontakt-Warn-Box in der Form-Sidebar, wenn kein Kontakt gewählt (8C).
4. ✅ Firmen-Liste auf Mockup-Niveau (Counter-Strip, Saved-Views, Filter-Chips, Card/List-Toggle, Rollen-Legende) (8E).
5. ✅ SVG-Platzhalter-Set für PM-Titelbilder + Auswahl-Modal + Cover-Resolver (8F/8G).
6. ✅ Image-Manager mit Lizenz-Pflichtfeldern (Urheber/Lizenztyp/Lizenz-URL/Rechte-Bestätigung) (8H).
7. ✅ Veröffentlichungs-Modal mit rechtlichen Hinweisen und Kontingent-Stub (8I/8J; das echte Tarif-System kommt später).
## KI-Prüfung & Veröffentlichung (abgeschlossen 11.06.2026)
Detail-Doku: `Entwicklungsplan KI-Pruefung und Veroeffentlichung.md`. Kurzfassung:
- Jede Einreichung (Customer-Form **und** API) läuft durch denselben Funnel: Blacklist-Hard-Filter → asynchrone KI-Klassifikation (Rot/Gelb/Grün, OpenAI mit deterministischem Fallback) → Status-Routing.
- Rot → abgelehnt + Begründung per Mail; Gelb → manuelle Admin-Review-Queue; Grün → Auto-Publish (sofort oder zum geplanten Termin).
- Jede KI-Entscheidung wird in `ki_audits` protokolliert; Admin sieht Badge, Begründung und kann nach Klassifikation filtern. On-Demand-Prüfung über den „Prüfung"-Button im Admin-Editor.
- Zusätzlich Content-Score 0100 → Stufe Standard/Geprüft/Hochwertig mit Editor-Panel und Badges.
- Parallel umgesetzt (10./11.06.): ein Titelbild pro PM (Cover 1280×580), erweitertes Lizenz-/Rechteformular, Termine in Europe/Berlin (Speicherung UTC), Embargo aus der Form-UI entfernt — siehe `Umsetzung Pressemitteilung Bearbeitung Titelbild Veroeffentlichung.md`.
## Topbar
@ -123,7 +134,7 @@ Stand 21.05.2026:
- **Anhaenge** sind im UI deaktiviert (Security-Review). Tabelle `press_release_attachments` und Service `PressReleaseAttachmentStorage` bleiben erhalten.
- **Filter-Presets** sind weiterhin **Gelb** (Tabelle existiert, UI noch nicht aktiv).
Phase: **Gruen** fuer Liste, Detail, Statusverlauf, Firmenpflicht, Untertitel, Scheduling, Embargo und Boilerplate-Override. **Gelb** fuer Filter-Presets. **Rot/Spaeter** fuer KI-Vorpruefung, Notice-and-Action und Korrektur-/Update-Hinweis-System (siehe `Presseportal Konzept für Relaunch.md`).
Phase: **Gruen** fuer Liste, Detail, Statusverlauf, Firmenpflicht, Untertitel, Scheduling und Boilerplate-Override. **Umgesetzt (11.06.)**: KI-Pruefung bei Einreichung (Klassifikation + Content-Score, siehe `Entwicklungsplan KI-Pruefung und Veroeffentlichung.md`); Embargo wurde aus der Form-UI entfernt. **Gelb** fuer Filter-Presets. **Rot/Spaeter** fuer Vorab-KI-Pruefung ohne Einreichung, Notice-and-Action und Korrektur-/Update-Hinweis-System (siehe `Presseportal Konzept für Relaunch.md`).
**3. Firmen** Klar strukturierter Detailbereich pro Firma, weil hier am meisten dranhängt:

View file

@ -0,0 +1,524 @@
# Entwicklungsplan: KI-Prüfung & Veröffentlichungs-Pipeline
Stand: 11.06.2026 — **Phasen 05 abgeschlossen**, Phase 6 (Trust-Score) offen.
Dieser Plan definiert die schrittweise Umsetzung der automatisierten Prüfung
und Veröffentlichung von Pressemitteilungen (PM). Er ist so geschnitten, dass
jede Phase einzeln umgesetzt, getestet und ausgeliefert werden kann.
> **Abgleich mit dem Decision-Update (11.06.2026)**: Das
> [`Decision-Update Preisstruktur & Veröffentlichungs-Flow`](../Decision-Update%20Preisstruktur%20&%20Ver%C3%B6ffentlichungs-Flow.md)
> setzt auf dieser Pipeline auf und ergänzt zum Launch drei noch offene
> Flow-Regeln, die **nicht** Teil dieses Plans waren:
>
> 1. **Submit-Gate**: „Zur Prüfung einreichen" wird hinter eine aktive
> Buchung gelegt (das Modal zeigt ohne Buchung einen Buchungs-Hinweis).
> 2. **Slot-Verbrauch bei Veröffentlichung** statt bei Einreichung —
> rot abgelehnte PMs verbrauchen keinen Slot. Der aktuelle Quota-Stub
> zählt noch beim Einreichen (`submitForReview`) und muss umgestellt werden.
> 3. **Kein Re-Check zum Launch**: eine Einreichung = eine Prüfung;
> Nachbessern + erneut prüfen kommt erst in Phase 2.
> 4. **Gelb-Routing geändert (Entscheidung 12.06.2026)**: Gelb geht zum
> Launch **direkt live** wie Grün — keine manuelle Review-Queue mehr.
> Nur Rot wird abgelehnt (mit Begründung an den Autor). Phase 4 unten
> beschreibt das ursprünglich gebaute Verhalten (Gelb → manuelle Queue);
> die Umstellung erfolgt im Phase-9-Plan
> (`docs/PHASE-9-FLOW-UND-TARIFE-PLAN.md`, Päckchen 9A).
## Ziel & Leitprinzip
Jede eingehende PM wird **automatisch von einer KI geprüft**. Nur in
**äußersten Fällen** erfolgt eine manuelle redaktionelle Prüfung. Zwei
Einreichungsstellen müssen denselben Prüf-Pfad durchlaufen:
1. **Web-Formular** (Customer- und Admin-Editor)
2. **API** (`/api/v1/press-releases`)
Es gibt zwei voneinander unabhängige Bewertungen (Konzept-Update 1, Abschnitt 15):
- **Klassifikations-Score (Grün/Gelb/Rot)** — der „Red Flag": entscheidet, ob
überhaupt veröffentlicht wird. **Jetzt umzusetzen.**
- **Content-Score (0100) → Stufe (Standard/Geprüft/Hochwertig)** — die
Qualitätsbewertung („Scoring"). **Spätere Phase.**
## Konzept-Grundlage
- `docs/konzept/Konzept-Update 1 Überarbeitete Abschnitte.md`, §15.1
(Klassifikations-Score) und §15.2 (Content-Score).
- `docs/konzept/Konzept-Update 2 Score-Stufen-System.md` (Stufen-Mapping,
`content_tier`, Außenkommunikation).
Klassifikations-Score laut Konzept §15.1:
| Klassifikation | Bedeutung | Auswirkung |
|---|---|---|
| **Grün** | unauffällig | direkte Veröffentlichung (optional 510 Min. Verzögerung) |
| **Gelb** | unklar/grenzwertig | manuelle Review-Queue (nicht boostbar) |
| **Rot** | unzulässig | zurück an Autor mit Begründung, keine Veröffentlichung |
Faktoren (Red Flags): Werbung statt PM, beleidigend/diskriminierend, rechtlich
heikel, Spam-Muster, unseriöse Versprechen. Speicherung laut Konzept:
`press_releases.classification` plus Audit-Log `ki_audits`.
## Ist-Zustand (Bestandsaufnahme)
- **Statuswerte** (`App\Enums\PressReleaseStatus`): `draft`, `review`,
`published`, `rejected`, `archived`.
- **Web-Einreichung**: `App\Services\PressRelease\PressReleaseService::submitForReview()`
prüft nur eine wortbasierte Blacklist (`config/blacklist.php` via
`BlacklistService`), setzt sonst Status `review`, erhöht das Quota und
schreibt ein `PressReleaseStatusLog`.
- **Veröffentlichung**: `PressReleaseService::publish()` (Admin-Aktion) und der
Cron `App\Console\Commands\PublishScheduledPressReleases` (publiziert
`review`-PMs mit fälligem `scheduled_at`). Beide prüfen erneut nur die
Blacklist.
- **API**: `App\Http\Controllers\Api\V1\PressReleaseController::store()` /
`update()` schreiben `status` direkt aus dem Request (erlaubt: `draft`,
`review`) und rufen `submitForReview` **nicht** auf. Eine API-PM mit
`status=review` landet damit **ohne** Blacklist-/Quota-/Log-Prüfung in der
Queue.
- **UI-Einreichung (Prozess-Start)**:
- Detailansicht ([show.blade.php]): vollständiges Modal `confirm-submit-review`
mit rechtlichen Hinweisen, Quota-Anzeige und Bestätigungs-Checkboxen →
ruft `submitForReview`.
- Bearbeiten ([edit.blade.php]): Button „Speichern & zur Prüfung" mit nur
`wire:confirm` (Browser-Dialog), **kein** Modal.
- Erstellen ([create.blade.php]): Button „Zur Prüfung senden" ohne Modal.
- **Kein** Datenmodell für Klassifikation/Score: keine Spalten
`classification`, `content_score`, `content_tier`, keine Tabelle `ki_audits`.
## Lücken & Risiken
- **L1 — API-Bypass**: Einreichung über die API umgeht jede Prüfung.
- **L2 — Keine echte Inhaltsprüfung**: nur eine triviale Wort-Blacklist; keine
Erkennung von Werbung, Spam, rechtlich heiklen oder unseriösen Inhalten.
- **L3 — Auto-Publish ohne Klassifikation**: geplante PMs werden vom Cron
veröffentlicht, ohne dass eine inhaltliche Bewertung stattgefunden hat.
- **L4 — Uneinheitlicher Prozess-Start**: das Bestätigungs-Modal existiert nur
in der Detailansicht, nicht beim Bearbeiten/Erstellen.
- **L5 — Kein Audit**: KI-Entscheidungen wären ohne `ki_audits` nicht
nachvollziehbar (DSGVO / Nachweispflicht).
## Zielarchitektur
```
Einreichung (Formular ODER API)
SubmissionService.submit() ← ein einziger Funnel
├─ Hard-Filter: Blacklist (synchron, deterministisch)
ClassificationService.classify() ← KI (Claude), mit Fallback
├─ Rot → status=rejected, Begründung an Autor
├─ Gelb → status=review (manuelle Queue, „äußerste Fälle")
└─ Grün → Veröffentlichungspfad (sofort / geplant)
ki_audits (vollständiges Audit-Log jeder KI-Entscheidung)
+
press_releases.classification / classified_at
+
(später) content_score / content_tier
```
Kernregeln:
- Formular **und** API rufen ausschließlich `SubmissionService.submit()` auf.
Die API darf `status` nicht mehr frei setzen; `published` ist über die API
nie erreichbar.
- Re-Klassifikation bei jeder Änderung einer PM (Konzept §15.1: „Bei Änderung
der PM wird neu klassifiziert").
- Schwellen/Verhalten sind konfigurierbar (`config/scoring.php`), damit sie
ohne Code-Änderung kalibriert werden können.
---
## Entwicklungsschritte
### Phase 0 — Prozess-Start im UI vereinheitlichen — ✅ erledigt (11.06.2026)
**Ziel:** Das bestehende Einreichungs-Modal erscheint überall dort, wo eine PM
eingereicht wird — auch beim Bearbeiten (Button „Speichern & zur Prüfung") und
beim Erstellen (Button „Zur Prüfung senden"). Reiner UI-Schritt, kein Backend.
**Umsetzung:** Das Modal `confirm-submit-review` (rechtliche Hinweise, Quota,
Bestätigungs-Checkboxen) wird in Customer-Show, -Create **und** -Edit über
`flux:modal.trigger` geöffnet; bestätigt ruft es wie geplant
`submitForReview` bzw. `saveAndSubmit`/`save('review')`.
**Umfang:**
- Modal `confirm-submit-review` aus `show.blade.php` in eine wiederverwendbare
Blade-/Volt-Komponente extrahieren (z. B.
`resources/views/livewire/components/press-release-submit-modal.blade.php`).
- In `edit.blade.php` den `wire:confirm`-Button durch einen
`flux:modal.trigger` ersetzen; bei Bestätigung wird wie bisher
`saveAndSubmit` ausgeführt (erst speichern, dann einreichen).
- In `create.blade.php` denselben Modal-Trigger vor `save('review')` schalten.
- Texte/Checkboxen identisch zur Detailansicht halten (rechtliche Hinweise,
Quota, Bestätigungen).
**Betroffene Dateien:** `resources/views/livewire/customer/press-releases/{show,edit,create}.blade.php`,
neue Komponente unter `resources/views/livewire/components/`.
**Done:** In allen drei Ansichten (Customer: show/edit/create) öffnet derselbe
Bestätigungsdialog; Tests für Edit/Create-Submit grün.
**Admin-Editor (`/admin/press-releases/`) — bewusst ausgenommen:** Der
Admin-Editor behält sein bisheriges Verhalten (`wire:confirm`). Begründung: Wenn
eine PM beim Admin landet, hat die vorgelagerte User-Prüfung (Einreichungs-Modal
im Customer-Flow) bereits stattgefunden. Der Admin braucht hier keinen erneuten
Bestätigungsdialog. Stattdessen erhält der Admin-Editor in einer späteren Phase
einen zusätzlichen **„Prüfung"-Button** (siehe Phase 4: On-Demand-KI-Prüfung).
**Tests:** Volt-Tests, die das Öffnen des Modals und den Submit-Pfad
(`saveAndSubmit` / `save('review')`) abdecken.
### Phase 1 — Einreichungs-Funnel & API-Absicherung — ✅ erledigt (11.06.2026)
**Ziel:** Beide Einreichungsstellen laufen durch einen Pfad; die API-Lücke (L1)
wird geschlossen. Noch ohne KI — nur Vereinheitlichung.
**Umsetzung:**
- `PressReleaseService::submitForReview()` ist der alleinige Einreichungs-Einstieg
(Web-Formular **und** API rufen dieselbe Methode). Auf eine separate
`SubmissionService`-Fassade wurde bewusst verzichtet — `submitForReview` ist
bereits die stabile Schnittstelle, in die Phase 3 die KI-Klassifikation
einhängt.
- API: `status` aus den Validierungsregeln von `StorePressReleaseRequest` und
`UpdatePressReleaseRequest` entfernt (inkl. ungenutzter Imports). `store()`
erzeugt jetzt **immer** `PressReleaseStatus::Draft`; ein übergebenes `status`
wird ignoriert. `update()` kann den Status nicht mehr setzen.
- Neue explizite Route `POST /api/v1/press-releases/{pressRelease}/submit`
(`press-releases.submit`) → `PressReleaseController::submit()`. Diese prüft
`press-releases:write`, Ownership und erlaubt nur `draft`/`rejected`
(sonst 409); ruft `submitForReview()`; eine `BlacklistViolationException`
wird als **422** mit Begründung zurückgegeben. Damit greifen Blacklist-,
Quota- und Status-Log-Behandlung auch für API-Einreichungen.
- `published` ist über die API weiterhin nie erreichbar (nur Admin-Aktion/Cron).
**Betroffene Dateien:** `app/Http/Controllers/Api/V1/PressReleaseController.php`,
`app/Http/Requests/Api/V1/{Store,Update}PressReleaseRequest.php`,
`routes/api.php`. `PressReleaseService` blieb unverändert (Schnittstelle
ausreichend).
**Done:** API kann keine PM mehr ungeprüft in `review` heben; eine PM-Einreichung
verhält sich über API und Formular identisch.
**Tests:** `tests/Feature/Api/V1/PressReleaseSubmitApiTest.php` (Create erzeugt
immer Draft & ignoriert `status`; Submit-Route hebt nach `review`, zählt Quota,
schreibt Log; Blacklist → 422 + `rejected`; fehlende Schreibrechte → 403;
bereits in `review` → 409; fremde PM → 403). Alle grün.
### Phase 2 — Datenmodell & Audit — ✅ erledigt (11.06.2026)
**Ziel:** Persistenz für Klassifikation und vollständiges KI-Audit. Noch ohne
Verhaltensänderung (alle Felder nullable).
**Umsetzung:**
- Migration `add_classification_to_press_releases`: Spalten `classification`
(string(16), nullable, nach `status`) und `classified_at` (timestamp,
nullable) plus Index auf `classification`. `content_score`/`content_tier`
bewusst **erst in Phase 5** (siehe Datenmodell-Anhang).
- Migration `create_ki_audits_table`: `press_release_id` (FK, cascade),
`type`, `provider` (nullable), `model` (nullable), `result` (nullable),
`reason` (text, nullable), `raw_response` (json, nullable),
`created_at` (useCurrent), Index `(press_release_id, type)`. Kein
`updated_at` (append-only Log).
- Model `App\Models\KiAudit` (`$timestamps = false`, Cast `raw_response`
array, Konstanten `TYPE_CLASSIFICATION`/`TYPE_CONTENT_SCORE`, Relation
`pressRelease()`), Relation `PressRelease::kiAudits()` (neueste zuerst).
- Enum `App\Enums\PressReleaseClassification` (Green/Yellow/Red + `label()`),
in `PressRelease::casts()` für `classification` registriert.
- `config/scoring.php`: Anbieter/Modell-Auswahl (`CLASSIFICATION_PROVIDER`,
Default `deterministic`, `CLASSIFICATION_MODEL`), Timeout, Grün-Verzögerung
(Minuten), Gelb→manuelle-Queue-Flag sowie Content-Score-Stufen-Schwellen
(Phase 5).
- `KiAuditFactory` mit States `classification()` / `contentScore()`.
**Betroffene Dateien:** zwei neue Migrationen unter `database/migrations/`,
`app/Models/PressRelease.php`, `app/Models/KiAudit.php`,
`app/Enums/PressReleaseClassification.php`, `config/scoring.php`,
`database/factories/KiAuditFactory.php`.
**Done:** Migrationen laufen; Modelle/Casts/Relation vorhanden; keine bestehende
Funktionalität verändert (alle Felder nullable).
**Tests:** `tests/Feature/PressReleaseClassificationModelTest.php` (Enum-/
Datetime-Cast, Default null, `kiAudits()`-Reihenfolge, `raw_response`-Array-Cast
+ Relation, Cascade-Delete). Alle grün.
### Phase 3 — KI-Klassifikation (Red Flag) — ✅ erledigt (11.06.2026)
**Ziel:** Echte inhaltliche Prüfung jeder Einreichung; Ergebnis asynchron als
Klassifikation gespeichert und auditiert.
**Entscheidungen (11.06.2026):** Erster aktiver Anbieter ist **OpenAI** (Key/
Budget vorhanden); Anthropic/Gemini folgen über dieselbe Treiber-Schnittstelle.
Klassifikation läuft **asynchron über die Queue** (synchron wäre später nicht
handelbar). Zum Testen ohne Dauer-Worker gibt es einen Drain-Befehl.
**Umsetzung:**
- **Provider-agnostische Treiber-Architektur** unter
`app/Services/PressRelease/Classification/`:
- Interface `Contracts\ClassificationDriver::classify(PressRelease): ClassificationResult`.
- `ClassificationResult` (Value Object: Enum-Klassifikation, `reasons[]`,
`provider`, `model`, `rawResponse`, `reasonText()`).
- `Drivers\OpenAiClassificationDriver` — OpenAI Chat-Completions via
`Http`-Client, liest `config/services.openai` (Key/URL/Modell/Timeout),
erzwingt `response_format: json_object` und parst
`{classification, reasons[]}`. Wirft bei fehlendem Key / HTTP-Fehler /
ungültigem JSON.
- `Drivers\DeterministicClassificationDriver` — Blacklist → Rot/Grün
(nie Gelb), als Fallback ohne externe API.
- `ClassificationManager` (Laravel-Manager) löst den Treiber aus
`config('scoring.classification.provider')` auf
(`createOpenaiDriver`/`createDeterministicDriver`).
- **Asynchroner Job** `app/Jobs/ClassifyPressRelease` (Queue `classification`,
`tries=3`): klassifiziert über den aktiven Treiber, bei Ausfall **Fallback**
auf den deterministischen Treiber (mit `Log::warning`), schreibt
`press_releases.classification`/`classified_at` und einen `ki_audits`-Eintrag
(inkl. `provider`/`model`/`reason`/`raw_response`).
- **Einbindung in den Funnel:** `PressReleaseService::submitForReview()` stößt
nach dem synchronen Blacklist-Hard-Filter und dem Statuswechsel den Job an
(`ClassifyPressRelease::dispatch(...)->onQueue('classification')`). Greift für
Formular **und** API (gemeinsamer Einstieg aus Phase 1).
- **Drain-Befehl** `php artisan classification:work` (Option `--once`): arbeitet
die Queue einmalig ab und beendet sich (`queue:work --stop-when-empty`) — zum
Testen ohne permanenten Worker.
- **Konfig:** `config/scoring.php` Default-Provider auf `openai` gesetzt
(`CLASSIFICATION_PROVIDER`); Modell leer ⇒ `config('services.openai.model')`.
- **Test-Isolation:** `phpunit.xml` erzwingt `CLASSIFICATION_PROVIDER=deterministic`
und leeren `OPENAI_API_KEY`, damit die Suite keine echten OpenAI-Calls macht;
der OpenAI-Pfad wird gezielt mit `Http::fake()` getestet.
**Noch offen (bewusst):** Re-Klassifikation bei jeder PM-Änderung (Update über
Formular/API) ist noch **nicht** verdrahtet — Phase 3 klassifiziert beim
Einreichen. Nachzuziehen, wenn das Status-Routing (Phase 4) steht. Anthropic-/
Gemini-Treiber + SDK folgen separat.
**Betroffene Dateien:** `app/Services/PressRelease/Classification/*`,
`app/Jobs/ClassifyPressRelease.php`,
`app/Console/Commands/RunClassificationQueue.php`,
`app/Services/PressRelease/PressReleaseService.php`, `config/scoring.php`,
`phpunit.xml`.
**Done:** Jede Einreichung (Formular + API) stößt asynchron eine Klassifikation
an, erzeugt einen `ki_audits`-Eintrag; bei KI-Ausfall greift der deterministische
Fallback nachvollziehbar. Status-Routing folgt in Phase 4.
**Tests:** `tests/Feature/PressReleaseClassificationJobTest.php` (OpenAI grün/gelb
mit `Http::fake`, Fallback bei HTTP-500, deterministisch Rot bei Blacklist,
Dispatch auf Queue `classification` via `Queue::fake`). Alle grün; volle Suite
416 grün (2 vorbestehende WIP-Failures unverändert).
### Phase 4 — Routing, Auto-Publish & Review-Queue — ✅ erledigt (11.06.2026)
**Ziel:** Die Klassifikation steuert den Status. Manuelle Prüfung nur noch bei
Gelb.
**Umsetzung:**
- **Routing im Job** über `PressReleaseService::routeByClassification()`
(vom `ClassifyPressRelease`-Job nach dem Klassifizieren aufgerufen):
- **Rot**`reject(..., source: 'ki')`: `status=rejected`, KI-Begründung per
Mail an den Autor (`PressReleaseRejected`, wie bei Blacklist).
- **Gelb** → keine Aktion, bleibt `review` (manuelle Admin-Queue).
- **Grün**`autoPublishGreen()`: ohne Termin sofort veröffentlichen,
optional mit Sicherheitsfenster `scoring.classification.green_delay_minutes`
(über `published_at`-Override); mit zukünftigem `scheduled_at` bleibt die PM
in `review` und der Scheduler publiziert zum Termin.
- Greift nur, solange die PM noch `review` ist (manuelle Admin-Eingriffe haben
Vorrang). `publish()` erhielt einen `?Carbon $publishedAtOverride`-Parameter,
`reject()` einen `string $source`-Parameter.
- **Scheduler** `PublishScheduledPressReleases`: Kandidaten-Query um
`where('classification', 'green')` erweitert — nur **grüne** fällige PMs
werden automatisch publiziert; gelbe warten immer auf den Admin. Geplante
Termine werden weiterhin respektiert.
- **Admin-Review-Queue:** Index- und Show-Ansicht zeigen ein KI-Klassifikations-
Badge (grün/gelb/rot); der Index hat einen **Klassifikations-Filter**
(`classificationFilter`, inkl. URL-Param, Active-Chip, Reset) — damit „nur
Gelb" filterbar. Die Show-Ansicht blendet im Review-Block den **KI-Hinweis**
(Begründung aus dem jüngsten `ki_audits`-Eintrag) ein.
**Test-Isolation (wichtig):** Da Tests mit `sync`-Queue den Job inline ausführen,
wurde der Klassifikations-Job in den „submit→review"-Tests via `Queue::fake()`
entkoppelt (Workflow, PublishModal, API-Submit). Die Scheduler-Tests setzen jetzt
`classification = green` für Publish-Kandidaten; neuer Test: fällige **gelbe** PM
bleibt `review`.
**Betroffene Dateien:** `app/Services/PressRelease/PressReleaseService.php`,
`app/Jobs/ClassifyPressRelease.php`,
`app/Console/Commands/PublishScheduledPressReleases.php`, Admin-Views
`resources/views/livewire/admin/press-releases/{index,show}.blade.php`.
**Done:** Grüne PMs gehen automatisch live (sofort/zum Termin), rote werden
abgelehnt + Autor benachrichtigt, nur gelbe landen in der manuellen Queue; Admin
sieht Klassifikation + KI-Begründung und kann nach Gelb filtern.
**Tests:** Routing in `PressReleaseClassificationJobTest` (Rot→rejected+Mail,
Grün-sofort→published+Mail, Grün-geplant→bleibt review, Gelb→bleibt review);
Scheduler in `PressReleaseSchedulingTest` (grün fällig→published, gelb
fällig→review); Admin-UI in `PressReleaseIndexPhase8bTest` (KI-Badge,
Klassifikations-Filter). Volle Suite 423 grün (2 vorbestehende WIP-Failures).
**Admin „Prüfung"-Button (On-Demand-KI-Prüfung)** — ✅ erledigt (11.06.2026):
- Im Admin-Editor gibt es oben den Button **„Prüfung"**, der ein Modal
`admin-ki-check` öffnet: auswählbare Klassifikation (Content-Score als
„in Vorbereitung" deaktiviert) und ein **Anbieter-Override** (Konfiguriert /
OpenAI / Deterministisch).
- `runKiCheck()` dispatcht `ClassifyPressRelease` auf der Queue `classification`
**mit `route: false`** und optionalem `providerOverride`. Das ist eine
nachgelagerte Re-Check-Prüfung: sie aktualisiert nur `classification` +
`ki_audits`, **ohne** den Status zu ändern (kein Auto-Publish/Reject) — die
Entscheidung bleibt beim Admin (Ergebnis sichtbar in der Detailansicht).
- Dafür erhielt `ClassifyPressRelease` die Parameter `bool $route = true` und
`?string $providerOverride = null`.
**Tests:** `tests/Feature/Admin/AdminKiCheckTest.php` (Button/Modal sichtbar;
Dispatch mit `route=false` + Provider-Override; Abbruch ohne Auswahl;
Re-Check-Job aktualisiert Bewertung, lässt Status unverändert).
**Re-Klassifikation bei Änderung** (Konzept §15.1) — ✅ erledigt (11.06.2026):
- Neue Service-Methode `reclassifyIfClassified()`: dispatcht nur wenn die PM
bereits klassifiziert ist `ClassifyPressRelease` mit `route: false`
(Re-Check ohne Statusänderung).
- Eingehängt überall dort, wo Inhalt geändert wird, und nur bei tatsächlicher
Änderung von Titel/Text (`wasChanged(['title', 'text'])`):
Customer-Editor `save()`, Admin-Editor `save()`, API `update()`.
Beim Einreichen übernimmt weiterhin `submitForReview` die (routende)
Klassifikation.
**Tests:** `tests/Feature/PressReleaseReclassifyTest.php` (Service dispatcht nur
bei vorhandener Klassifikation; API-Update klassifiziert neu bei Text-Änderung,
nicht bei reiner Keyword-Änderung).
**Noch offen / Folgearbeiten:**
- **Live-Aktualisierung der Ansicht** nach Abschluss des Hintergrund-Jobs
(Polling/Event) wäre ein optionales UX-Upgrade; aktuell erscheint das Ergebnis
nach Reload/Navigation.
- **Content-Score-Option** im Prüfungs-Modal — ✅ mit Phase 5 aktiviert (s. u.).
### Phase 5 — Content-Score & Stufen — ✅ erledigt (11.06.2026)
**Ziel:** Qualitätsbewertung 0100 → Stufe Standard/Geprüft/Hochwertig
(Konzept-Update 2).
**Umsetzung:**
- **Datenmodell:** Migration `add_content_score_to_press_releases`
`content_score` (tinyint, nullable), `content_tier` (string, nullable, Index),
`scored_at`. Enum `App\Enums\PressReleaseContentTier`
(Standard/Geprueft/Hochwertig) mit `fromScore()` (Schwellen aus
`config/scoring.php`), `label()` und `isPubliclyBadged()` (Standard wird laut
Update 2 nicht beworben). In `PressRelease` als Cast registriert.
- **Schwellen** (`config/scoring.php`): Geprüft ≥ 60, Hochwertig ≥ 80 (Update 2),
kalibrierbar; plus Anbieter/Modell/Timeout für den Score.
- **Treiber-Architektur** unter `app/Services/PressRelease/ContentScore/`
analog zur Klassifikation: `Contracts\ContentScoreDriver`, `ContentScoreResult`,
`Drivers\OpenAiContentScoreDriver` (gewichtete Faktoren §15.2 als JSON
`{score, breakdown}`), `Drivers\DeterministicContentScoreDriver`
(regelbasierte Heuristik: Länge, Bild, Quelle, Headline, Vollständigkeit),
`ContentScoreManager`.
- **Job** `app/Jobs/ScorePressRelease` (Queue `classification`, Fallback auf
deterministisch): schreibt `content_score` + abgeleitete `content_tier` +
`scored_at` und `ki_audits` (type=content_score). Optionaler
`providerOverride`.
- **Berechnung** bei Einreichung (`submitForReview` dispatcht Klassifikation
**und** Score) und bei Inhaltsänderung (`rescoreIfScored()` in Customer-/
Admin-Editor und API-`update()`, analog zur Re-Klassifikation).
- **Anzeige:**
- Customer-Editor: Score-Panel (Punktzahl, Stufe, „noch X Punkte bis zur
nächsten Stufe") — der produktive Editor-Score laut Update 2.
- Admin-Index & -Show: Stufen-/Score-Badge (intern inkl. Punktzahl).
- Customer-Detailansicht: öffentliches Stufen-Badge (✓ Geprüft / ★ Hochwertig;
Standard ohne Badge).
- **Admin-Prüfungs-Modal:** Content-Score-Option aktiviert; `runKiCheck()`
dispatcht zusätzlich `ScorePressRelease`.
**Done:** Score wird bei Einreichung/Änderung berechnet, Stufe abgeleitet,
auditiert und überall sichtbar.
**Tests:** `tests/Feature/PressReleaseContentScoreTest.php` (Tier-Mapping,
öffentliche Badges, OpenAI-Score→Tier+Audit, Fallback, Dispatch bei Submit,
Re-Score nur wenn bereits bewertet); Editor-Panel in
`CustomerPressReleaseEditPhase7Test`; Stufen-Badge in `PressReleaseIndexPhase8bTest`;
Content-Score-Dispatch in `AdminKiCheckTest`. Volle Suite 440 grün.
**Noch offen / Folgearbeiten:**
- **Public Web-Frontend** (presseecho/businessportal24): Stufen-Badges in den
öffentlichen Listen/Detailseiten gemäß Update 2 ergänzen (bisher nur im
Portal/Backend und der Customer-Ansicht).
- **Score-History & Breakdown-Ansicht** (Publisher-Dashboard) und Boost-
Eligibilität (Abschnitt 16) sind eigene spätere Ausbaustufen.
### Phase 6 — Trust-Score (später)
Account-/Firmen-Ebene (Konzept §15.3): lockert die KI-Freigabe-Schwelle für
zuverlässige Publisher. Eigene spätere Ausbaustufe; hier nur als Ausblick
vermerkt.
---
## Datenmodell-Anhang (Zielzustand)
```
press_releases (Ergänzungen)
+ classification enum(green,yellow,red) NULL
+ classified_at timestamp NULL
+ content_score tinyint NULL (Phase 5)
+ content_tier enum(standard,gepruft,hochwertig) NULL (Phase 5)
ki_audits (neu)
- id
- press_release_id FK
- type enum(classification,content_score)
- provider string (z. B. anthropic)
- model string (z. B. claude-opus-4-8)
- result string/json
- reason text NULL
- raw_response json/longtext
- created_at timestamp
```
## Offene Entscheidungen
- **Anbieter & Modell** — ✅ entschieden (11.06.2026): Erster aktiver Anbieter
ist **OpenAI** (`CLASSIFICATION_PROVIDER=openai`, Modell aus
`config/services.openai`). Architektur provider-agnostisch; Anthropic/Gemini
folgen. Offen bleibt, ob später mehrere Anbieter parallel (Primär + Fallback
jenseits des deterministischen) laufen sollen.
- **Synchron vs. Queue** — ✅ entschieden (11.06.2026): **Queue** (asynchron,
Queue-Name `classification`). Drain zum Testen: `php artisan classification:work`.
- **Dependency**: OpenAI-Treiber nutzt den nativen `Http`-Client (kein neues
Composer-Paket). Anthropic PHP-SDK (`anthropic-ai/sdk`) ist **freigegeben**;
für Gemini je ein offizielles/etabliertes SDK oder HTTP-Client bei Umsetzung
des Treibers.
- **Grün-Verzögerung**: 0 Min. (sofort) oder 510 Min. (Konzept-Option) als
Sicherheitsfenster — konfigurierbar über
`scoring.classification.green_delay_minutes`, Default noch festzulegen.
- **Gelb-Verhalten**: ausschließlich manuelle Queue, oder zusätzlich
automatische Benachrichtigung des Autors.
- **DSGVO**: Aufbewahrung/Anonymisierung der `raw_response` in `ki_audits`.
## Nächste Schritte
Phasen 05 sind umgesetzt (Suite grün). Es folgen:
1. **Launch-Block aus dem Decision-Update** (siehe Abgleich-Box oben):
Submit-Gate hinter Buchung, Slot-Verbrauch bei Veröffentlichung,
Tarif-/Zahlungs-Modul.
2. **Betrieb**: Queue-Worker für `classification` im Produktions-Setup
(Test-Drain: `php artisan classification:work`).
3. **Folgearbeiten**: Live-Aktualisierung des KI-Ergebnisses in der UI,
Stufen-Badges im öffentlichen Web-Frontend, Anthropic-/Gemini-Treiber.
4. **Phase 6**: Trust-Score (eigene Ausbaustufe).

View file

@ -0,0 +1,207 @@
Ich würde das Formular inhaltlich klarer machen und stärker gegen typische Bildrechts-Probleme absichern. Der aktuelle Ansatz ist gut, aber bei Presseportalen würde ich etwas präziser zwischen **Urheberrecht**, **Nutzungsrecht**, **Personenrechten** und **Quelle/Nachweis** unterscheiden.
## **1. Lizenztyp-Auswahl überarbeiten**
Aktuell hast du:
- Eigene Aufnahme
- CC-Lizenz
- Kommerzielle Lizenz erworben
- Einwilligung des Urhebers
- Sonstiges
Ich würde daraus eher machen:
### **Empfohlene Lizenztypen**
|**Option**|**Wann verwenden?**|
|---|---|
|**Eigene Aufnahme**|Der Uploadende hat das Bild selbst erstellt|
|**Vom Urheber / Fotografen freigegeben**|Direkte schriftliche Erlaubnis liegt vor|
|**Agentur-/Stockbild-Lizenz**|Bild wurde z. B. über Adobe Stock, Shutterstock, Getty etc. lizenziert|
|**Creative-Commons-Lizenz**|Bild steht unter CC BY, CC BY-SA, CC0 etc.|
|**Presse-/PR-Bild mit Nutzungsfreigabe**|Bild wurde z. B. von Unternehmen, Veranstaltern, Agenturen oder Pressestellen bereitgestellt|
|**Gemeinfrei / Public Domain / CC0**|Keine oder sehr weitgehende Nutzungsbeschränkungen|
|**Sonstige Lizenz / Sondervereinbarung**|Freitext erforderlich|
„Einwilligung des Urhebers“ würde ich nicht als eigenen Lizenztyp stehen lassen, sondern eher als **„Vom Urheber/Fotografen freigegeben“** formulieren. Das ist verständlicher.
## **2. Bei Creative Commons zusätzliche Felder anzeigen**
Wenn jemand **CC-Lizenz** auswählt, sollte nicht nur „CC-Lizenz“ gespeichert werden. Du brauchst genauer:
- CC0
- CC BY
- CC BY-SA
- CC BY-ND
- CC BY-NC
- CC BY-NC-SA
- CC BY-NC-ND
Wichtig: **NC** bedeutet „nicht-kommerziell“ und kann für ein Presseportal problematisch sein, besonders wenn die Seite werbefinanziert ist oder kommerziell betrieben wird. **ND** erlaubt keine Bearbeitung, also eventuell auch keinen Beschnitt als Titelbild.
Daher würde ich bei CC-Lizenzen automatisch Hinweise anzeigen, zum Beispiel:
Diese Lizenz kann Einschränkungen enthalten. Bitte prüfen, ob kommerzielle Nutzung, Bearbeitung und Veröffentlichung als Titelbild erlaubt sind.
## **3. „Urheber / Fotograf“ verpflichtender machen**
Das Feld **Urheber / Fotograf** sollte in den meisten Fällen Pflicht sein, außer vielleicht bei eigener Aufnahme, wenn der Name des Uploadenden automatisch hinterlegt wird.
Besser wäre:
**Urheber / Fotograf / Rechteinhaber**
Denn nicht immer ist der Fotograf auch der Rechteinhaber. Bei Agenturen oder Unternehmen können die Rechte woanders liegen.
## **4. „Copyright / Quelle“ klarer benennen**
Das Feld „Copyright / Quelle“ ist etwas gemischt. Ich würde es aufteilen oder klarer formulieren:
- **Copyright-Hinweis / Bildnachweis**
- **Quelle des Bildes**
- **Lizenz- oder Nachweis-URL**
Beispiel:
**Bildnachweis, wie er angezeigt werden soll**
`Foto: Max Mustermann / Beispiel GmbH`
**Quelle / Fundstelle**
`https://...`
**Lizenz-URL / Nachweis-URL**
`https://creativecommons.org/licenses/by/4.0/` oder Link zur Stocklizenz / Presseseite
So vermeidest du, dass jemand nur „Internet“ oder „Google“ einträgt.
## **5. Datei-Upload um Pflicht-Hinweise ergänzen**
Beim Upload würde ich neben Dateityp und Größe noch einen kurzen Warnhinweis ergänzen:
Bitte laden Sie nur Bilder hoch, für die Sie die erforderlichen Nutzungsrechte besitzen. Bilder aus Google, Social Media, Messenger-Gruppen oder fremden Websites dürfen nicht ohne ausdrückliche Erlaubnis verwendet werden.
Das ist sehr hilfreich, weil genau dort viele Fehler passieren.
## **6. Personenrechte besser abfragen**
Dein Feld „Einwilligung abgebildeter Personen liegt vor“ ist gut, aber ich würde es differenzierter machen.
Statt nur einem Schalter:
**Sind Personen auf dem Bild erkennbar?**
- Nein
- Ja, und die Einwilligung liegt vor
- Ja, aber es handelt sich um eine öffentliche Veranstaltung / redaktionelle Berichterstattung
- Unsicher
Wenn „Ja“ oder „Unsicher“ gewählt wird, kannst du einen Hinweis anzeigen:
Bei erkennbaren Personen können zusätzlich Persönlichkeits- oder Datenschutzrechte betroffen sein. Bitte stellen Sie sicher, dass eine Veröffentlichung zulässig ist.
Der aktuelle Toggle „Einwilligung liegt vor“ ist gut, aber er setzt voraus, dass der Nutzer selbst erkennt, ob Personenrechte relevant sind.
## **7. Property Rights / Marken / Kunstwerke ergänzen**
Neben Personen sind auch diese Fälle kritisch:
- Logos und Marken
- Kunstwerke
- private Innenräume
- Gebäude, Architektur, Museen
- Fahrzeuge mit Kennzeichen
- Veranstaltungsplakate oder Screenshots
Ich würde daher ergänzen:
**Enthält das Bild erkennbare Marken, Kunstwerke, geschützte Werke oder private Orte?**
- Nein
- Ja, Rechte/Nutzung sind geklärt
- Unsicher
Das schützt besonders bei PR-, Event- und Pressebildern.
## **8. Rechtebestätigung präziser formulieren**
Aktuell:
Ich bestätige, dass ich zur Nutzung dieses Bildes berechtigt bin und alle Rechte geklärt sind.
Ich würde es ausführlicher und rechtlich klarer machen:
Ich bestätige, dass ich über die erforderlichen Rechte zur Veröffentlichung dieses Bildes verfüge. Dies umfasst insbesondere Urheberrechte, Nutzungsrechte, Persönlichkeitsrechte abgebildeter Personen sowie gegebenenfalls Marken-, Eigentums- oder sonstige Rechte Dritter. Ich bin berechtigt, das Bild auf diesem Presseportal veröffentlichen zu lassen.
Optional zusätzlich:
Mir ist bewusst, dass ich für fehlerhafte oder unvollständige Angaben verantwortlich bin.
Je nach Portal kannst du das etwas freundlicher formulieren, aber inhaltlich sollte es klar sein.
## **9. Lizenznachweis als Datei-Upload ermöglichen**
Sehr sinnvoll wäre ein optionaler Upload:
**Nachweis / Freigabe hochladen**
Zum Beispiel:
- Lizenzbestätigung
- E-Mail-Freigabe
- Model Release
- Vertrag
- Screenshot der Lizenzseite
- Pressefreigabe
Das muss nicht öffentlich sichtbar sein, aber intern gespeichert werden.
## **10. Sichtbarer Bildnachweis im Frontend**
Ich würde im Formular klar anzeigen:
**Dieser Bildnachweis wird öffentlich angezeigt:**
`Foto: Max Mustermann / Beispiel GmbH`
Viele Nutzer verstehen besser, was sie eintragen müssen, wenn sie sehen, wo es später erscheint.
## **11. Meine empfohlene Struktur**
So würde ich das Formular aufbauen:
1. **Bild hochladen**
2. **Titel / Alt-Text**
3. **Bildnachweis, öffentlich sichtbar**
4. **Urheber / Fotograf / Rechteinhaber**
5. **Lizenztyp**
6. **Lizenzdetails je nach Auswahl**
7. **Quelle / Lizenz-URL**
8. **Personen auf dem Bild?**
9. **Marken, Kunstwerke oder private Orte sichtbar?**
10. **Nachweis/Freigabe hochladen**
11. **Rechte bestätigen**
Zusätzlich würde ich **Alt-Text** ergänzen. Nicht primär wegen Recht, sondern wegen Barrierefreiheit und SEO.
## **Konkrete Anpassung deiner Felder**
Aus deinem Screenshot würde ich ändern:
**„Copyright / Quelle“**→ **„Öffentlicher Bildnachweis“**
**„Urheber / Fotograf“**→ **„Urheber / Fotograf / Rechteinhaber“**
**„Lizenz-URL optional“**→ **„Quelle oder Lizenznachweis-URL“**
**„Einwilligung abgebildeter Personen liegt vor“**
→ ersetzen durch Auswahl:
**„Sind erkennbare Personen abgebildet?“**
**„Bildrechte bestätigt“**
→ Pflicht-Checkbox mit ausführlicher Bestätigung.
## **Besonders wichtig**
Ich würde **„Sonstiges“ nie ohne Pflicht-Freitext erlauben**. Wenn jemand „Sonstiges“ wählt, sollte zwingend erklärt werden müssen, warum die Nutzung erlaubt ist.
Außerdem würde ich bei riskanten Angaben wie **CC-NC**, **CC-ND**, **Unsicher**, **Sonstiges** oder fehlender Lizenz-URL entweder eine Warnung anzeigen oder eine manuelle Prüfung durch die Redaktion auslösen.

View file

@ -1,12 +1,14 @@
> **Stand der Doku**: 21.05.2026 — dieses Konzept beschreibt den Zielzustand
> der Plattform. Mehrere Themen (KI-Vorprüfung, externe Meldungen, Tarife,
> Magic-Link-Flow, Korrektur-Hinweise, Score-System) sind konzeptuell hier
> ausgearbeitet, aber noch nicht oder nur rudimentär gebaut. Welcher Teil
> in welchem Zustand ist, steht jeweils in einer **„IST-Stand"-Box** am
> Anfang des betroffenen Abschnitts.
> **Stand der Doku**: 11.06.2026 — dieses Konzept beschreibt den Zielzustand
> der Plattform. Umgesetzt sind inzwischen die KI-Prüfung (§1, §15.1/15.2)
> und Bilder/Lizenzen (§2); offen bleiben externe Meldungen, Magic-Link-Flow,
> Korrektur-Hinweise und Trust-Score. Welcher Teil in welchem Zustand ist,
> steht jeweils in einer **„IST-Stand"-Box** am Anfang des Abschnitts.
>
> **Für Tarife/Credits (§810) gilt das
> [`Decision-Update Preisstruktur & Veröffentlichungs-Flow`](../Decision-Update%20Preisstruktur%20&%20Ver%C3%B6ffentlichungs-Flow.md).**
>
> Aktueller Code-vs-Konzept-Abgleich: [`docs/STATUS-ABGLEICH-USER-PANEL.md`](../STATUS-ABGLEICH-USER-PANEL.md).
@ -14,14 +16,21 @@
## 1. KI-Freigabe-Workflow für Pressemitteilungen
> **IST-Stand 21.05.2026**: Die hier beschriebene KI-Vorpruefung ist noch
> nicht implementiert. Aktuell laeuft beim Submit zur Pruefung lediglich ein
> Blacklist-Check (`PressReleaseService::submitForReview` wirft
> `BlacklistViolationException` bei Treffern). Die Freigabe selbst erfolgt
> manuell durch einen Admin/Editor ueber die Admin-PM-Show-Page (Status:
> `draft → review → published | rejected | archived`).
> Der hier beschriebene Drei-Stufen-Workflow mit KI-Klassifikation,
> JSON-Antwort und Logging ist ein Phase-2/3-Thema.
> **IST-Stand 11.06.2026**: Der Drei-Stufen-Workflow ist **umgesetzt**
> (Detail-Doku: `Entwicklungsplan KI-Pruefung und Veroeffentlichung.md`,
> Phasen 05):
>
> - Jede Einreichung (Formular + API) laeuft durch den Blacklist-Hard-Filter
> und wird anschliessend asynchron KI-klassifiziert (Rot/Gelb/Gruen,
> OpenAI-Treiber mit deterministischem Fallback, Queue `classification`).
> - Routing: Rot → `rejected` + Mail mit Begruendung, Gelb → manuelle
> Admin-Queue, Gruen → Auto-Publish (sofort oder zum geplanten Termin).
> - Jede Entscheidung wird in `ki_audits` protokolliert (Provider, Modell,
> Begruendung, Raw-Response); Re-Klassifikation bei Titel-/Text-Aenderung.
> - Zusaetzlich umgesetzt: Content-Score 0100 → Stufe (§15.2).
>
> Offen: Trust-Score (§15.3), Live-Anzeige des Ergebnisses ohne Reload,
> DSGVO-Aufbewahrungsregel fuer `raw_response`.
### Ziel
@ -90,19 +99,19 @@ KI-Prüfungen müssen nachvollziehbar sein, dürfen aber nicht unbegrenzt und un
## 2. Bilder & Lizenzen
> **IST-Stand 21.05.2026**: Der Bild-Upload ist nur teilweise umgesetzt.
> Aktuell:
> **IST-Stand 11.06.2026**: Lizenz-/Rechteerfassung und Titelbild sind
> umgesetzt (Phase 8F8H + Umbau 10./11.06., Detail-Doku:
> `Umsetzung Pressemitteilung Bearbeitung Titelbild Veroeffentlichung.md`,
> Fachvorgabe: `Lizenztyp Bildupload.md`):
>
> - Nur Quelle „Eigenes Bild hochladen". Stock und KI sind nicht angebunden.
> - Im `press-release-images-manager` werden bisher nur `title` und
> `copyright` als Freitext erfasst — die im folgenden geforderten
> Pflichtfelder (Urheber, Lizenz-Typ, Lizenz-URL, Personen-Einwilligung,
> Rechte-Bestaetigung) sind in Phase 8H eingeplant.
> - Variantenbildung (`thumb` / `medium` / `large`) erfolgt automatisch
> ueber `App\Services\Image\ImageService`.
> - `is_preview`-Flag im Modell `PressReleaseImage` ist da; jede PM kann
> genau ein Vorschaubild haben. Default-SVG-Platzhalter fuer PMs ohne
> Titelbild sind in Phase 8F/8G in Planung.
> - Ein **Titelbild pro PM** (Cover-Variante 1280×580, Original wird nach
> Verarbeitung geloescht) oder SVG-Platzhalter aus dem zentralen Set
> (`App\Enums\PressReleasePlaceholder`, `PressReleaseCoverImage`-Resolver).
> - Vollstaendiges Rechteformular: Urheber, 7 Lizenztypen, Lizenzdetails,
> Lizenz-/Quell-URL, Personen- und Sachrechte-Status, interne Notizen,
> Rechte-Bestaetigung; bedingte Pflichtfelder + Risikohinweise.
> - Nur Quelle „Eigenes Bild hochladen". **Stock und KI sind nicht
> angebunden** (weiterhin offen, ebenso der KI-Wasserzeichen-Check).
### Upload-Workflow
@ -515,19 +524,24 @@ Eigene Statistiken trennen:
## 8. Preismodell Tarife (überarbeitet)
> **IST-Stand 21.05.2026**: Das Tarif- und Credit-System ist noch nicht
> **⚠️ Ueberschrieben (11.06.2026)**: Die Abschnitte 8, 9 und 10 sind durch
> das [`Decision-Update Preisstruktur & Veröffentlichungs-Flow`](../Decision-Update%20Preisstruktur%20&%20Ver%C3%B6ffentlichungs-Flow.md)
> ersetzt. Wichtigste Aenderungen: Kontingente Pro 25 / Agency 60 (statt
> 60/150), Jahrespreis als „2 Monate gratis", Bonus-Credits aus der
> Tarif-Tabelle entfernt, Launch-Credits auf Extra-PM / Boost /
> PDF-Nachweis reduziert, Slot-Verbrauch erst bei Veroeffentlichung.
> Der folgende Text bleibt als urspruengliche Zielvorstellung erhalten.
>
> **IST-Stand 11.06.2026**: Das Tarif- und Credit-System ist noch nicht
> implementiert. Es gibt:
>
> - Eine Tabelle `user_payment_options` (mit Pivot zu `companies`).
> - Eine Tabelle `invoices` (aktuell + Legacy ueber `legacy_invoices`).
> - Keine Tarif-Stufen, kein Kontingent-Counter pro User, keine
> Stripe-Anbindung, kein Auto-Refill.
>
> Phase 8 (siehe `docs/PHASE-8-USER-PANEL-PLAN.md`) bereitet die
> Kontingent-Anzeige im Veroeffentlichungs-Modal vor — mit zwei
> temporaeren Spalten auf `users` (`press_release_quota`,
> `press_release_quota_used_this_month`) als Stub, damit das echte
> Tarif-Modell spaeter ohne UI-Aenderung andocken kann.
> - Keine Tarif-Stufen, keine Stripe-Anbindung, kein Auto-Refill.
> - Den Phase-8-**Quota-Stub** auf `users` (`press_release_quota`,
> `press_release_quota_used_this_month`) samt Kontingent-Anzeige im
> Veroeffentlichungs-Modal — zaehlt aktuell beim Einreichen, laut
> Decision-Update kuenftig bei Veroeffentlichung.
### Grundlogik
@ -854,6 +868,11 @@ retention_policies
## Abschnitt 15: Score-Architektur
> **IST-Stand 11.06.2026**: §15.1 (Klassifikations-Score Rot/Gelb/Grün) und
> §15.2 (Content-Score 0100 → Stufe) sind **umgesetzt** — siehe
> `Entwicklungsplan KI-Pruefung und Veroeffentlichung.md` (Phasen 25).
> §15.3 (Trust-Score) ist weiterhin offen (Phase 3).
Die Plattform arbeitet mit drei voneinander unabhängigen Scores. Sie haben unterschiedliche Funktionen, werden unterschiedlich berechnet und an unterschiedlichen Stellen wirksam. Die Trennung ist zentral, weil sie unterschiedliche Datenmodelle und Update-Logiken betrifft.
### 15.1 Klassifikations-Score (Eintritts-Filter)

View file

@ -0,0 +1,277 @@
# Umsetzung Pressemitteilung bearbeiten: Titelbild, Rechte, Veröffentlichung
Stand: 11.06.2026
Diese Notiz dokumentiert die zuletzt umgesetzten Anpassungen an der Bearbeitung von Pressemitteilungen im User Panel und an den parallel genutzten Admin-Formularen.
## Betroffener Bereich
- Customer Create/Edit: `resources/views/livewire/customer/press-releases/create.blade.php`
- Customer Edit: `resources/views/livewire/customer/press-releases/edit.blade.php`
- Admin Create/Edit: `resources/views/livewire/admin/press-releases/create.blade.php`, `resources/views/livewire/admin/press-releases/edit.blade.php`
- Show/Index (Customer + Admin) für die Termin-Anzeige: `resources/views/livewire/customer/press-releases/{show,index}.blade.php`, `resources/views/livewire/admin/press-releases/{show,index}.blade.php`
- Model (Zeitzonen-Konstante + Accessoren): `app/Models/PressRelease.php`
- Titelbild-Manager: `resources/views/livewire/components/press-release-images-manager.blade.php`
- Platzhalter-Auswahl: `resources/views/livewire/components/press-release-placeholder-picker.blade.php`
- Platzhalter-Dateien: `public/images/press-release-placeholders`
- Layout-CSS: `resources/css/shared/hub-components.css`
## Titelbild-Platzhalter
Die Platzhalter für Pressemitteilungs-Titelbilder wurden erweitert.
- Die Varianten werden über `App\Enums\PressReleasePlaceholder` verwaltet.
- Die SVG-Dateien liegen lokal unter `public/images/press-release-placeholders`.
- Der Picker lädt die lokalen Varianten in `resources/views/livewire/components/press-release-placeholder-picker.blade.php`.
- Das Modal wurde für mehr Varianten verbreitert und mit einer scrollbaren Grid-Darstellung versehen.
Ziel: Wenn noch kein eigenes Titelbild vorhanden ist, kann ein optisch passender Platzhalter gewählt werden.
## Titelbild-Upload
Der Upload wurde auf ein einzelnes Titelbild begrenzt.
- Es kann vorerst nur ein Titelbild pro Pressemitteilung hochgeladen werden.
- Wenn ein Titelbild vorhanden ist, wird die Platzhalter-Card ausgeblendet.
- Das Upload-Formular wird ebenfalls ausgeblendet, solange ein Titelbild existiert.
- Das vorhandene Titelbild wird in einer eigenen Bild-Card angezeigt.
- In der Bild-Card werden Titel, Größe und Bildnachweis/Copyright angezeigt.
- Das Titelbild kann gelöscht werden; danach erscheinen Platzhalter und Upload-Formular wieder.
Das Upload-Formular ist einklappbar:
- Im Ausgangszustand erscheint nur der Hinweis, dass ein Titelbild fehlt.
- Über „Eigenes Titelbild hochladen" wird das Formular geöffnet.
- Über „Abbrechen" wird das Formular wieder geschlossen und zurückgesetzt.
## Bildverarbeitung und Speicherverhalten
Die Bildverarbeitung wurde auf die Titelbild-Nutzung optimiert.
- Erlaubte Formate: JPG, PNG, WebP.
- Maximale Dateigröße: 16 MB.
- Nicht previewfähige Dateien wie TIFF lösen keine Livewire-Preview-Exception mehr aus; sie werden über die Validierung abgefangen.
- Für Pressemitteilungsbilder wird eine Cover-Variante erzeugt: 1280 x 580 px.
- Der kanonische Bildpfad zeigt auf die Cover-Variante.
- Das Original wird nach der Variantenerzeugung gelöscht, um Speicherplatz zu sparen.
- Breite und Höhe in der Oberfläche beziehen sich auf die gespeicherte Cover-Version, nicht auf das Original.
Relevante Datei: `app/Services/Image/ImageService.php`.
## Lizenz- und Rechteformular
Das Formular wurde an die Vorgaben aus `docs/user-admin/Lizenztyp Bildupload.md` angepasst.
Erfasste Felder:
- Titel / Alt-Text über das bestehende `title`-Feld.
- Öffentlicher Bildnachweis über das bestehende `copyright`-Feld.
- Urheber / Fotograf / Rechteinhaber über `author`.
- Lizenztyp über `license_type`.
- Lizenzdetails über `license_detail`.
- Lizenz-URL über `license_url`.
- Quelle / Fundstelle über `source_url`.
- Personenrechte über `people_rights_status`.
- Marken, Kunstwerke, geschützte Werke oder private Orte über `property_rights_status`.
- Interne Notizen über `rights_notes`.
- Rechtebestätigung über `rights_confirmed_at`.
Lizenztypen:
- Eigene Aufnahme
- Creative-Commons-Lizenz
- Agentur-/Stockbild-Lizenz
- Vom Urheber / Fotografen freigegeben
- Presse-/PR-Bild mit Nutzungsfreigabe
- Gemeinfrei / Public Domain / CC0
- Sonstige Lizenz / Sondervereinbarung
Wichtige Regeln:
- „Bitte wählen" ist der Ausgangszustand.
- „Unsicher" wurde aus den Auswahlmöglichkeiten entfernt.
- Am Ende muss der Uploadende die Verantwortung für die Rechte bestätigen.
- Creative-Commons-Lizenzen erfassen zusätzlich die konkrete CC-Variante.
- CC-, Stock-/Agentur- und Presse-/PR-Lizenzen verlangen eine Lizenz- oder Nachweis-URL.
- „Sonstige Lizenz / Sondervereinbarung" verlangt einen Pflicht-Freitext.
- Risikohinweise werden bei eingeschränkten oder unklaren Lizenzfällen angezeigt.
Relevante Dateien:
- `app/Enums/ImageLicenseType.php`
- `app/Models/PressReleaseImage.php`
- `database/migrations/2026_06_10_154249_add_rights_detail_fields_to_press_release_images_table.php`
- `resources/views/livewire/components/press-release-images-manager.blade.php`
## Veröffentlichung
Die Veröffentlichungs-Box wurde vereinfacht.
Sichtbar sind nur noch:
- Sofort nach Freigabe
- Geplanter Termin
Embargo / Sperrfrist wurde in den Formularen aus der Oberfläche entfernt, weil es aktuell noch keine sinnvolle Anwendung im User-Flow gibt.
Technisches Verhalten:
- `scheduled_at` bleibt erhalten und wird weiterhin gespeichert.
- `embargo_at` wird in den betroffenen Formularen nicht mehr gesetzt und beim Speichern auf `null` geführt.
- Für den geplanten Termin wird `flux:date-picker` für das Datum verwendet.
- Für die Uhrzeit wird `flux:time-picker` verwendet.
- Intern werden Datum und Uhrzeit wieder zu `scheduledAt` kombiniert.
- Der geplante Termin muss mindestens 5 Minuten in der Zukunft liegen.
- Bei zu frühem Termin wird direkt ein Fehler gesetzt; beim Speichern greift die Validierung ebenfalls.
Betroffene Properties:
- `scheduledDate`
- `scheduledTime`
- `scheduledAt`
## Zeitzonen-Handling für geplante Veröffentlichung
Stand: 11.06.2026 (nachgezogen)
Die Anwendung läuft serverseitig in UTC (`config/app.php``timezone = 'UTC'`).
Geplante Termine werden aber von Redaktion und Kunden in **deutscher Zeit**
gedacht. Vorher wurde die im Formular eingegebene Uhrzeit naiv als UTC
interpretiert, wodurch die Veröffentlichung um den Berlin-Offset (im Sommer
+2 h) verschoben stattfand. Das ist behoben.
Grundprinzip:
- Eingabe und Anzeige erfolgen in **Europe/Berlin**.
- Gespeichert wird weiterhin **UTC**.
- Wichtig: Laravel konvertiert beim Speichern **nicht** automatisch nach UTC.
Deshalb wird der eingegebene Wert beim Parsen explizit als Berlin
interpretiert und mit `->utc()` umgewandelt; beim Laden wird umgekehrt von
UTC nach Berlin gewandelt.
Zentrale Stelle:
- `App\Models\PressRelease::DISPLAY_TIMEZONE` (`'Europe/Berlin'`) ist die
Single Source of Truth.
- `PressRelease::scheduledAtLocal()` und `PressRelease::embargoAtLocal()`
liefern die Termine in der Anzeige-Zeitzone für alle Views.
Verhalten in den Formularen (Customer **und** Admin, Create **und** Edit):
- Helper `scheduledAtUtc()`: parst die naiven Eingabefelder als Berlin und
gibt den UTC-Zeitpunkt für die Speicherung zurück.
- Die „mind. 5 Minuten in der Zukunft"-Prüfung läuft jetzt über eine
zeitzonenbewusste Closure-Regel statt über die naive `after:`-Regel.
- Beim Bearbeiten (`mount`) wird `scheduled_at` von UTC nach Berlin gewandelt,
bevor Datum/Uhrzeit in die Eingabefelder gefüllt werden.
Anzeige (lokalisiert auf Berlin):
- Customer-Show/-Index und Admin-Show/-Index: geplanter Termin und Embargo
werden über `scheduledAtLocal()` / `embargoAtLocal()` ausgegeben.
Bewusst (noch) nicht umgestellt:
- `published_at`, `created_at` und die Status-Log-Zeitstempel werden weiterhin
in UTC angezeigt. Eine vollständige Anzeige-Lokalisierung dieser Felder ist
als Folgeschritt vorgesehen.
## Aufräumung: Scheduling-Logik und Queries
Im Zuge der Zeitzonen-Umstellung wurden zwei Altlasten in allen vier
PM-Formularen bereinigt:
- **Doppelte Termin-Synchronisierung entfernt:** Die Termin-Logik lief vorher
sowohl im generischen `updated()`-Hook als auch in den spezifischen
`updated{PublishMode,ScheduledDate,ScheduledTime}`-Hooks also doppelt.
`updated()` enthält jetzt nur noch die generische Re-Validierung bereits
fehlerhafter Felder; die Synchronisierung liegt ausschließlich in den
spezifischen Hooks.
- **Redundante Queries reduziert:** Im Customer-Edit wird die geladene
Pressemitteilung pro Request memoisiert (`mount()`, `with()` und `save()`
greifen sonst jeweils mit einer eigenen Query auf dieselbe PM zu).
## Responsive Layout
Das Layout der Pressemitteilungsformulare wurde entkoppelt von der globalen Sidebar-Logik.
Die globale Flux-Sidebar bleibt im stabilen Standardzustand:
- `flux:sidebar sticky stashable`
- Header- und Toggle-Sichtbarkeit weiter über `lg:hidden`
Das eigentliche Formularlayout wird über eigene Klassen gesteuert:
- `.pr-editor-layout`
- `.pr-editor-side`
Regel in `resources/css/shared/hub-components.css`:
```css
@media (min-width: 1180px) {
.pr-editor-layout {
grid-template-columns: minmax(0, 1fr) 360px;
}
.pr-editor-side {
position: sticky;
top: 1rem;
}
}
```
Verhalten:
- Unter 1180 px steht die rechte Formularbox unterhalb des Hauptinhalts.
- Ab 1180 px steht die rechte Formularbox wieder rechts.
- Die rechte Box wird ab 1180 px sticky.
- Die globale linke Navigation bleibt davon unberührt.
## Button-Varianten
Sekundäre `variant="ghost"`-Buttons in Blade-Views wurden breit auf `variant="filled"` umgestellt, weil die Ghost-Buttons optisch zu wenig als Buttons erkennbar waren.
Umfang:
- Alle Blade-Views unter `resources/views` wurden auf verbleibende `variant="ghost"` geprüft.
- Markdown-Dokumentation wurde dabei nicht als UI geändert.
## Tests und Verifikation
Ergänzte bzw. angepasste Tests:
- `tests/Feature/PressReleasePlaceholderTest.php`
- `tests/Feature/PressReleaseImageLicenseTest.php`
- `tests/Feature/CustomerPressReleaseSchedulingFormTest.php`
- `tests/Feature/Admin/AdminPressReleaseSchedulingTest.php`
Für die Zeitzonen-Umstellung zusätzlich angepasst (Assertions auf
Berlin-Werte umgestellt):
- `tests/Feature/PressReleaseShowPhase8aTest.php`
- `tests/Feature/Admin/AdminPressReleaseShowTest.php`
Zuletzt erfolgreich ausgeführte Checks:
- `php artisan test --compact tests/Feature/CustomerPressReleaseSchedulingFormTest.php tests/Feature/Admin/AdminPressReleaseSchedulingTest.php tests/Feature/Admin/AdminPressReleaseShowTest.php tests/Feature/PressReleaseShowPhase8aTest.php tests/Feature/PressReleaseIndexPhase8bTest.php`
- `vendor/bin/pint --dirty --format agent`
- Volle Suite: 400 passed (die zwei roten Tests `PressReleaseImageApiTest` und
`CustomerPressReleaseCreatePhase7Test` sind vorbestehende, unabhängige WIP-
Failures per Stash-Test verifiziert, dass sie auch ohne diese Änderungen
scheitern).
Vorher zusätzlich grün gelaufen:
- `php artisan test --compact tests/Feature/PressReleasePlaceholderTest.php tests/Feature/PressReleaseImageLicenseTest.php tests/Feature/CustomerPressReleaseEditPhase7Test.php`
- Phase-8-nahe Show-/Index-/Attachment-/Admin-Tests.
## Bewusst noch nicht umgesetzt
- Optionaler Upload von Lizenznachweisen oder Freigabe-Dokumenten.
- Reaktivierung des separaten Anhang-Managers.
- Manuelle redaktionelle Prüf-Workflows für riskante Lizenzfälle.
- Vollständige Medienbibliothek statt einzelnes Titelbild.
- Frontend-Ausgabe des Bildnachweises außerhalb der Bearbeitungsoberfläche, sofern noch nicht separat angebunden.
- Anzeige-Lokalisierung von `published_at`, `created_at` und Status-Log-Zeitstempeln (aktuell weiterhin UTC).
- Klärung/Anpassung der Auto-Publish-Policy: geplante PMs (Status `review` + fälliger `scheduled_at`) werden vom Scheduler-Command automatisch veröffentlicht ohne separate redaktionelle Freigabe. Wird in einem eigenen Schritt geprüft.

View file

@ -1,13 +1,16 @@
# Checkliste User Backend
Stand: 21.05.2026 (Phase 7 abgeschlossen, Phase 8 in Planung)
Stand: 11.06.2026 (Phase 7 + Phase 8 + KI-Pruef-Pipeline abgeschlossen; naechster Block: Zahlung/Tarife + Veroeffentlichungs-Flow laut Decision-Update)
Diese Checkliste fasst den aktuellen Stand des User Backends zusammen und trennt erledigte Punkte von den naechsten sinnvollen Umsetzungsschritten.
Begleitende Dokumente:
- `docs/STATUS-ABGLEICH-USER-PANEL.md` — Konzept-vs-Code-Abgleich pro Page.
- `docs/PHASE-8-USER-PANEL-PLAN.md` — Detail-Plan der naechsten Sub-Paeckchen.
- `docs/Decision-Update Preisstruktur & Veröffentlichungs-Flow.md` — verbindliche Launch-Entscheidungen zu Tarifen, Kontingenten und Flow.
- `docs/user-admin/Entwicklungsplan KI-Pruefung und Veroeffentlichung.md` — KI-Klassifikation + Content-Score (Phasen 05 erledigt).
- `docs/user-admin/Umsetzung Pressemitteilung Bearbeitung Titelbild Veroeffentlichung.md` — Titelbild/Lizenzformular/Zeitzonen-Umbau (10./11.06.).
- `docs/PHASE-8-USER-PANEL-PLAN.md` — Phase-8-Plan (abgeschlossen).
- `dev/frontend/hub-flux/19-PHASE-7-PRESS-RELEASE-FORM.md` — Phase-7-Abschluss.
- `dev/frontend/hub-flux/PROGRESS.md` — Tagebuch der Hub-Migration.
@ -71,42 +74,83 @@ Begleitende Dokumente:
- [x] Smooth-Scrolling zum ersten Validation-Fehler nach Save (`resources/js/portal-form-hooks.js`).
- [x] Pre-Submit-Check-Liste (`@computed presubmitChecks`) zeigt vor dem Einreichen offene Pflichtfelder und Empfehlungen.
## Phase 8 — User-Panel-Konsolidierung (in Planung)
## Phase 8 — User-Panel-Konsolidierung (abgeschlossen)
Vollstaendiger Plan: `docs/PHASE-8-USER-PANEL-PLAN.md`.
Vollstaendiger Plan: `docs/PHASE-8-USER-PANEL-PLAN.md`. Roadmap-Abschluss:
`dev/frontend/hub-flux/20-PHASE-8-USER-PANEL.md`.
- [ ] Show-Page-Luecken schliessen (Subtitle, Scheduling, Embargo, Boilerplate-Override) — Customer + Admin (8A).
- [ ] Listen-Indikatoren fuer geplante Veroeffentlichung und Embargo (8B).
- [ ] Pressekontakt-Warn-Box in Sidebar-Card, wenn kein Kontakt gewaehlt (8C).
- [ ] Doku-Pflege: `docs/user-admin/*` an IST-Stand ziehen (8D, dieses Dokument).
- [ ] Firmen-Liste auf Mockup-Niveau (Counter-Strip, Saved-Views, Filter-Chips, Card/List-Toggle, Rollen-Legende) (8E).
- [ ] Set wiederverwendbarer SVG-Platzhalter fuer PM-Titelbilder + Auswahl-Modal (8F).
- [ ] Titelbild-Schema in `press_releases` (Default-Platzhalter pro PM, `PressReleaseCoverImage`-Resolver) (8G).
- [ ] FluxUI `flux:file-upload` im Image-Manager inkl. Pflichtfelder fuer Urheber, Lizenz-Typ, Lizenz-URL, Rechte-Bestaetigung (8H).
- [ ] Veroeffentlichungs-Modal mit rechtlichen Hinweisen + Kontingent-Anzeige (Customer) (8I).
- [ ] Kontingent-Stub im Datenmodell (Spalten auf `users`, monatlicher Reset-Command) als Vorbereitung fuer das Tarif-Modul (8J).
- [ ] Tests, Pint, Build, Roadmap-Update (8K).
- [x] Show-Page-Luecken schliessen (Subtitle, Scheduling, Embargo, Boilerplate-Override) — Customer + Admin (8A).
- [x] Listen-Indikatoren fuer geplante Veroeffentlichung und Embargo (8B).
- [x] Pressekontakt-Warn-Box in Sidebar-Card, wenn kein Kontakt gewaehlt (8C).
- [x] Doku-Pflege: `docs/user-admin/*` an IST-Stand ziehen (8D, dieses Dokument).
- [x] Firmen-Liste auf Mockup-Niveau (Counter-Strip, Saved-Views, Filter-Chips, Card/List-Toggle, Rollen-Legende) (8E) — Tests: `CustomerPressKitIndexPhase8eTest`, `CustomerPressKitCreatePhase8eTest`.
- [x] Set wiederverwendbarer SVG-Platzhalter fuer PM-Titelbilder + Auswahl-Modal (8F) — `App\Enums\PressReleasePlaceholder`, `<x-portal.press-release-placeholder>`, Picker `components.press-release-placeholder-picker`.
- [x] Titelbild-Schema in `press_releases` (`placeholder_variant`, deterministischer Default, `PressReleaseCoverImage`-Resolver, Hero in Customer-/Admin-Show) (8G).
- [x] Bild-Upload mit Lizenz-Pflichtfeldern (Urheber, Lizenz-Typ, Lizenz-URL bedingt, Personen-Einwilligung, Rechte-Bestaetigung) im Image-Manager (8H). Hinweis: Upload-Control bleibt `flux:input type=file` statt `flux:file-upload` (Stabilitaet); Lizenzerfassung vollstaendig.
- [x] Veroeffentlichungs-Modal mit rechtlichen Hinweisen (Platzhalter, anwaltlich zu pruefen) + Kontingent-Anzeige (Customer-Show) (8I).
- [x] Kontingent-Stub im Datenmodell (`users.press_release_quota` + `..._used_this_month`, Decrement in `submitForReview`, monatlicher `press-releases:reset-monthly-quota`-Command) (8J).
- [x] Tests, Pint, Build, Roadmap-Update (8K).
## KI-Pruef-Pipeline — Klassifikation & Content-Score (abgeschlossen 11.06.2026)
Vollstaendiger Plan mit Phasen-Details: `docs/user-admin/Entwicklungsplan KI-Pruefung und Veroeffentlichung.md`.
- [x] Einreichungs-Modal vereinheitlicht: `confirm-submit-review` in Customer-Show, -Create und -Edit (Phase 0).
- [x] API-Absicherung: `status` nicht mehr per API setzbar, eigene Submit-Route durch denselben Funnel (Phase 1).
- [x] Datenmodell: `press_releases.classification`/`classified_at`, `ki_audits`-Audit-Tabelle (Phase 2).
- [x] KI-Klassifikation Rot/Gelb/Gruen, asynchron ueber Queue `classification`, OpenAI-Treiber + deterministischer Fallback (Phase 3).
- [x] Status-Routing: Rot → abgelehnt + Mail, Gelb → manuelle Admin-Queue, Gruen → Auto-Publish (sofort/zum Termin); Scheduler publiziert nur gruene PMs (Phase 4).
- [x] Admin: KI-Badge + Klassifikations-Filter im Index, KI-Begruendung in der Show, On-Demand-„Pruefung"-Button mit Anbieter-Override.
- [x] Re-Klassifikation und Re-Score bei Titel-/Text-Aenderung (Customer, Admin, API).
- [x] Content-Score 0100 → Stufe Standard/Geprueft/Hochwertig inkl. Editor-Panel und Badges (Phase 5).
## Titelbild, Lizenzen & Termin-Handling (abgeschlossen 10./11.06.2026)
Details: `docs/user-admin/Umsetzung Pressemitteilung Bearbeitung Titelbild Veroeffentlichung.md`.
- [x] Upload auf ein Titelbild pro PM begrenzt; Cover-Variante 1280×580, Original wird nach Verarbeitung geloescht.
- [x] Lizenz-/Rechteformular nach `Lizenztyp Bildupload.md` erweitert (7 Lizenztypen, Personen-/Sachrechte-Status, Quelle, Notizen, Risikohinweise).
- [x] Veroeffentlichungs-Box vereinfacht: nur „Sofort nach Freigabe" und „Geplanter Termin"; Embargo aus der Form-UI entfernt (`embargo_at` bleibt im Schema).
- [x] Zeitzonen-Handling: Eingabe/Anzeige Europe/Berlin, Speicherung UTC (`PressRelease::DISPLAY_TIMEZONE`, `scheduledAtLocal()`).
- [x] PM-Editor-Layout responsive entkoppelt (`.pr-editor-layout`); Ghost-Buttons auf `filled` umgestellt.
## Naechster Block — Zahlung, Tarife & Veroeffentlichungs-Flow (Launch)
Verbindliche Entscheidungen: `docs/Decision-Update Preisstruktur & Veröffentlichungs-Flow.md`. Umsetzungsplan: `docs/PHASE-9-FLOW-UND-TARIFE-PLAN.md`.
- [ ] Gelb-Routing auf Direkt-Live umstellen (Entscheidung 12.06.: Gelb geht wie Gruen online, keine manuelle Queue; nur Rot wird abgelehnt).
- [ ] Tarif-Datenmodell + Checkout/Zahlung (Starter/Business/Pro/Agency, Einzel-PM 19 €, Jahrespreis „2 Monate gratis").
- [ ] Submit-Gate: „Speichern & zur Pruefung einreichen" hinter aktiver Buchung; „Speichern" bleibt immer frei.
- [ ] Slot-Verbrauch von Einreichung auf **Veroeffentlichung** umstellen (Rot = kein Slot-Verbrauch); Quota-Stub abloesen.
- [ ] Tageslimit je Tier (Business 2 / Pro 3 / Agency 5), gilt auch fuer Extra-PMs.
- [ ] Launch-Credits: Extra-PM, Boost (nur gruene PMs), Veroeffentlichungsnachweis-PDF; Credit-Anker 1 Credit = 1 €.
- [ ] Einzel→Abo-Bruecke (19 € Anrechnung innerhalb 30 Tagen).
- [ ] Rechtstexte im Einreichungs-Modal anwaltlich pruefen lassen (Platzhalter, Go-Live-Blocker).
- [ ] Queue-Worker fuer `classification` im Produktions-Setup verankern.
## Phase 2 / spaeter
- [ ] Vorab-KI-Pruefung, Redigieren/Nachbessern + Re-Check-Loop, Pruefzaehler und Credit-Overflow (Decision-Update §7).
- [ ] Magic-Link-Zugriff fuer Firmen-E-Mail-Adressen konzipieren und umsetzen.
- [ ] Separate `token_requests`-Tabelle fuer nicht-userbasierte Zugriffe anlegen.
- [ ] Zugriff per Firmen-E-Mail so begrenzen, dass nur passende Firmen und Pressemitteilungen sichtbar werden.
- [ ] Trust Score fuer User/Firmen konzipieren und im Admin Backend justierbar machen.
- [ ] Moderationslogik an Trust Score und Freigabeprozess anbinden.
- [ ] Aufbewahrungsfristen fuer Magic Links, Token Requests, API Logs und Statuslogs definieren und technisch absichern.
- [ ] Trust Score fuer User/Firmen konzipieren und im Admin Backend justierbar machen (KI-Plan Phase 6).
- [ ] Moderationslogik an Trust Score anbinden (Klassifikations-Routing existiert bereits).
- [ ] Stufen-Badges (Geprueft/Hochwertig) im oeffentlichen Web-Frontend ausgeben.
- [ ] Aufbewahrungsfristen fuer Magic Links, Token Requests, API Logs, Statuslogs und `ki_audits`-Raw-Responses (DSGVO) definieren und technisch absichern.
- [ ] Admin-editierbare Textvorlagen fuer neutrale Tombstone-/Entfernungs- und Systemtexte einbauen.
- [ ] API-Nutzungs-Log im User Backend sichtbar machen.
- [ ] Benachrichtigungen und Newsletter-Abos im Konto-Bereich ausbauen.
- [ ] Zahlungsarten und firmenbezogene Zahlungsoptionen im User Backend aktivieren.
- [ ] Credits, Tarife und Add-ons an ein echtes Preismodell anbinden.
- [ ] Statistikbereich fuer Firmen und Pressemitteilungen umsetzen.
- [ ] Medienbereich aus vorhandenen Pressemitteilungsbildern ableiten; spaeter echte Medienbibliothek pruefen.
- [ ] Team-/Rollenverwaltung fuer Firmen im User Backend ergaenzen.
- [ ] Anzeige-Lokalisierung von `published_at`, `created_at` und Status-Log-Zeitstempeln (aktuell UTC).
## Hinweise
- Phase 1 ist funktional abgeschlossen; Phase 7 (PM-Form-Refactor) ebenfalls — siehe Plan-Doku oben.
- Phase 8 fokussiert das User-Panel: Firmen-Liste auf Mockup-Niveau, PM-Titelbilder mit SVG-Platzhaltern und Veroeffentlichungs-Modal mit rechtlichen Hinweisen.
- Die Admin-Oberflaeche bekommt in Phase 8 nur die Phase-7-Parallelitaeten (Show-Page-Felder, Listen-Indikatoren); groessere Admin-Aenderungen kommen erst mit Phase 2.
- Phase 1, Phase 7 (PM-Form-Refactor), Phase 8 (User-Panel-Konsolidierung) und die KI-Pruef-Pipeline (Phasen 05) sind abgeschlossen — siehe Plan-Dokus oben.
- Fuer Preise, Kontingente und den Veroeffentlichungs-Flow gilt ausschliesslich das Decision-Update vom 11.06.2026; aeltere Tarif-Tabellen in `Konzept-Update 1` und im Relaunch-Konzept sind ueberschrieben.
- Der Quota-Stub (3 PM/Monat, zaehlt beim Einreichen) bleibt bis zum Tarif-Modul aktiv; die Umstellung auf Slot-Verbrauch bei Veroeffentlichung ist Teil des Launch-Blocks.
- Die KI-Klassifikation laeuft asynchron — in Produktion wird ein Queue-Worker fuer die Queue `classification` benoetigt (Test-Drain: `php artisan classification:work`).
- Anhaenge sind aktuell aus Sicherheitsgruenden deaktiviert, Tabelle und Komponente bleiben aber erhalten und werden in einem separaten Audit-Track reaktiviert.

View file

@ -1,9 +1,33 @@
# User-Admin: Zusammenhänge und relevante Daten
Stand: 2026-05-21 (aktualisiert nach Phase 7)
Stand: 2026-06-11 (aktualisiert nach Phase 8 + KI-Pipeline)
Diese Notiz beschreibt den User als fachlichen Mittelpunkt für die weitere Konzeption des Admin-User-Bereichs. Grundlage sind die aktuellen Models und Migrationen im Laravel-Projekt.
> **Was seit Phase 8 + KI-Pipeline dazugekommen ist (29.05.11.06.2026)**:
>
> - `press_releases`: `placeholder_variant` (SVG-Titelbild-Platzhalter, 8G),
> `classification`/`classified_at` (KI-Klassifikation Rot/Gelb/Grün),
> `content_score`/`content_tier`/`scored_at` (Content-Score).
> - `press_release_images`: Lizenz-/Rechtefelder `author`, `license_type`,
> `license_detail`, `license_url`, `source_url`, `people_rights_status`,
> `property_rights_status`, `rights_notes`, `persons_consent`,
> `rights_confirmed_at` (8H + Erweiterung 10.06.).
> - `users`: Quota-Stub `press_release_quota` +
> `press_release_quota_used_this_month` (8J; wird vom Tarif-Modul abgelöst).
> - Neue Tabelle `ki_audits` (Modell `KiAudit`, append-only Audit-Log jeder
> KI-Entscheidung) mit Relation `PressRelease::kiAudits()`.
> - Neue Enums: `PressReleasePlaceholder`, `ImageLicenseType`,
> `PressReleaseClassification`, `PressReleaseContentTier`.
> - Neue Services/Jobs: `PressReleaseCoverImage` (Cover-Resolver),
> Treiber-Architektur unter `Services/PressRelease/Classification/` und
> `…/ContentScore/`, Jobs `ClassifyPressRelease`/`ScorePressRelease`
> (Queue `classification`), Konfiguration in `config/scoring.php`.
> - Neue Commands: `press-releases:reset-monthly-quota` (Scheduler, 1. des
> Monats), `classification:work` (Queue-Drain zum Testen).
> - Zeitzonen-Konstante `PressRelease::DISPLAY_TIMEZONE` (Europe/Berlin) mit
> `scheduledAtLocal()`/`embargoAtLocal()` für alle Termin-Anzeigen.
> **Was sich seit dem ursprünglichen Stand (2026-05-05) geändert hat**:
>
> - Pressemitteilungen haben zusätzliche Felder: `subtitle`, `scheduled_at`,