attributes->set('audit_skip', true); $context = $this->clientContext->normalizeFromRequest($request); $this->clientContext->storeInSession($request, $context); return response()->json(['ok' => true]); } public function pageView(Request $request): JsonResponse { $request->attributes->set('audit_skip', true); $data = $request->validate([ 'page_visit_id' => ['required', 'string', 'max:64'], 'path' => ['required', 'string', 'max:255'], 'title' => ['nullable', 'string', 'max:255'], 'referrer' => ['nullable', 'string', 'max:500'], ]); $context = $this->mergeContext($request); $this->audit->logPageView( $request, $data['page_visit_id'], $data['path'], $data['title'] ?? null, $data['referrer'] ?? null, $context ); return response()->json(['ok' => true]); } public function pageDuration(Request $request): JsonResponse { $request->attributes->set('audit_skip', true); $data = $request->validate([ 'page_visit_id' => ['required', 'string', 'max:64'], 'path' => ['required', 'string', 'max:255'], 'duration_ms' => ['required', 'integer', 'min:0', 'max:86400000'], ]); $context = $this->mergeContext($request); $this->audit->logPageDuration( $request, $data['page_visit_id'], $data['path'], (int) $data['duration_ms'], $context ); return response()->json(['ok' => true]); } private function mergeContext(Request $request): array { $sessionContext = $this->clientContext->fromSession($request); if ($sessionContext !== []) { return $sessionContext; } return $this->clientContext->normalizeFromRequest($request); } }