Files
familienarchiv/docs/adr/018-glitchtip-frontend-error-tracking.md
Marcel de19d17b00
Some checks failed
CI / Unit & Component Tests (pull_request) Successful in 3m4s
CI / OCR Service Tests (pull_request) Successful in 18s
CI / Backend Unit Tests (pull_request) Successful in 2m39s
CI / fail2ban Regex (pull_request) Successful in 40s
CI / Compose Bucket Idempotency (pull_request) Successful in 59s
CI / Unit & Component Tests (push) Successful in 5m46s
CI / OCR Service Tests (push) Successful in 45s
CI / Backend Unit Tests (push) Failing after 10m32s
CI / fail2ban Regex (push) Successful in 3m7s
CI / Compose Bucket Idempotency (push) Successful in 2m26s
docs(adr): add ADR-018 for GlitchTip frontend error tracking via @sentry/sveltekit
Documents the decision to use the Sentry SDK with self-hosted GlitchTip,
sendDefaultPii:false rationale, errorId surfacing to users, and alternatives
considered (Sentry SaaS rejected for data-minimisation reasons).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 10:27:46 +02:00

3.9 KiB

ADR-018: GlitchTip frontend error tracking via @sentry/sveltekit

Date: 2026-05-17
Status: Accepted
Deciders: Marcel Raddatz


Context

The Familienarchiv had no client-side error reporting. When a user encountered a crash or unhandled error in the SvelteKit frontend, there was no way for the operator to observe it — errors were invisible until a user manually reported them. A GlitchTip instance (self-hosted, Sentry-compatible) was already running as part of the observability stack (docker-compose.observability.yml). The backend already reported server-side errors to it.

We needed a way to:

  1. Capture frontend errors automatically and route them to GlitchTip.
  2. Give users a visible error identifier they can include in a support message.
  3. Do this without leaking personally identifiable information (PII) from the family archive — documents contain personal histories, names, and relationships.

Decision

Use @sentry/sveltekit (the official Sentry SDK for SvelteKit) to:

  • Initialise with sendDefaultPii: false on both hooks.server.ts and hooks.client.ts.
  • Pass a callback to Sentry.handleErrorWithSentry() that returns { message, errorId } where errorId is Sentry.lastEventId() when Sentry captured the event, or a fresh crypto.randomUUID() as fallback.
  • Display the errorId on the +error.svelte page so users can include it in a report to the operator.

The SDK is initialised with enabled: !!import.meta.env.VITE_SENTRY_DSN so that development and CI builds without a DSN configured do not send any events.

VITE_SENTRY_DSN is a write-only ingest key — it can POST events to GlitchTip but cannot read them. It is safe to include in the client bundle per the Sentry security model; it does not require rotation like a password.


Alternatives considered

Sentry SaaS — rejected. The archive contains private family documents and personal history. Sending error events with stack traces to a US-hosted third party is inconsistent with the project's data-minimisation posture. Self-hosted GlitchTip on the same Hetzner VPS keeps all data on infrastructure the operator controls.

Custom error logging endpoint — rejected. The @sentry/sveltekit SDK handles SvelteKit's hook lifecycle, source-map upload, and event grouping automatically. Reimplementing this would cost significant engineering time for no benefit.

Log-only (no user-visible errorId) — rejected. Without a visible error ID, users can only describe what happened in natural language, making it hard to correlate a report with a specific GlitchTip event. The errorId closes this gap at negligible UI cost.


Consequences

Positive:

  • Frontend errors are now observable without requiring user reports.
  • Users can provide an errorId that maps directly to a GlitchTip event.
  • sendDefaultPii: false ensures names, IPs, and cookie values are not included in captured events.
  • tracesSampleRate: 0.1 limits trace volume to 10% of transactions, keeping GlitchTip load low on the shared VPS.

Negative / trade-offs:

  • The @sentry/sveltekit SDK is now a production dependency. SDK updates must be reviewed for changes to the default PII scrubbing behaviour.
  • The handleError callback in both hooks returns a hardcoded English message ('An unexpected error occurred'). This bypasses Paraglide i18n — the error page will always show English text when the hooks are active, regardless of the user's locale. This is acceptable because: (a) the error page is a last-resort fallback not part of normal UX, (b) the errorId is the actionable information, not the message text. A future ADR may address this if internationalised error messages become a requirement.
  • Sentry.lastEventId() returns undefined when Sentry did not capture the event (e.g. DSN not configured). The crypto.randomUUID() fallback guarantees an errorId is always present, but that UUID will not appear in GlitchTip.