validate([ 'tid' => 'required|string', 'vid' => 'required|string|max:64', 'sid' => 'required|string|max:64', 'type' => 'required|in:pageview,event', 'url' => 'nullable|string|max:2048', 'path' => 'nullable|string|max:2048', 'title' => 'nullable|string|max:512', 'referrer' => 'nullable|string|max:2048', 'event_name' => 'nullable|string|max:255', 'event_category' => 'nullable|string|max:255', 'event_action' => 'nullable|string|max:255', 'event_label' => 'nullable|string|max:255', 'event_value' => 'nullable|numeric', 'event_properties' => 'nullable|array', 'sr' => 'nullable|string|max:20', 'lang' => 'nullable|string|max:10', 'ua' => 'nullable|string|max:512', 'utm_source' => 'nullable|string|max:255', 'utm_medium' => 'nullable|string|max:255', 'utm_campaign' => 'nullable|string|max:255', 'utm_term' => 'nullable|string|max:255', 'utm_content' => 'nullable|string|max:255', 'ref_domain' => 'nullable|string|max:255', 'device' => 'nullable|string|max:20', 'browser' => 'nullable|string|max:50', 'browser_version' => 'nullable|string|max:20', 'os' => 'nullable|string|max:50', 'os_version' => 'nullable|string|max:20', 'time_on_page' => 'nullable|integer|min:0', 'is_new_session' => 'nullable|boolean', ]); $website = Website::where('tracking_id', $payload['tid']) ->where('is_active', true) ->first(); if (! $website) { return response()->json(['ok' => false], 404); } $now = Carbon::now(); $visitor = Visitor::updateOrCreate( [ 'website_id' => $website->id, 'uid' => $payload['vid'], ], [ 'last_seen_at' => $now, 'first_seen_at' => $now, 'device_type' => $payload['device'] ?? null, 'browser' => $payload['browser'] ?? null, 'browser_version' => $payload['browser_version'] ?? null, 'os' => $payload['os'] ?? null, 'os_version' => $payload['os_version'] ?? null, 'screen_resolution' => $payload['sr'] ?? null, 'language' => $payload['lang'] ?? null, ], ); if ($visitor->wasRecentlyCreated) { $visitor->update(['first_seen_at' => $now]); } $session = AnalyticsSession::firstOrCreate( ['uid' => $payload['sid']], [ 'website_id' => $website->id, 'visitor_id' => $visitor->id, 'started_at' => $now, 'entry_page' => $payload['path'] ?? $payload['url'] ?? null, 'ip_address' => $request->ip(), 'referrer_url' => $payload['referrer'] ?? null, 'referrer_domain' => $payload['ref_domain'] ?? null, 'utm_source' => $payload['utm_source'] ?? null, 'utm_medium' => $payload['utm_medium'] ?? null, 'utm_campaign' => $payload['utm_campaign'] ?? null, 'utm_term' => $payload['utm_term'] ?? null, 'utm_content' => $payload['utm_content'] ?? null, ], ); if ($payload['type'] === 'pageview') { $this->recordPageView($website, $visitor, $session, $payload, $now); } if ($payload['type'] === 'event') { $this->recordEvent($website, $visitor, $session, $payload, $now); } $session->update([ 'ended_at' => $now, 'duration' => $now->diffInSeconds($session->started_at), 'exit_page' => $payload['path'] ?? $payload['url'] ?? $session->exit_page, 'pages_count' => $session->pageViews()->count(), 'is_bounce' => $session->pageViews()->count() <= 1, ]); return response()->json(['ok' => true]); } private function recordPageView( Website $website, Visitor $visitor, AnalyticsSession $session, array $payload, Carbon $now, ): void { PageView::create([ 'website_id' => $website->id, 'visitor_id' => $visitor->id, 'analytics_session_id' => $session->id, 'url' => $payload['url'] ?? '', 'path' => $payload['path'] ?? '/', 'title' => $payload['title'] ?? null, 'referrer' => $payload['referrer'] ?? null, 'time_on_page' => $payload['time_on_page'] ?? null, 'viewed_at' => $now, ]); } private function recordEvent( Website $website, Visitor $visitor, AnalyticsSession $session, array $payload, Carbon $now, ): void { Event::create([ 'website_id' => $website->id, 'visitor_id' => $visitor->id, 'analytics_session_id' => $session->id, 'name' => $payload['event_name'] ?? 'unknown', 'category' => $payload['event_category'] ?? null, 'action' => $payload['event_action'] ?? null, 'label' => $payload['event_label'] ?? null, 'value' => $payload['event_value'] ?? null, 'properties' => $payload['event_properties'] ?? null, 'occurred_at' => $now, ]); } }