User Panel: Phase-8-Abschluss, Titelbild/Lizenzen/Zeitzonen und KI-Pruef-Pipeline

Phase 8 (Rest) + Umbauten vom 10./11.06.:
- Ein Titelbild pro PM (Cover 1280x580), SVG-Platzhalter-Set + Picker,
  PressReleaseCoverImage-Resolver
- Lizenz-/Rechteformular nach "Lizenztyp Bildupload" (7 Lizenztypen,
  Personen-/Sachrechte-Status, bedingte Pflichtfelder, Risikohinweise)
- Veroeffentlichungs-Box vereinfacht (Embargo aus der Form-UI entfernt),
  geplante Termine in Europe/Berlin (Speicherung UTC, DISPLAY_TIMEZONE)
- Quota-Stub (users.press_release_quota) + monatlicher Reset-Command
- Einreichungs-Modal einheitlich in Show/Create/Edit; Ghost-Buttons auf
  filled; PM-Editor-Layout responsive entkoppelt (.pr-editor-layout)

KI-Pruef-Pipeline (Phasen 1-5 des Entwicklungsplans):
- API-Haertung: status nicht mehr per API setzbar, eigene Submit-Route
  durch denselben Funnel (Blacklist, Quota, Status-Log)
- Klassifikation Rot/Gelb/Gruen asynchron (Queue classification,
  OpenAI-Treiber + deterministischer Fallback), ki_audits-Audit-Log
- Routing: Rot -> rejected + Mail, Gelb -> Review-Queue, Gruen ->
  Auto-Publish; Scheduler publiziert nur gruene faellige PMs
- Content-Score 0-100 -> Stufe (Standard/Geprueft/Hochwertig) inkl.
  Editor-Panel und Badges; Re-Klassifikation/-Score bei Aenderung
- Admin: KI-Badge + Filter, On-Demand-Pruefung mit Anbieter-Override

Suite: 442 passed, 4 skipped.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-06-12 08:30:13 +00:00
parent 0efabaf446
commit a000238ca8
141 changed files with 5922 additions and 1001 deletions

View file

@ -0,0 +1,51 @@
<?php
namespace App\Enums;
/**
* Content-Score-Stufe (Außenkommunikation, Konzept Update 2).
*
* Der numerische Score (0100) bleibt plattform-intern; nach außen wird er auf
* drei Stufen gemappt. Schwellen sind über config/scoring.php kalibrierbar.
*/
enum PressReleaseContentTier: string
{
case Standard = 'standard';
case Geprueft = 'gepruft';
case Hochwertig = 'hochwertig';
/**
* Leitet die Stufe aus dem numerischen Score ab (kalibrierbar über
* config('scoring.content_score.tiers')).
*/
public static function fromScore(int $score): self
{
$tiers = config('scoring.content_score.tiers', []);
$hochwertig = (int) ($tiers['hochwertig'] ?? 80);
$gepruft = (int) ($tiers['gepruft'] ?? 60);
return match (true) {
$score >= $hochwertig => self::Hochwertig,
$score >= $gepruft => self::Geprueft,
default => self::Standard,
};
}
public function label(): string
{
return match ($this) {
self::Standard => 'Standard',
self::Geprueft => 'Geprüft',
self::Hochwertig => 'Hochwertig',
};
}
/**
* Ob die Stufe öffentlich als Vertrauensindikator gezeigt wird. Standard
* wird laut Update 2 bewusst nicht beworben (kein Badge/Label).
*/
public function isPubliclyBadged(): bool
{
return $this !== self::Standard;
}
}