resolveTenant($request); if (! $tenant) { return response()->json([ 'error' => 'tenant_context_missing', 'message' => 'Der Tenant-Kontext konnte nicht ermittelt werden.', ], Response::HTTP_UNAUTHORIZED); } $status = TenantOnboardingState::status($tenant); $settings = $tenant->settings ?? []; return response()->json([ 'steps' => [ 'admin_app_opened_at' => Arr::get($settings, 'onboarding.admin_app_opened_at'), 'primary_event_id' => Arr::get($settings, 'onboarding.primary_event_id'), 'selected_packages' => Arr::get($settings, 'onboarding.selected_packages'), 'branding_completed' => (bool) ($status['palette'] ?? false), 'tasks_configured' => (bool) ($status['packages'] ?? false), 'event_created' => (bool) ($status['event'] ?? false), 'invite_created' => (bool) ($status['invite'] ?? false), ], ]); } public function store(Request $request): JsonResponse { $tenant = $this->resolveTenant($request); if (! $tenant) { return response()->json([ 'error' => 'tenant_context_missing', 'message' => 'Der Tenant-Kontext konnte nicht ermittelt werden.', ], Response::HTTP_UNAUTHORIZED); } $payload = $request->validate([ 'step' => ['required', 'string'], 'meta' => ['array'], ]); $step = $payload['step']; $meta = $payload['meta'] ?? []; $settings = $tenant->settings ?? []; switch ($step) { case 'admin_app_opened': Arr::set($settings, 'onboarding.admin_app_opened_at', Carbon::now()->toIso8601String()); break; case 'event_created': Arr::set($settings, 'onboarding.primary_event_id', Arr::get($meta, 'event_id')); break; case 'package_selected': Arr::set($settings, 'onboarding.selected_packages', Arr::get($meta, 'packages')); break; case 'branding_configured': Arr::set($settings, 'onboarding.branding_set', true); break; case 'invite_created': Arr::set($settings, 'onboarding.invite_created_at', Carbon::now()->toIso8601String()); break; case 'completed': TenantOnboardingState::markCompleted($tenant, $meta); break; default: Log::info('[TenantOnboarding] Unbekannter Schritt gemeldet', [ 'tenant_id' => $tenant->id, 'step' => $step, ]); } if ($step !== 'completed') { $tenant->forceFill(['settings' => $settings])->save(); } return response()->json([ 'message' => 'Onboarding-Schritt aktualisiert.', ]); } private function resolveTenant(Request $request): ?Tenant { try { $tenantId = $request->attributes->get('tenant_id'); if ($tenantId) { return Tenant::query()->find($tenantId); } return TenantAuth::resolveTenant($request); } catch (\Throwable $exception) { Log::warning('[TenantOnboarding] Tenant konnte nicht ermittelt werden', [ 'error' => $exception->getMessage(), ]); return null; } } }