admin: Aktivitäts-Verlauf unter Reports ▸ Verlauf

Chronologisches Protokoll der Systemereignisse als neue Admin-Seite
(/admin/reports/activity) mit Filter nach Ereignistyp, Zeitraum und
Suche. Erfasst ab jetzt fortlaufend:

- Registrierungen inkl. Weg (Formular, Google, Magic-Link)
- Anmeldungen inkl. Weg (Passwort, Google, Magic-Link, Impersonation)
- PM-Statuswechsel mit Ergebnis/Begründung (zentral im Status-Log-Hook;
  KI-/Scheduler-Wechsel erscheinen als „System")
- Zahlungseingänge (Rechnungsspiegelung) und Credit-Aufladungen
- Formular-Eingänge: Kontakt, Rechtsanfrage, Widerruf, Kündigung,
  Newsletter-Anmeldung (Observer auf den Modellen)

Schreiben ist Best-Effort über den ActivityLog-Service — ein
fehlgeschlagener Verlaufseintrag bricht nie den fachlichen Ablauf.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-15 16:00:58 +00:00
parent a574898ca9
commit 3a11963990
19 changed files with 720 additions and 4 deletions

View file

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Aktivitäts-Verlauf für Admin ▸ Reports ▸ Verlauf: chronologisches
* Protokoll der Systemereignisse (Registrierung, Login, PM-Lebenszyklus,
* Zahlungen, Formular-Eingänge). Befüllt ab Einführung über ActivityLog.
*/
return new class extends Migration
{
public function up(): void
{
Schema::create('activity_events', function (Blueprint $table) {
$table->id();
$table->string('type', 40)->index();
$table->timestamp('occurred_at')->index();
// Bewusst ohne FK-Constraint: Der Verlauf soll User-Löschungen
// überleben und Inserts dürfen nie am Constraint scheitern.
$table->unsignedBigInteger('user_id')->nullable()->index();
// Anzeige-Snapshot des Handelnden (auch für Gäste, z. B.
// Kontaktformular ohne Konto).
$table->string('actor_label')->nullable();
$table->nullableMorphs('subject');
$table->string('description', 500);
$table->json('meta')->nullable();
});
}
public function down(): void
{
Schema::dropIfExists('activity_events');
}
};