fix: send pageviews to the analytics API correctly

- Use the correct endpoint (analytics.mattitja.se instead of the
  non-existent .cloud domain)
- Authenticate with the site ingest secret as a Bearer token so the API
  trusts the forwarded visitor IP and user agent
- Forward the visitor Accept-Language header (required by bot detection)
- Only track successful GET requests rendering HTML
- Short timeouts and a file-based circuit breaker that pauses sending
  after connection failures or 5xx responses, so no queue, worker or
  cache is needed and a down API never slows the host site
- Log rejected requests instead of failing silently
This commit is contained in:
mathiaspalmqvist committed 2026-11-12 09:08:27 +01:00
1 parent e3911ca12c
commit 19f632d652
11 files changed
+298 -26

No files matched your search

+48 -1
View File
@@ -48,7 +48,7 @@ it('captures analytics data for web requests', function () {
Http::assertSent(function ($request) {
$data = $request->data();
return $request->url() === 'https://analytics.mattitja.cloud/api/send' &&
return $request->url() === 'https://analytics.mattitja.se/api/send' &&
$data['k'] === 'testsiteky' &&
$data['u'] === 'https://example.com/test' &&
$data['r'] === 'https://google.com' &&
@@ -140,3 +140,50 @@ it('handles empty user agent gracefully', function () {
return array_key_exists('ua', $data) && $data['ua'] === '';
});
});
it('does not capture analytics without an ingest secret', function () {
config(['mattitja-analytics.ingest_secret' => null]);
handleRequest(createMiddleware(), createTestRequest());
Http::assertNothingSent();
});
it('forwards the visitor Accept-Language header', function () {
$request = createTestRequest();
$request->headers->set('Accept-Language', 'sv-SE,sv;q=0.9');
handleRequest(createMiddleware(), $request);
Http::assertSent(fn ($request) => $request->hasHeader('Accept-Language', 'sv-SE,sv;q=0.9'));
});
it('ignores non-GET requests', function () {
handleRequest(createMiddleware(), createTestRequest(method: 'POST'));
Http::assertNothingSent();
});
it('ignores JSON responses and redirects', function () {
$middleware = createMiddleware();
$request = createTestRequest();
foreach ([
new \Illuminate\Http\JsonResponse(['ok' => true]),
new \Illuminate\Http\RedirectResponse('https://example.com/elsewhere'),
] as $response) {
$result = $middleware->handle($request, fn () => $response);
$middleware->terminate($request, $result);
}
Http::assertNothingSent();
});
it('ignores requests expecting JSON', function () {
$request = createTestRequest();
$request->headers->set('Accept', 'application/json');
handleRequest(createMiddleware(), $request);
Http::assertNothingSent();
});
+2 -1
View File
@@ -45,7 +45,8 @@ it('adds env variable if .env exists and key is missing', function () {
$envContent = File::get($this->envPath);
expect($envContent)->toContain('MATTITJA_ANALYTICS_SITE_KEY=');
expect($envContent)->toContain('MATTITJA_ANALYTICS_SITE_KEY=')
->toContain('MATTITJA_ANALYTICS_INGEST_SECRET=');
File::put($this->envPath, $originalContent);
});