PM-Tracking: Ereignis-Log fuer Aufrufe + Shares (press_release_events)

- press_release_events (type view/share, channel, ohne Personenbezug):
  Model/Enums/Factory, Cascade-Delete an der PM
- Detailaufruf loggt View-Event zusaetzlich zum Legacy-hits-Zaehler
  (bleibt bewusst einfacher Page-Request-Zaehler, User-Vorgabe 10.07.)
- POST press-release/{slug}/share (throttle 30/min, nur archiv-sichtbare
  PMs des Portals) loggt Teilen-Klicks je Kanal (LinkedIn/X/E-Mail/Copy)
- Kundenpanel-PM-Seite: neue Kachel Geteilt mit Kanal-Aufschluesselung
- lang: web.detail.views (de/en)
- Tests: Web/PressReleaseTrackingTest (7)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-10 09:56:42 +00:00
parent 80a37f8fcd
commit 644f860223
14 changed files with 392 additions and 0 deletions

View file

@ -0,0 +1,35 @@
<?php
namespace Database\Factories;
use App\Enums\PressReleaseEventType;
use App\Enums\PressReleaseShareChannel;
use App\Models\PressRelease;
use App\Models\PressReleaseEvent;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<PressReleaseEvent>
*/
class PressReleaseEventFactory extends Factory
{
/**
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'press_release_id' => PressRelease::factory(),
'type' => PressReleaseEventType::View,
'channel' => null,
];
}
public function share(?PressReleaseShareChannel $channel = null): static
{
return $this->state([
'type' => PressReleaseEventType::Share,
'channel' => $channel ?? fake()->randomElement(PressReleaseShareChannel::cases()),
]);
}
}