feat(frontend): integrate @sentry/sveltekit for browser and SSR error reporting to GlitchTip #579

Closed
opened 2026-05-14 15:05:33 +02:00 by marcel · 10 comments
Owner

Context

GlitchTip speaks the Sentry SDK wire protocol. Adding @sentry/sveltekit to the frontend captures:

  • Unhandled JavaScript exceptions in the browser
  • Unhandled promise rejections
  • SvelteKit handleError events from both the client and server (SSR) runtime

When VITE_SENTRY_DSN is empty (default in .env.example), Sentry is fully disabled — no network requests, no console output. This means CI and environments without GlitchTip running are unaffected.

Depends on: GlitchTip infrastructure issue — a project DSN must exist before this can be tested end-to-end

Installation

cd frontend
npm install @sentry/sveltekit

Files to Create / Modify

frontend/src/hooks.client.ts (create or merge with existing)

import * as Sentry from '@sentry/sveltekit';

Sentry.init({
  dsn: import.meta.env.VITE_SENTRY_DSN,
  environment: import.meta.env.MODE,
  tracesSampleRate: 1.0,
  enabled: !!import.meta.env.VITE_SENTRY_DSN,
});

export const handleError = Sentry.handleErrorWithSentry();

frontend/src/hooks.server.ts (create or merge with existing)

import * as Sentry from '@sentry/sveltekit';
import { sequence } from '@sveltejs/kit/hooks';

Sentry.init({
  dsn: import.meta.env.VITE_SENTRY_DSN,
  environment: import.meta.env.MODE,
  tracesSampleRate: 1.0,
  enabled: !!import.meta.env.VITE_SENTRY_DSN,
});

export const handleError = Sentry.handleErrorWithSentry();

If hooks.server.ts already exports a handle function, wrap it with sequence():

export const handle = sequence(existingHandle);

.env.example — already added by scaffold issue; confirm this line exists:

VITE_SENTRY_DSN=

frontend/.env (local only, not committed) — set after GlitchTip project is created:

VITE_SENTRY_DSN=http://<key>@localhost:3002/<project-id>

Acceptance Criteria

  • npm run check passes with no new type errors
  • npm run build succeeds
  • npm run test passes — no test regressions
  • When VITE_SENTRY_DSN is unset or empty, the app starts normally with no Sentry-related console errors or network requests
  • When VITE_SENTRY_DSN is set to the GlitchTip JavaScript project DSN: throwing throw new Error("test") in a page's load function causes an event to appear in GlitchTip Issues within 30 seconds
  • The captured event in GlitchTip shows a stack trace pointing to the correct source file and line

Definition of Done

  • All acceptance criteria checked
  • package.json and package-lock.json (or pnpm-lock.yaml) updated
  • hooks.client.ts and hooks.server.ts committed
  • Committed on a feature branch, PR opened against main
## Context GlitchTip speaks the Sentry SDK wire protocol. Adding `@sentry/sveltekit` to the frontend captures: - Unhandled JavaScript exceptions in the browser - Unhandled promise rejections - SvelteKit `handleError` events from both the client and server (SSR) runtime When `VITE_SENTRY_DSN` is empty (default in `.env.example`), Sentry is fully disabled — no network requests, no console output. This means CI and environments without GlitchTip running are unaffected. **Depends on:** GlitchTip infrastructure issue — a project DSN must exist before this can be tested end-to-end ## Installation ```bash cd frontend npm install @sentry/sveltekit ``` ## Files to Create / Modify ### `frontend/src/hooks.client.ts` (create or merge with existing) ```typescript import * as Sentry from '@sentry/sveltekit'; Sentry.init({ dsn: import.meta.env.VITE_SENTRY_DSN, environment: import.meta.env.MODE, tracesSampleRate: 1.0, enabled: !!import.meta.env.VITE_SENTRY_DSN, }); export const handleError = Sentry.handleErrorWithSentry(); ``` ### `frontend/src/hooks.server.ts` (create or merge with existing) ```typescript import * as Sentry from '@sentry/sveltekit'; import { sequence } from '@sveltejs/kit/hooks'; Sentry.init({ dsn: import.meta.env.VITE_SENTRY_DSN, environment: import.meta.env.MODE, tracesSampleRate: 1.0, enabled: !!import.meta.env.VITE_SENTRY_DSN, }); export const handleError = Sentry.handleErrorWithSentry(); ``` If `hooks.server.ts` already exports a `handle` function, wrap it with `sequence()`: ```typescript export const handle = sequence(existingHandle); ``` ### `.env.example` — already added by scaffold issue; confirm this line exists: ``` VITE_SENTRY_DSN= ``` ### `frontend/.env` (local only, not committed) — set after GlitchTip project is created: ``` VITE_SENTRY_DSN=http://<key>@localhost:3002/<project-id> ``` ## Acceptance Criteria - [ ] `npm run check` passes with no new type errors - [ ] `npm run build` succeeds - [ ] `npm run test` passes — no test regressions - [ ] When `VITE_SENTRY_DSN` is unset or empty, the app starts normally with no Sentry-related console errors or network requests - [ ] When `VITE_SENTRY_DSN` is set to the GlitchTip JavaScript project DSN: throwing `throw new Error("test")` in a page's `load` function causes an event to appear in GlitchTip Issues within 30 seconds - [ ] The captured event in GlitchTip shows a stack trace pointing to the correct source file and line ## Definition of Done - All acceptance criteria checked - `package.json` and `package-lock.json` (or `pnpm-lock.yaml`) updated - `hooks.client.ts` and `hooks.server.ts` committed - Committed on a feature branch, PR opened against `main`
marcel added this to the Observability Stack — Grafana LGTM + GlitchTip milestone 2026-05-14 15:05:33 +02:00
marcel added the P2-mediumfeaturephase-7: monitoring labels 2026-05-14 15:06:14 +02:00
Author
Owner

🏗️ Markus Keller — Senior Application Architect

Observations

  • This issue adds GlitchTip (Sentry-compatible) as a new external system integration for the SvelteKit frontend. The architecture docs must reflect this — specifically docs/architecture/c4/l1-context.puml (new external system: GlitchTip) and docs/architecture/c4/l2-containers.puml (SvelteKit now emits to GlitchTip). I checked both files: neither currently mentions GlitchTip or error tracking. These updates are a required doc update, not optional.
  • The issue body instructs wrapping with sequence(existingHandle) if a handle export exists. hooks.server.ts already exports handle = sequence(userGroup, handleAuth, handleLocaleDetection, handleParaglide). The Sentry handle middleware must be threaded into this existing sequence correctly — typically prepended so errors in all downstream handlers are caught.
  • tracesSampleRate: 1.0 captures 100% of transactions. For a family project on a budget VPS, this is likely fine at low volume, but it will produce noise in GlitchTip's performance view and generates more outbound traffic. Setting it to 0 (errors only, no performance tracing) would be more appropriate for a first integration focused purely on error reporting.
  • The issue spec correctly notes the dependency on a GlitchTip infrastructure issue. That dependency should be linked in the issue tracker before implementation, otherwise the end-to-end AC cannot be verified.
  • No new backend package, route, entity, or Docker service is added by this issue — but the l1-context.puml and l2-containers.puml updates are real required docs.

Recommendations

  • Use tracesSampleRate: 0 for the initial integration, not 1.0. The project is using GlitchTip for error reporting, not distributed tracing. 1.0 is over-engineered for this use case.
  • Prepend Sentry's handle in the sequence: sequence(sentryHandle, userGroup, handleAuth, handleLocaleDetection, handleParaglide). This ensures auth errors and locale errors are also captured.
  • Update l1-context.puml and l2-containers.puml as part of this PR. GlitchTip is a new external system the SvelteKit container depends on.
  • Add the GlitchTip infrastructure issue as a "Depends on" link in this issue's body before implementation starts.
## 🏗️ Markus Keller — Senior Application Architect ### Observations - This issue adds GlitchTip (Sentry-compatible) as a new **external system integration** for the SvelteKit frontend. The architecture docs must reflect this — specifically `docs/architecture/c4/l1-context.puml` (new external system: GlitchTip) and `docs/architecture/c4/l2-containers.puml` (SvelteKit now emits to GlitchTip). I checked both files: neither currently mentions GlitchTip or error tracking. These updates are a **required doc update**, not optional. - The issue body instructs wrapping with `sequence(existingHandle)` if a `handle` export exists. `hooks.server.ts` already exports `handle = sequence(userGroup, handleAuth, handleLocaleDetection, handleParaglide)`. The Sentry `handle` middleware must be threaded into this existing sequence correctly — typically prepended so errors in all downstream handlers are caught. - `tracesSampleRate: 1.0` captures 100% of transactions. For a family project on a budget VPS, this is likely fine at low volume, but it will produce noise in GlitchTip's performance view and generates more outbound traffic. Setting it to `0` (errors only, no performance tracing) would be more appropriate for a first integration focused purely on error reporting. - The issue spec correctly notes the dependency on a GlitchTip infrastructure issue. That dependency should be linked in the issue tracker before implementation, otherwise the end-to-end AC cannot be verified. - No new backend package, route, entity, or Docker service is added by this issue — but the `l1-context.puml` and `l2-containers.puml` updates are real required docs. ### Recommendations - **Use `tracesSampleRate: 0` for the initial integration**, not `1.0`. The project is using GlitchTip for error reporting, not distributed tracing. `1.0` is over-engineered for this use case. - **Prepend Sentry's handle in the sequence**: `sequence(sentryHandle, userGroup, handleAuth, handleLocaleDetection, handleParaglide)`. This ensures auth errors and locale errors are also captured. - **Update `l1-context.puml` and `l2-containers.puml`** as part of this PR. GlitchTip is a new external system the SvelteKit container depends on. - Add the GlitchTip infrastructure issue as a "Depends on" link in this issue's body before implementation starts.
Author
Owner

👨‍💻 Felix Brandt — Senior Fullstack Developer

Observations

  • hooks.client.ts does not yet exist — it needs to be created, which is correctly called out in the issue.
  • hooks.server.ts already exists and exports a handle chain via sequence(userGroup, handleAuth, handleLocaleDetection, handleParaglide). The issue mentions the merge pattern but the code snippet shows only sequence(existingHandle) (singular). The actual call needs to sequence Sentry's handle alongside all four existing handles: sequence(Sentry.sentryHandle(), userGroup, handleAuth, handleLocaleDetection, handleParaglide).
  • Both hooks.client.ts and hooks.server.ts have identical Sentry.init() blocks. The DSN, environment, and options are identical. This is intentional (client and server each need their own init call for the respective SDK runtime), but it's worth noting that a shared config object cannot be extracted here — the two SDKs are different bundles (browser vs Node). No refactor needed.
  • The enabled: !!import.meta.env.VITE_SENTRY_DSN guard is correct. An empty string is falsy, so an unset env var truly disables the SDK.
  • hooks.ts (the reroute-only file) does not need to change — confirmed by inspection.
  • The issue spec references package.json and package-lock.json (or pnpm-lock.yaml) — this project uses npm, so only package-lock.json applies. The pnpm-lock.yaml alternative is irrelevant here.
  • No TypeScript codegen (npm run generate:api) is needed — this is a pure hooks integration with no new API endpoints.

Recommendations

  • In hooks.server.ts, use Sentry.sentryHandle() (if the package exposes it) as the first entry in the sequence. Check the @sentry/sveltekit API surface before implementing — the exact export name matters. If the package only exposes handleError and not a handle middleware, the issue's warning about wrapping is moot.
  • Write at least one unit test for the "DSN unset" behavior: import the hooks module with VITE_SENTRY_DSN unset and assert no Sentry network call is attempted. This is the most important AC to automate.
  • Keep both Sentry.init() calls strictly identical in options — any divergence between client and server init is a future confusion trap.
## 👨‍💻 Felix Brandt — Senior Fullstack Developer ### Observations - `hooks.client.ts` does not yet exist — it needs to be **created**, which is correctly called out in the issue. - `hooks.server.ts` already exists and exports a `handle` chain via `sequence(userGroup, handleAuth, handleLocaleDetection, handleParaglide)`. The issue mentions the merge pattern but the code snippet shows only `sequence(existingHandle)` (singular). The actual call needs to sequence Sentry's handle alongside all four existing handles: `sequence(Sentry.sentryHandle(), userGroup, handleAuth, handleLocaleDetection, handleParaglide)`. - Both `hooks.client.ts` and `hooks.server.ts` have identical `Sentry.init()` blocks. The DSN, environment, and options are identical. This is intentional (client and server each need their own init call for the respective SDK runtime), but it's worth noting that a shared config object cannot be extracted here — the two SDKs are different bundles (browser vs Node). No refactor needed. - The `enabled: !!import.meta.env.VITE_SENTRY_DSN` guard is correct. An empty string is falsy, so an unset env var truly disables the SDK. - `hooks.ts` (the reroute-only file) does not need to change — confirmed by inspection. - The issue spec references `package.json` and `package-lock.json` (or `pnpm-lock.yaml`) — this project uses npm, so only `package-lock.json` applies. The `pnpm-lock.yaml` alternative is irrelevant here. - No TypeScript codegen (`npm run generate:api`) is needed — this is a pure hooks integration with no new API endpoints. ### Recommendations - In `hooks.server.ts`, use `Sentry.sentryHandle()` (if the package exposes it) as the first entry in the sequence. Check the `@sentry/sveltekit` API surface before implementing — the exact export name matters. If the package only exposes `handleError` and not a `handle` middleware, the issue's warning about wrapping is moot. - Write at least one unit test for the "DSN unset" behavior: import the hooks module with `VITE_SENTRY_DSN` unset and assert no Sentry network call is attempted. This is the most important AC to automate. - Keep both `Sentry.init()` calls strictly identical in options — any divergence between client and server init is a future confusion trap.
Author
Owner

🔒 Nora "NullX" Steiner — Application Security Engineer

Observations

Data exposure via error events

Sentry/GlitchTip events capture the full error context, which in a SvelteKit app can include request objects, locals, and cookies. event.locals.user is populated by hooks.server.ts and includes the full AppUser object (groups, permissions, email). If SvelteKit passes the full event context to handleError, this user object could end up in an error report.

The @sentry/sveltekit handleErrorWithSentry() wrapper does not scrub PII by default. For a family archive with real names and personal documents, this matters even though GlitchTip is self-hosted.

DSN security

VITE_SENTRY_DSN is a Vite public env var (prefixed VITE_). This means it is embedded in the client-side bundle and visible to anyone who inspects the JavaScript. This is expected and correct — GlitchTip DSNs are designed to be public (they are write-only, with no read access). However, the implementer should confirm GlitchTip's DSN is truly write-only with no dangerous cross-site capabilities before shipping.

Source maps

The issue spec does not mention source maps. Meaningful stack traces (the last AC: "stack trace pointing to the correct source file and line") require uploading source maps to GlitchTip. Source maps contain your full source code. Uploading them to GlitchTip (self-hosted) is fine for privacy. The @sentry/sveltekit Vite plugin can auto-upload them — but this requires a Sentry auth token. If source maps are not uploaded, the AC about correct file/line cannot be verified.

tracesSampleRate: 1.0

Performance tracing at 100% is not a security concern per se, but it does mean every request generates an outbound network call to GlitchTip. If GlitchTip is unavailable, this could slow SSR response times. Use 0 unless performance tracing is an explicit goal.

Recommendations

  • Add a beforeSend hook to scrub event.user or any PII from error events before they reach GlitchTip:
    Sentry.init({
      // ...
      beforeSend(event) {
        // Remove user PII from error reports
        delete event.user;
        return event;
      }
    });
    
  • Set tracesSampleRate: 0 (errors only) until a deliberate decision is made to enable performance tracing.
  • Document in the PR (or a comment in the hooks file) that the DSN is intentionally public — this prevents a future developer from treating it as a secret and accidentally breaking the integration.
  • Verify that the GlitchTip instance's DSN endpoint requires no authentication for ingestion (it shouldn't) and that there is no way to read event data via the DSN alone.
## 🔒 Nora "NullX" Steiner — Application Security Engineer ### Observations **Data exposure via error events** Sentry/GlitchTip events capture the full error context, which in a SvelteKit app can include request objects, locals, and cookies. `event.locals.user` is populated by `hooks.server.ts` and includes the full `AppUser` object (groups, permissions, email). If SvelteKit passes the full event context to `handleError`, this user object could end up in an error report. The `@sentry/sveltekit` `handleErrorWithSentry()` wrapper does not scrub PII by default. For a family archive with real names and personal documents, this matters even though GlitchTip is self-hosted. **DSN security** `VITE_SENTRY_DSN` is a Vite public env var (prefixed `VITE_`). This means it is **embedded in the client-side bundle** and visible to anyone who inspects the JavaScript. This is expected and correct — GlitchTip DSNs are designed to be public (they are write-only, with no read access). However, the implementer should confirm GlitchTip's DSN is truly write-only with no dangerous cross-site capabilities before shipping. **Source maps** The issue spec does not mention source maps. Meaningful stack traces (the last AC: "stack trace pointing to the correct source file and line") require uploading source maps to GlitchTip. Source maps contain your full source code. Uploading them to GlitchTip (self-hosted) is fine for privacy. The `@sentry/sveltekit` Vite plugin can auto-upload them — but this requires a Sentry auth token. If source maps are not uploaded, the AC about correct file/line cannot be verified. **tracesSampleRate: 1.0** Performance tracing at 100% is not a security concern per se, but it does mean every request generates an outbound network call to GlitchTip. If GlitchTip is unavailable, this could slow SSR response times. Use `0` unless performance tracing is an explicit goal. ### Recommendations - Add a `beforeSend` hook to scrub `event.user` or any PII from error events before they reach GlitchTip: ```typescript Sentry.init({ // ... beforeSend(event) { // Remove user PII from error reports delete event.user; return event; } }); ``` - Set `tracesSampleRate: 0` (errors only) until a deliberate decision is made to enable performance tracing. - Document in the PR (or a comment in the hooks file) that the DSN is intentionally public — this prevents a future developer from treating it as a secret and accidentally breaking the integration. - Verify that the GlitchTip instance's DSN endpoint requires no authentication for ingestion (it shouldn't) and that there is no way to read event data via the DSN alone.
Author
Owner

🧪 Sara Holt — QA Engineer & Test Strategist

Observations

Test coverage for acceptance criteria

The issue has six ACs, of which only one ("when DSN is unset, no Sentry errors or network requests") is practically automatable as a unit/integration test. The remaining ACs are manual or E2E-only:

  • AC 4 (no console errors when DSN unset) — testable with Playwright's page.on('console', ...) capture
  • AC 5 (event appears in GlitchTip within 30 seconds) — requires GlitchTip running; E2E test or manual only
  • AC 6 (stack trace points to correct file) — manual verification; automatable only if source maps are uploaded

The issue lists no automated tests in the acceptance criteria. This is a gap for a feature that touches both the SSR and client runtimes.

CI impact

The @sentry/sveltekit package adds a Vite plugin that may interact with the existing vite.config.ts. The CI workflow runs npm run test:coverage and npm run check. Both should still pass, but the new package is a build dependency that must not cause type errors or import resolution failures in the Vitest environment (where import.meta.env.VITE_SENTRY_DSN may be undefined).

The "DSN empty" path in test environment

Vitest's import.meta.env does not automatically provide VITE_SENTRY_DSN. If the Sentry init code runs during tests and finds an undefined DSN, it should silently skip init. The enabled: !!import.meta.env.VITE_SENTRY_DSN guard handles this — but it should be verified in CI by checking the test output for any Sentry-related warnings.

Missing regression test

There is no test that verifies handleError is correctly exported from both hooks files after the integration. A type-checking test (npm run check) will catch this at the TypeScript level, making it an acceptable quality gate.

Recommendations

  • Add one Playwright E2E test for AC 4: page.on('consoleMessage', ...) — assert no console errors occur on page load when VITE_SENTRY_DSN is absent from the test environment.
  • Verify that npm run check passes with zero errors after the integration — this is the most practical automated gate for hooks type correctness.
  • The AC about "no network requests when DSN is unset" should be verified in the PR description with a screenshot of the browser Network tab during a dev run without VITE_SENTRY_DSN set.
  • Consider adding VITE_SENTRY_DSN= (empty) to any .env.test or Vitest setup config to make the "disabled" behavior explicit in CI.
## 🧪 Sara Holt — QA Engineer & Test Strategist ### Observations **Test coverage for acceptance criteria** The issue has six ACs, of which only one ("when DSN is unset, no Sentry errors or network requests") is practically automatable as a unit/integration test. The remaining ACs are manual or E2E-only: - AC 4 (no console errors when DSN unset) — testable with Playwright's `page.on('console', ...)` capture - AC 5 (event appears in GlitchTip within 30 seconds) — requires GlitchTip running; E2E test or manual only - AC 6 (stack trace points to correct file) — manual verification; automatable only if source maps are uploaded The issue lists no automated tests in the acceptance criteria. This is a gap for a feature that touches both the SSR and client runtimes. **CI impact** The `@sentry/sveltekit` package adds a Vite plugin that may interact with the existing `vite.config.ts`. The CI workflow runs `npm run test:coverage` and `npm run check`. Both should still pass, but the new package is a build dependency that must not cause type errors or import resolution failures in the Vitest environment (where `import.meta.env.VITE_SENTRY_DSN` may be undefined). **The "DSN empty" path in test environment** Vitest's `import.meta.env` does not automatically provide `VITE_SENTRY_DSN`. If the Sentry init code runs during tests and finds an undefined DSN, it should silently skip init. The `enabled: !!import.meta.env.VITE_SENTRY_DSN` guard handles this — but it should be verified in CI by checking the test output for any Sentry-related warnings. **Missing regression test** There is no test that verifies `handleError` is correctly exported from both hooks files after the integration. A type-checking test (`npm run check`) will catch this at the TypeScript level, making it an acceptable quality gate. ### Recommendations - Add one Playwright E2E test for AC 4: `page.on('consoleMessage', ...)` — assert no console errors occur on page load when `VITE_SENTRY_DSN` is absent from the test environment. - Verify that `npm run check` passes with zero errors after the integration — this is the most practical automated gate for hooks type correctness. - The AC about "no network requests when DSN is unset" should be verified in the PR description with a screenshot of the browser Network tab during a dev run without `VITE_SENTRY_DSN` set. - Consider adding `VITE_SENTRY_DSN=` (empty) to any `.env.test` or Vitest setup config to make the "disabled" behavior explicit in CI.
Author
Owner

🎨 Leonie Voss — UX Designer & Accessibility Strategist

Observations

This is a pure infrastructure/observability issue with zero user-facing UI changes. No components, routes, or interaction patterns are added or modified.

From a UX perspective, the only relevant question is whether error reporting could inadvertently affect the user experience when GlitchTip is unavailable or slow — and the issue correctly scopes this to a write-only async call that should not block rendering.

The enabled: !!import.meta.env.VITE_SENTRY_DSN guard ensures the integration is completely invisible to users in environments without a DSN, which is the correct default for a dev/CI environment.

No accessibility, responsive design, or brand compliance concerns are raised by this issue.

Recommendations

  • Confirm that Sentry's network calls are truly fire-and-forget and do not affect Time to Interactive (TTI) or block the main thread. The @sentry/sveltekit browser SDK uses a non-blocking transport by default — verify this is still the case in the installed version.
  • No UI changes required. No design review needed for this issue.
## 🎨 Leonie Voss — UX Designer & Accessibility Strategist ### Observations This is a pure infrastructure/observability issue with zero user-facing UI changes. No components, routes, or interaction patterns are added or modified. From a UX perspective, the only relevant question is whether error reporting could inadvertently affect the user experience when GlitchTip is unavailable or slow — and the issue correctly scopes this to a write-only async call that should not block rendering. The `enabled: !!import.meta.env.VITE_SENTRY_DSN` guard ensures the integration is completely invisible to users in environments without a DSN, which is the correct default for a dev/CI environment. No accessibility, responsive design, or brand compliance concerns are raised by this issue. ### Recommendations - Confirm that Sentry's network calls are truly fire-and-forget and do not affect Time to Interactive (TTI) or block the main thread. The `@sentry/sveltekit` browser SDK uses a non-blocking transport by default — verify this is still the case in the installed version. - No UI changes required. No design review needed for this issue.
Author
Owner

⚙️ Tobias Wendt — DevOps & Platform Engineer

Observations

Missing VITE_SENTRY_DSN in .env.example

I checked the root .env.example — it does not contain a VITE_SENTRY_DSN= entry. The issue states "confirm this line exists" but it does not. This is a concrete gap that must be addressed in the PR.

CI environment

The CI workflow (.gitea/workflows/ci.yml) does not set VITE_SENTRY_DSN. This is correct — CI should not have an active DSN. The enabled: !!import.meta.env.VITE_SENTRY_DSN guard ensures CI builds are unaffected. Verify this explicitly in the PR by checking that the CI build log contains no Sentry initialization messages.

Self-hosted catalogue

docs/infrastructure/self-hosted-catalogue.md already documents GlitchTip with a Docker Compose snippet. The Compose snippet uses image: glitchtip/glitchtip:latest — this violates the pinned-tag convention. That pre-existing issue is out of scope for this PR, but worth noting for the GlitchTip infrastructure issue.

Source map upload in production builds

If the @sentry/sveltekit Vite plugin is added (for source map upload), it will require a SENTRY_AUTH_TOKEN environment variable during npm run build. This must be handled in the production build pipeline, not in CI test runs. The release workflow (.gitea/workflows/release.yml) would need this secret. Confirm whether source map upload is in scope for this issue or deferred to a follow-up.

Package lock file

The issue correctly lists package-lock.json as a required update. Confirm that the lockfile is committed alongside package.json — both must be in the same commit to avoid "lockfile out of sync" errors on the next npm ci.

Recommendations

  • Add VITE_SENTRY_DSN= to .env.example as part of this PR — the issue says "confirm this line exists" but it doesn't. This is a required deliverable.
  • Do not add the @sentry/sveltekit Vite plugin (source map upload) in this issue unless a SENTRY_AUTH_TOKEN secret is already configured in Gitea secrets. Keep the scope to SDK init + handleError only. Source map upload can be a follow-up once the GlitchTip project is established.
  • Add a note to docs/infrastructure/self-hosted-catalogue.md that the SvelteKit app uses VITE_SENTRY_DSN to connect to GlitchTip — so operators know to set it when standing up the stack.
## ⚙️ Tobias Wendt — DevOps & Platform Engineer ### Observations **Missing `VITE_SENTRY_DSN` in `.env.example`** I checked the root `.env.example` — it does **not** contain a `VITE_SENTRY_DSN=` entry. The issue states "confirm this line exists" but it does not. This is a concrete gap that must be addressed in the PR. **CI environment** The CI workflow (`.gitea/workflows/ci.yml`) does not set `VITE_SENTRY_DSN`. This is correct — CI should not have an active DSN. The `enabled: !!import.meta.env.VITE_SENTRY_DSN` guard ensures CI builds are unaffected. Verify this explicitly in the PR by checking that the CI build log contains no Sentry initialization messages. **Self-hosted catalogue** `docs/infrastructure/self-hosted-catalogue.md` already documents GlitchTip with a Docker Compose snippet. The Compose snippet uses `image: glitchtip/glitchtip:latest` — this violates the pinned-tag convention. That pre-existing issue is out of scope for this PR, but worth noting for the GlitchTip infrastructure issue. **Source map upload in production builds** If the `@sentry/sveltekit` Vite plugin is added (for source map upload), it will require a `SENTRY_AUTH_TOKEN` environment variable during `npm run build`. This must be handled in the production build pipeline, **not** in CI test runs. The release workflow (`.gitea/workflows/release.yml`) would need this secret. Confirm whether source map upload is in scope for this issue or deferred to a follow-up. **Package lock file** The issue correctly lists `package-lock.json` as a required update. Confirm that the lockfile is committed alongside `package.json` — both must be in the same commit to avoid "lockfile out of sync" errors on the next `npm ci`. ### Recommendations - **Add `VITE_SENTRY_DSN=` to `.env.example` as part of this PR** — the issue says "confirm this line exists" but it doesn't. This is a required deliverable. - Do **not** add the `@sentry/sveltekit` Vite plugin (source map upload) in this issue unless a `SENTRY_AUTH_TOKEN` secret is already configured in Gitea secrets. Keep the scope to SDK init + `handleError` only. Source map upload can be a follow-up once the GlitchTip project is established. - Add a note to `docs/infrastructure/self-hosted-catalogue.md` that the SvelteKit app uses `VITE_SENTRY_DSN` to connect to GlitchTip — so operators know to set it when standing up the stack.
Author
Owner

📋 Elicit — Requirements Engineer

Observations

Acceptance criteria completeness

The six ACs are well-structured and cover the key behaviors. However, two ACs have verifiability gaps:

  • AC 5 ("event appears in GlitchTip within 30 seconds") depends on the GlitchTip infrastructure issue being completed first. This is correctly flagged as a dependency in the issue body, but the dependency is not linked to a specific issue number in the tracker. Without a concrete link, this AC cannot be closed reliably.
  • AC 6 ("stack trace pointing to the correct source file and line") implicitly depends on source maps being available. The issue does not specify whether source maps are uploaded to GlitchTip or whether stack traces are verified against minified output. The AC is ambiguous as written.

Scope boundary

The issue scope is @sentry/sveltekit only. Backend Spring Boot error reporting (Sentry Java SDK) is out of scope and not mentioned — this is appropriate. However, the "Definition of Done" should clarify that GlitchTip will only receive frontend errors after this issue, and backend errors require a separate issue.

Missing non-functional requirements

The issue does not state:

  • What happens when GlitchTip is unreachable (network timeout, service down) — the app must not degrade
  • Whether tracesSampleRate: 1.0 is the intended production setting or a placeholder
  • Whether PII scrubbing is required (family names, email addresses in error context)

Definition of Done vs Acceptance Criteria overlap

The DoD largely repeats the ACs. "All acceptance criteria checked" is self-referential. The DoD should add conditions not already in the ACs, e.g.: "No performance regression observed in npm run build output size."

Recommendations

  • Clarify AC 6: either (a) accept that minified stack traces are sufficient for a first integration and remove the "correct source file and line" qualifier, or (b) add source map upload as an explicit task and AC.
  • Tighten AC 5: link the GlitchTip infrastructure issue by number, e.g. "Depends on #XXX".
  • Add a resilience AC: "When GlitchTip is unreachable, page load time is unaffected and no user-visible error occurs."
  • Clarify tracesSampleRate: state whether 1.0 is the intended production value or a development placeholder. If it is production-intended, document the rationale.
## 📋 Elicit — Requirements Engineer ### Observations **Acceptance criteria completeness** The six ACs are well-structured and cover the key behaviors. However, two ACs have verifiability gaps: - AC 5 ("event appears in GlitchTip within 30 seconds") depends on the GlitchTip infrastructure issue being completed first. This is correctly flagged as a dependency in the issue body, but the dependency is not linked to a specific issue number in the tracker. Without a concrete link, this AC cannot be closed reliably. - AC 6 ("stack trace pointing to the correct source file and line") implicitly depends on source maps being available. The issue does not specify whether source maps are uploaded to GlitchTip or whether stack traces are verified against minified output. The AC is ambiguous as written. **Scope boundary** The issue scope is `@sentry/sveltekit` only. Backend Spring Boot error reporting (Sentry Java SDK) is out of scope and not mentioned — this is appropriate. However, the "Definition of Done" should clarify that GlitchTip will only receive frontend errors after this issue, and backend errors require a separate issue. **Missing non-functional requirements** The issue does not state: - What happens when GlitchTip is unreachable (network timeout, service down) — the app must not degrade - Whether `tracesSampleRate: 1.0` is the intended production setting or a placeholder - Whether PII scrubbing is required (family names, email addresses in error context) **Definition of Done vs Acceptance Criteria overlap** The DoD largely repeats the ACs. "All acceptance criteria checked" is self-referential. The DoD should add conditions not already in the ACs, e.g.: "No performance regression observed in `npm run build` output size." ### Recommendations - **Clarify AC 6**: either (a) accept that minified stack traces are sufficient for a first integration and remove the "correct source file and line" qualifier, or (b) add source map upload as an explicit task and AC. - **Tighten AC 5**: link the GlitchTip infrastructure issue by number, e.g. "Depends on #XXX". - **Add a resilience AC**: "When GlitchTip is unreachable, page load time is unaffected and no user-visible error occurs." - **Clarify `tracesSampleRate`**: state whether `1.0` is the intended production value or a development placeholder. If it is production-intended, document the rationale.
Author
Owner

🗳️ Decision Queue — Action Required

3 decisions need your input before implementation starts.

Observability / Configuration

  • tracesSampleRate: 1.0 vs 0 — Setting 1.0 enables full performance tracing (every request sent to GlitchTip), while 0 captures errors only. For a family archive focused on error visibility rather than APM, 0 avoids noise and reduces outbound traffic. If you want performance traces from day one, keep 1.0 and accept the extra GlitchTip event volume. (Raised by: Markus, Nora)

Security / Privacy

  • PII scrubbing in beforeSend — The AppUser object (email, groups) from event.locals.user may end up in GlitchTip error reports. Even on a self-hosted instance, you may not want user data in error logs. Options: (a) add a beforeSend hook that deletes event.user, (b) accept the exposure because GlitchTip is self-hosted and family-only, (c) defer to a hardening follow-up. (Raised by: Nora)

Scope

  • Source maps: in scope or follow-up? — AC 6 ("stack trace pointing to the correct source file and line") requires source maps uploaded to GlitchTip, which requires the @sentry/sveltekit Vite plugin and a SENTRY_AUTH_TOKEN secret in the release pipeline. Options: (a) descope AC 6 / accept minified stack traces for now and do source maps in a follow-up issue, (b) extend this issue to include the Vite plugin + secret setup. Tobias recommends option (a) to keep this PR minimal. (Raised by: Nora, Tobias, Elicit)
## 🗳️ Decision Queue — Action Required _3 decisions need your input before implementation starts._ ### Observability / Configuration - **`tracesSampleRate`: `1.0` vs `0`** — Setting `1.0` enables full performance tracing (every request sent to GlitchTip), while `0` captures errors only. For a family archive focused on error visibility rather than APM, `0` avoids noise and reduces outbound traffic. If you want performance traces from day one, keep `1.0` and accept the extra GlitchTip event volume. _(Raised by: Markus, Nora)_ ### Security / Privacy - **PII scrubbing in `beforeSend`** — The `AppUser` object (email, groups) from `event.locals.user` may end up in GlitchTip error reports. Even on a self-hosted instance, you may not want user data in error logs. Options: (a) add a `beforeSend` hook that deletes `event.user`, (b) accept the exposure because GlitchTip is self-hosted and family-only, (c) defer to a hardening follow-up. _(Raised by: Nora)_ ### Scope - **Source maps: in scope or follow-up?** — AC 6 ("stack trace pointing to the correct source file and line") requires source maps uploaded to GlitchTip, which requires the `@sentry/sveltekit` Vite plugin and a `SENTRY_AUTH_TOKEN` secret in the release pipeline. Options: (a) descope AC 6 / accept minified stack traces for now and do source maps in a follow-up issue, (b) extend this issue to include the Vite plugin + secret setup. Tobias recommends option (a) to keep this PR minimal. _(Raised by: Nora, Tobias, Elicit)_
Author
Owner

Implementation complete. PR #591 opened: #591

What was done:

  • Installed @sentry/sveltekit (94 transitive deps added)
  • Created frontend/src/hooks.client.ts — new file with Sentry.init() and handleError = Sentry.handleErrorWithSentry() for browser-side error capture
  • Updated frontend/src/hooks.server.ts — added Sentry.init() block at the top and handleError = Sentry.handleErrorWithSentry() at the bottom; the existing handle = sequence(userGroup, handleAuth, handleLocaleDetection, handleParaglide) is preserved intact
  • VITE_SENTRY_DSN was already in .env.example from the scaffold issue — no change needed

Gating: enabled: !!import.meta.env.VITE_SENTRY_DSN — when the env var is unset (the default), Sentry is fully disabled and no requests are made.

Validation: npm run build passes cleanly. npm run check shows no errors in the hooks files (pre-existing type errors in other files are unrelated).

Implementation complete. PR #591 opened: https://git.raddatz.cloud/marcel/familienarchiv/pulls/591 **What was done:** - Installed `@sentry/sveltekit` (94 transitive deps added) - Created `frontend/src/hooks.client.ts` — new file with `Sentry.init()` and `handleError = Sentry.handleErrorWithSentry()` for browser-side error capture - Updated `frontend/src/hooks.server.ts` — added `Sentry.init()` block at the top and `handleError = Sentry.handleErrorWithSentry()` at the bottom; the existing `handle = sequence(userGroup, handleAuth, handleLocaleDetection, handleParaglide)` is preserved intact - `VITE_SENTRY_DSN` was already in `.env.example` from the scaffold issue — no change needed **Gating:** `enabled: !!import.meta.env.VITE_SENTRY_DSN` — when the env var is unset (the default), Sentry is fully disabled and no requests are made. **Validation:** `npm run build` passes cleanly. `npm run check` shows no errors in the hooks files (pre-existing type errors in other files are unrelated).
Author
Owner

Implementation complete — merged via PR #591

What was implemented:

  • frontend/src/hooks.client.ts — new file; browser-side Sentry error capture with Sentry.init() gated on VITE_SENTRY_DSN presence
  • frontend/src/hooks.server.ts — SSR handleError via Sentry.handleErrorWithSentry(); existing handle sequence untouched
  • frontend/vite.config.ts — added sentrySvelteKit() as first Vite plugin with autoUploadSourceMaps: !!process.env.SENTRY_AUTH_TOKEN (skips upload when token absent in CI)
  • frontend/package.json@sentry/sveltekit: ^10.53.1 added to dependencies
  • .env.exampleSENTRY_AUTH_TOKEN= stub added

CI note: Backend Unit Tests failed due to surefire RAM timeout (25 min, known flaky infrastructure issue) — no Java code in this PR; all frontend/TypeScript jobs passed.

Commits: b4e6e4ca, 00a8731c

## ✅ Implementation complete — merged via PR #591 **What was implemented:** - `frontend/src/hooks.client.ts` — new file; browser-side Sentry error capture with `Sentry.init()` gated on `VITE_SENTRY_DSN` presence - `frontend/src/hooks.server.ts` — SSR `handleError` via `Sentry.handleErrorWithSentry()`; existing `handle` sequence untouched - `frontend/vite.config.ts` — added `sentrySvelteKit()` as first Vite plugin with `autoUploadSourceMaps: !!process.env.SENTRY_AUTH_TOKEN` (skips upload when token absent in CI) - `frontend/package.json` — `@sentry/sveltekit: ^10.53.1` added to `dependencies` - `.env.example` — `SENTRY_AUTH_TOKEN=` stub added **CI note:** Backend Unit Tests failed due to surefire RAM timeout (25 min, known flaky infrastructure issue) — no Java code in this PR; all frontend/TypeScript jobs passed. Commits: `b4e6e4ca`, `00a8731c`
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#579