Ablehnungskategorien live aus der DB (rejection_categories)

/richtlinien rendert jetzt alle aktiven Kategorien aus der neuen
rejection_categories-Tabelle (stabiler code als Anker, public_label/desc,
optionale Beispiele) statt der statischen K1-K6-Liste. Kategorien werden
nie geloescht, nur deaktiviert; neue Kategorien erscheinen ohne
Textaenderung und ohne neue AGB-Version (AGB par. 7 Abs. 3 verweist nicht
abschliessend). Seeder legt K1-K6 idempotent an; Versionszeile der Seite
kommt aus legal_documents. Go-Live-Checkliste um beide Seeder ergaenzt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-06 09:25:16 +00:00
parent 7510e7633e
commit 0bec71ffa5
8 changed files with 213 additions and 18 deletions

View file

@ -0,0 +1,36 @@
<?php
namespace Database\Factories;
use App\Models\RejectionCategory;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<RejectionCategory>
*/
class RejectionCategoryFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'code' => 'K'.fake()->unique()->numberBetween(1, 999),
'public_label' => fake()->sentence(3),
'public_desc' => fake()->sentence(12),
'examples' => null,
'severity' => 'rot',
'rubric_ref' => null,
'active' => true,
'sort_order' => fake()->numberBetween(0, 100),
];
}
public function inactive(): static
{
return $this->state(['active' => false]);
}
}

View file

@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Ablehnungskategorien (Rechtstexte-Architektur E3, Richtlinien v0.1):
* Die öffentliche Richtlinien-Seite rendert alle aktiven Kategorien live;
* Ablehnungs-Mails referenzieren den stabilen `code` (AGB § 7 Abs. 3).
* Kategorien werden nie gelöscht, nur deaktiviert — Ablehnungen der
* Vergangenheit müssen referenzierbar bleiben.
*/
return new class extends Migration
{
public function up(): void
{
Schema::create('rejection_categories', function (Blueprint $table) {
$table->id();
$table->string('code', 20)->unique(); // z. B. "K1", stabil
$table->string('public_label');
$table->text('public_desc');
$table->text('examples')->nullable(); // optional, öffentlich
$table->string('severity', 20)->default('rot'); // rot | gelb_hinweis
$table->string('rubric_ref', 80)->nullable(); // interne Rubrik, nie öffentlich
$table->boolean('active')->default(true);
$table->unsignedInteger('sort_order')->default(0);
$table->timestamps();
$table->index(['active', 'sort_order']);
});
}
public function down(): void
{
Schema::dropIfExists('rejection_categories');
}
};

View file

@ -22,6 +22,7 @@ class DatabaseSeeder extends Seeder
PlanSeeder::class,
PaymentOptionSeeder::class,
LegalDocumentSeeder::class,
RejectionCategorySeeder::class,
// CategorySeeder::class,
]);

View file

@ -0,0 +1,39 @@
<?php
namespace Database\Seeders;
use App\Models\RejectionCategory;
use Illuminate\Database\Seeder;
/**
* Start-Kategorien K1–K6 (Richtlinien v0.1, docs/legal). Idempotent über
* den stabilen `code`; bestehende Kategorien werden aktualisiert, nie
* gelöscht. Neue Kategorien sind neue Zeilen ohne AGB-Änderung.
*/
class RejectionCategorySeeder extends Seeder
{
public function run(): void
{
$categories = [
['K1', 'Rechtswidrige Inhalte', 'Inhalte, die gegen geltendes Recht verstoßen — etwa strafbare Inhalte, Verstöße gegen das Wettbewerbs- oder Heilmittelwerberecht, Angebote verbotener Produkte oder Dienstleistungen.'],
['K2', 'Explizite oder jugendgefährdende Inhalte', 'Pornografische, gewaltverherrlichende oder anderweitig jugendgefährdende Darstellungen in Text oder Bild.'],
['K3', 'Hass und Diskriminierung', 'Inhalte, die Menschen wegen ihrer Herkunft, Religion, Geschlechtsidentität, sexuellen Orientierung, Behinderung oder vergleichbarer Merkmale herabwürdigen oder zu Hass aufrufen.'],
['K4', 'Irreführung und Falschbehauptung', 'Nachweislich falsche Tatsachenbehauptungen, erfundene Studien oder Zitate, Täuschung über den Absender sowie gesundheits- oder finanzbezogene Heilsversprechen ohne Grundlage.'],
['K5', 'Rechte Dritter', 'Verletzung von Urheber-, Marken- oder Persönlichkeitsrechten — etwa fremde Texte oder Bilder ohne Lizenz, unbefugte Namensnennung, herabsetzende Aussagen über Dritte.'],
['K6', 'Kein Pressecharakter / Spam', 'Reine Werbe- oder Verkaufstexte ohne Nachrichtenwert, Keyword-Spam, automatisch generierte Masseninhalte ohne inhaltliche Substanz, Duplikate bereits veröffentlichter Mitteilungen.'],
];
foreach ($categories as $index => [$code, $label, $desc]) {
RejectionCategory::query()->updateOrCreate(
['code' => $code],
[
'public_label' => $label,
'public_desc' => $desc,
'severity' => 'rot',
'active' => true,
'sort_order' => ($index + 1) * 10,
],
);
}
}
}