fix(prospecting): handle PageSpeed API errors and improve performance card

- Detect API-level errors (quota exceeded, invalid URL) in response JSON
  and store in scan_error instead of silently writing zeros
- Show scan error message on the performance card when present
- Show "No performance data — configure PAGESPEED_API_KEY" when all
  scores are 0 and no error was recorded
- Add accessibility and best practices scores to performance card

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-30 21:41:37 +02:00
parent a247622d23
commit 70f2803dd3
2 changed files with 39 additions and 9 deletions

View File

@@ -210,6 +210,20 @@ class EnrichmentService:
response = requests.get(api_url, params=params, timeout=60) response = requests.get(api_url, params=params, timeout=60)
data = response.json() data = response.json()
# Check for API-level errors (quota exceeded, invalid URL, etc.)
if "error" in data:
error_msg = data["error"].get("message", str(data["error"]))
logger.warning("PageSpeed API error for %s: %s", domain, error_msg)
profile = prospect.performance_profile
if not profile:
profile = ProspectPerformanceProfile(prospect_id=prospect.id)
db.add(profile)
profile.scan_error = error_msg
profile.scan_strategy = "mobile"
prospect.last_perf_scan_at = datetime.now(UTC)
db.flush()
return profile
lighthouse = data.get("lighthouseResult", {}) lighthouse = data.get("lighthouseResult", {})
categories = lighthouse.get("categories", {}) categories = lighthouse.get("categories", {})
audits = lighthouse.get("audits", {}) audits = lighthouse.get("audits", {})

View File

@@ -162,23 +162,39 @@
<!-- Performance Summary --> <!-- Performance Summary -->
<div x-show="prospect.performance_profile" class="p-4 bg-white rounded-lg shadow-xs dark:bg-gray-800"> <div x-show="prospect.performance_profile" class="p-4 bg-white rounded-lg shadow-xs dark:bg-gray-800">
{{ section_header('Performance', icon='chart-bar') }} {{ section_header('Performance', icon='chart-bar') }}
<div class="space-y-2 text-sm"> <!-- Scan error -->
<div x-show="prospect.performance_profile?.scan_error" class="p-3 mb-3 text-sm text-orange-700 bg-orange-50 rounded-lg dark:bg-orange-900/20 dark:text-orange-300">
<span class="font-medium">Scan failed:</span>
<span x-text="prospect.performance_profile?.scan_error"></span>
</div>
<!-- Scores (only when real data exists) -->
<div x-show="!prospect.performance_profile?.scan_error && (prospect.performance_profile?.performance_score > 0 || prospect.performance_profile?.seo_score > 0)" class="space-y-2 text-sm">
<div class="flex justify-between"> <div class="flex justify-between">
<span class="text-gray-600 dark:text-gray-400">Performance Score</span> <span class="text-gray-600 dark:text-gray-400">Performance</span>
<span class="font-semibold" :class="scoreColor(prospect.performance_profile?.performance_score)" <span class="font-semibold" :class="scoreColor(prospect.performance_profile?.performance_score)"
x-text="prospect.performance_profile?.performance_score ?? '—'"></span> x-text="prospect.performance_profile?.performance_score + '/100'"></span>
</div>
<div class="flex justify-between">
<span class="text-gray-600 dark:text-gray-400">Accessibility</span>
<span class="font-semibold text-gray-700 dark:text-gray-200" x-text="prospect.performance_profile?.accessibility_score + '/100'"></span>
</div>
<div class="flex justify-between">
<span class="text-gray-600 dark:text-gray-400">Best Practices</span>
<span class="font-semibold text-gray-700 dark:text-gray-200" x-text="prospect.performance_profile?.best_practices_score + '/100'"></span>
</div>
<div class="flex justify-between">
<span class="text-gray-600 dark:text-gray-400">SEO</span>
<span class="font-semibold text-gray-700 dark:text-gray-200" x-text="prospect.performance_profile?.seo_score + '/100'"></span>
</div> </div>
<div class="flex justify-between"> <div class="flex justify-between">
<span class="text-gray-600 dark:text-gray-400">Mobile Friendly</span> <span class="text-gray-600 dark:text-gray-400">Mobile Friendly</span>
<span x-text="prospect.performance_profile?.is_mobile_friendly ? 'Yes' : 'No'" <span x-text="prospect.performance_profile?.is_mobile_friendly == null ? '—' : prospect.performance_profile?.is_mobile_friendly ? 'Yes' : 'No'"
:class="prospect.performance_profile?.is_mobile_friendly ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'" :class="prospect.performance_profile?.is_mobile_friendly ? 'text-green-600 dark:text-green-400' : prospect.performance_profile?.is_mobile_friendly === false ? 'text-red-600 dark:text-red-400' : 'text-gray-400'"
class="font-medium"></span> class="font-medium"></span>
</div> </div>
<div class="flex justify-between">
<span class="text-gray-600 dark:text-gray-400">SEO Score</span>
<span class="font-medium text-gray-700 dark:text-gray-300" x-text="prospect.performance_profile?.seo_score ?? '—'"></span>
</div>
</div> </div>
<p x-show="!prospect.performance_profile?.scan_error && prospect.performance_profile?.performance_score === 0 && prospect.performance_profile?.seo_score === 0"
class="text-sm text-gray-400 text-center py-4">No performance data — configure PAGESPEED_API_KEY in .env</p>
</div> </div>
</div> </div>