images: Datenmodell, Textarchiv, Herkunftsprüfung und gemeinsamer Uploader für Formular v2 (Bildkennzeichnung Block A)
- press_release_images: Kundenangabe/Portalkennzeichnung getrennt, Herkunftsbefund, Beweisoriginal, Snapshot-Pfade, published_ever_at, rules_version, Fokus/Letterbox; Bestand unangetastet - legal_texts (insert-only) mit img-confirm-v1 (alter Wortlaut), v2 (AGB 0.6), v3 (AGB 0.7, noch ohne Datum); image-rights:backfill-confirmations - image_rights_confirmations polymorph, insert-only, IP als versionierter HMAC; Löschung nur für nie veröffentlichte Uploads - ImageProvenanceInspector (Imagick/exif): IPTC, XMP, EXIF; algorithmicallyEnhanced nur Vermerk; unlesbare Datei = error - PressReleaseImageUploader: Original vor Derivaten, Hash-Bindung, Titelbild-Regel unter Sperre, Dateien bei Fehlern zurückgerollt; Admin-Upload ohne Bestätigung - ImageService: kein Rückfall auf die Quelldatei, og-Variante, Fokuspunkt und no_crop Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
b624f80d7f
commit
e9bdff3ad3
36 changed files with 2631 additions and 30 deletions
27
app/Enums/AiDeclarationSource.php
Normal file
27
app/Enums/AiDeclarationSource.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
/**
|
||||
* Woher die effektive KI-Kennzeichnung eines Bildes stammt (Decision-Update
|
||||
* S6): Angabe des Kunden, Vorbelegung aus ungesicherten Metadaten, geprüfte
|
||||
* Content Credentials oder eine Admin-Korrektur. Wird öffentlich im
|
||||
* Detailfenster genannt („Angabe des Einreichers" usw.).
|
||||
*/
|
||||
enum AiDeclarationSource: string
|
||||
{
|
||||
case Customer = 'customer';
|
||||
case IptcPrefill = 'iptc_prefill';
|
||||
case C2paVerified = 'c2pa_verified';
|
||||
case AdminCorrection = 'admin_correction';
|
||||
|
||||
public function publicLabel(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Customer => __('Angabe des Einreichers'),
|
||||
self::IptcPrefill => __('aus Metadaten der Datei vorbelegt, vom Einreicher bestätigt'),
|
||||
self::C2paVerified => __('aus geprüften Herkunftsdaten der Datei'),
|
||||
self::AdminCorrection => __('vom Portal nach Prüfung korrigiert'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,11 @@ namespace App\Enums;
|
|||
* Pflichtauswahl beim Bild-Upload (Decision-Update KI-Kennzeichnung,
|
||||
* 08.07.2026). Bewusste Über-Erfüllung: gelabelt wird jedes deklarierte
|
||||
* KI-Bild — auch stilisiert/abstrakt, nicht nur fotorealistische Deepfakes.
|
||||
*
|
||||
* Seit Formular v2 (Bildkennzeichnung, 22.09.2026) heißt die erste Option
|
||||
* „Ohne generative KI erstellt oder bearbeitet": Sie gilt auch für Logos,
|
||||
* Grafiken und Screenshots, nicht nur für Fotos (Feedback F11). Der
|
||||
* gespeicherte Wert `original` bleibt aus Kompatibilitätsgründen.
|
||||
*/
|
||||
enum AiImageDeclaration: string
|
||||
{
|
||||
|
|
@ -21,9 +26,9 @@ enum AiImageDeclaration: string
|
|||
public function label(): string
|
||||
{
|
||||
return match ($this) {
|
||||
self::Original => __('Originalfoto'),
|
||||
self::AiGenerated => __('KI-generiertes Bild'),
|
||||
self::AiEdited => __('KI-bearbeitetes Bild'),
|
||||
self::Original => __('Ohne generative KI erstellt oder bearbeitet'),
|
||||
self::AiGenerated => __('KI-generiert'),
|
||||
self::AiEdited => __('KI-bearbeitet (z. B. generative Füllung, KI-Retusche)'),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -41,6 +46,40 @@ enum AiImageDeclaration: string
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Rangfolge für die Portalregel „Kennzeichnung = max(geprüfter Befund,
|
||||
* Kundenangabe)" (Bildkennzeichnung A.4). Das ist eine bewusste
|
||||
* Portalregel und keine Aussage über den Wahrheitsgehalt: Ein
|
||||
* KI-erzeugter Bestandteil macht ein Bild nicht automatisch vollständig
|
||||
* KI-generiert (Feedback F11) — der Befund wird vorher fachlich
|
||||
* zugeordnet, erst dann greift die Mindestkennzeichnung.
|
||||
*/
|
||||
public function rank(): int
|
||||
{
|
||||
return match ($this) {
|
||||
self::Original => 0,
|
||||
self::AiEdited => 1,
|
||||
self::AiGenerated => 2,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Die strengere von zwei Kennzeichnungen nach rank(); null zählt als
|
||||
* „keine Angabe".
|
||||
*/
|
||||
public static function strictest(?self $a, ?self $b): ?self
|
||||
{
|
||||
if ($a === null) {
|
||||
return $b;
|
||||
}
|
||||
|
||||
if ($b === null) {
|
||||
return $a;
|
||||
}
|
||||
|
||||
return $b->rank() > $a->rank() ? $b : $a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionsliste für Radios/Selects: value => label.
|
||||
*
|
||||
|
|
|
|||
15
app/Enums/ConfirmationChannel.php
Normal file
15
app/Enums/ConfirmationChannel.php
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
/**
|
||||
* Über welchen Weg eine Bildrechte-Bestätigung abgegeben wurde
|
||||
* (Bildkennzeichnung A.2). `admin` ist kein Bestätigungskanal: Ein
|
||||
* Admin-Upload wartet auf die Kundenbestätigung per Magic-Link (E10).
|
||||
*/
|
||||
enum ConfirmationChannel: string
|
||||
{
|
||||
case Form = 'form';
|
||||
case Api = 'api';
|
||||
case MagicLink = 'magic_link';
|
||||
}
|
||||
14
app/Enums/CreditSource.php
Normal file
14
app/Enums/CreditSource.php
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
/**
|
||||
* Woher der Vorschlag für den Bildnachweis kam, den der Einreicher
|
||||
* übernommen oder geändert hat (Bildkennzeichnung A.1).
|
||||
*/
|
||||
enum CreditSource: string
|
||||
{
|
||||
case Customer = 'customer';
|
||||
case Metadata = 'metadata';
|
||||
case Api = 'api';
|
||||
}
|
||||
51
app/Enums/ImageProvenanceStatus.php
Normal file
51
app/Enums/ImageProvenanceStatus.php
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
/**
|
||||
* Ergebnisklasse der Herkunftsprüfung eines Bild-Uploads (Bildkennzeichnung
|
||||
* A.4, Feedback F02). Phase 1 liest nur ungesicherte IPTC/XMP/EXIF-Angaben,
|
||||
* kann also höchstens `unsigned_metadata` liefern. Die `validated_*`-Stufen
|
||||
* entstehen erst mit der C2PA-Signaturprüfung (Phase 2, Block I).
|
||||
*/
|
||||
enum ImageProvenanceStatus: string
|
||||
{
|
||||
/** Keine unterstützten Herkunftsdaten in der Datei. */
|
||||
case Absent = 'absent';
|
||||
|
||||
/** IPTC/XMP/EXIF gefunden — frei editierbar, nicht signiert. */
|
||||
case UnsignedMetadata = 'unsigned_metadata';
|
||||
|
||||
/** C2PA-Manifest, Signatur und Dateibindung geprüft, Aussteller in der Vertrauensliste. */
|
||||
case ValidatedTrusted = 'validated_trusted';
|
||||
|
||||
/** C2PA technisch geprüft, Aussteller nicht in der Vertrauensliste. */
|
||||
case ValidatedUntrusted = 'validated_untrusted';
|
||||
|
||||
/** C2PA vorhanden, Prüfung fehlgeschlagen (Signatur oder Bindung). */
|
||||
case Invalid = 'invalid';
|
||||
|
||||
/** Format oder Manifestversion nicht unterstützt. */
|
||||
case Unsupported = 'unsupported';
|
||||
|
||||
/** Technischer Fehler oder Zeitüberschreitung — Prüfung nicht abgeschlossen. */
|
||||
case Error = 'error';
|
||||
|
||||
/**
|
||||
* Nur ein vertrauenswürdig geprüfter Befund darf eine Kennzeichnung
|
||||
* erzwingen (Decision-Update E9).
|
||||
*/
|
||||
public function allowsLock(): bool
|
||||
{
|
||||
return $this === self::ValidatedTrusted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ob überhaupt Herkunftsangaben vorliegen, aus denen das Formular
|
||||
* vorbelegt werden kann.
|
||||
*/
|
||||
public function hasMetadata(): bool
|
||||
{
|
||||
return in_array($this, [self::UnsignedMetadata, self::ValidatedTrusted, self::ValidatedUntrusted], true);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue