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>
59 lines
2.2 KiB
PHP
59 lines
2.2 KiB
PHP
<?php
|
||
|
||
namespace App\Services\Auth;
|
||
|
||
use App\Enums\ActivityType;
|
||
use App\Enums\RegistrationType;
|
||
use App\Models\User;
|
||
use App\Services\ActivityLog;
|
||
|
||
/**
|
||
* Legt verifizierte Kunden-Accounts an, die über einen vertrauenswürdigen Kanal
|
||
* entstehen – Magic-Link an eine hinterlegte E-Mail (ContactAccessService) oder
|
||
* Social-Login (SocialAuthService).
|
||
*
|
||
* Single Source of Truth für das lazy Provisioning: Account direkt aktiv mit
|
||
* customer-Rolle, die E-Mail gilt über den bestätigenden Kanal als verifiziert
|
||
* (Entscheidung 15.06.2026). Der Name fällt auf die E-Mail zurück, wenn keiner
|
||
* bekannt ist.
|
||
*/
|
||
class CustomerAccountProvisioner
|
||
{
|
||
public function __construct(
|
||
private readonly UserRolePermissionSyncService $roleSync,
|
||
private readonly ActivityLog $activityLog,
|
||
) {}
|
||
|
||
/**
|
||
* @param array<string, mixed> $extraAttributes Zusätzliche Spalten beim
|
||
* Anlegen (z. B. OAuth-Provider).
|
||
* @param string $channel Herkunft fürs Aktivitäts-Protokoll
|
||
* ('magic-link' oder 'google').
|
||
*/
|
||
public function provisionVerifiedCustomer(string $email, string $name, array $extraAttributes = [], string $channel = 'magic-link'): User
|
||
{
|
||
$user = User::create([
|
||
'name' => $name !== '' ? $name : $email,
|
||
'email' => $email,
|
||
'registration_type' => RegistrationType::Company->value,
|
||
'is_active' => true,
|
||
// Konto-Anlage ist hier immer nutzerinitiiert (Magic-Link-Anforderung
|
||
// bzw. OAuth-Login) – der Zeitpunkt gilt als DSGVO-Einwilligung.
|
||
'gdpr_consent_at' => now(),
|
||
...$extraAttributes,
|
||
]);
|
||
|
||
$user->forceFill(['email_verified_at' => now()])->save();
|
||
$this->roleSync->assignRoleAndSyncPermissions($user, 'customer');
|
||
|
||
$channelLabels = ['magic-link' => 'Magic-Link', 'google' => 'Google'];
|
||
$this->activityLog->record(
|
||
ActivityType::UserRegistered,
|
||
sprintf('%s (%s) wurde registriert — %s.', $user->name, $user->email, $channelLabels[$channel] ?? $channel),
|
||
user: $user,
|
||
meta: ['way' => $channel],
|
||
);
|
||
|
||
return $user;
|
||
}
|
||
}
|