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 ba0ee120f1
commit 48993f5506
141 changed files with 5922 additions and 1001 deletions

View file

@ -80,6 +80,12 @@ new class extends Component
Flux::toast(text: __('Anhang hochgeladen.'), variant: 'success');
}
public function removeNewFile(): void
{
$this->reset('newFile');
$this->resetErrorBag('newFile');
}
public function startEdit(int $attachmentId): void
{
$attachment = $this->getAttachment($attachmentId);
@ -252,16 +258,31 @@ new class extends Component
@if ($canEdit)
<form wire:submit="upload"
class="rounded-[5px] border border-dashed border-[color:var(--color-hub-soft-2)] bg-[color:var(--color-bg-elev)] p-4 space-y-3">
<div class="grid gap-3 sm:grid-cols-[1fr_auto] items-start">
<flux:field>
<flux:label>{{ __('Datei') }} <span class="text-[color:var(--color-err)]">*</span></flux:label>
<flux:input
type="file"
wire:model="newFile"
accept=".{{ implode(',.', $allowedExtensions) }}"
/>
<flux:error name="newFile" />
</flux:field>
<flux:file-upload
wire:model="newFile"
accept=".{{ implode(',.', $allowedExtensions) }}"
>
<flux:file-upload.dropzone
:heading="__('Datei hierher ziehen oder klicken')"
:text="strtoupper(implode(' · ', $allowedExtensions)).' · max. '.$maxMb.' MB'"
with-progress
inline
/>
</flux:file-upload>
<flux:error name="newFile" />
@if ($newFile)
<flux:file-item
:heading="$newFile->getClientOriginalName()"
:size="$newFile->getSize()"
>
<x-slot name="actions">
<flux:file-item.remove wire:click="removeNewFile" :aria-label="__('Datei entfernen')" />
</x-slot>
</flux:file-item>
@endif
<div class="flex justify-end">
<flux:button type="submit" variant="primary" icon="arrow-up-tray" wire:loading.attr="disabled">
<span wire:loading.remove wire:target="upload,newFile">{{ __('Hochladen') }}</span>
<span wire:loading wire:target="upload,newFile">{{ __('Lädt…') }}</span>
@ -308,7 +329,7 @@ new class extends Component
<flux:error name="editDescription" />
</flux:field>
<div class="flex justify-end gap-1 pt-1">
<flux:button size="xs" variant="ghost" wire:click="cancelEdit">{{ __('Abbrechen') }}</flux:button>
<flux:button size="xs" variant="filled" wire:click="cancelEdit">{{ __('Abbrechen') }}</flux:button>
<flux:button size="xs" variant="primary" icon="check" wire:click="updateAttachment">{{ __('Speichern') }}</flux:button>
</div>
</div>
@ -359,17 +380,17 @@ new class extends Component
<div class="flex flex-wrap items-center gap-1 mt-3 pt-3 border-t border-[color:var(--color-bg-rule)]">
@if ($attachment->url())
<flux:button size="xs" variant="ghost" icon="arrow-down-tray"
<flux:button size="xs" variant="filled" icon="arrow-down-tray"
href="{{ $attachment->url() }}" target="_blank" rel="noopener">
{{ __('Download') }}
</flux:button>
@endif
@if ($canEdit)
<flux:button size="xs" variant="ghost" icon="pencil-square" wire:click="startEdit({{ $attachment->id }})" :title="__('Bearbeiten')" />
<flux:button size="xs" variant="ghost" icon="arrow-up" wire:click="moveUp({{ $attachment->id }})" :title="__('Hoch')" />
<flux:button size="xs" variant="ghost" icon="arrow-down" wire:click="moveDown({{ $attachment->id }})" :title="__('Runter')" />
<flux:button size="xs" variant="filled" icon="pencil-square" wire:click="startEdit({{ $attachment->id }})" :title="__('Bearbeiten')" />
<flux:button size="xs" variant="filled" icon="arrow-up" wire:click="moveUp({{ $attachment->id }})" :title="__('Hoch')" />
<flux:button size="xs" variant="filled" icon="arrow-down" wire:click="moveDown({{ $attachment->id }})" :title="__('Runter')" />
<span class="flex-1"></span>
<flux:button size="xs" variant="ghost" icon="trash" wire:click="remove({{ $attachment->id }})"
<flux:button size="xs" variant="filled" icon="trash" wire:click="remove({{ $attachment->id }})"
wire:confirm="{{ __('Anhang wirklich entfernen?') }}" :title="__('Entfernen')" />
@endif
</div>