feat(ui): add Sentry Browser SDK client-side integration

- Add 3 new config fields for browser SDK sample rates:
  sentry_js_traces_sample_rate (default 0.0),
  sentry_js_replay_session_sample_rate (default 0.0),
  sentry_js_replay_on_error_sample_rate (default 0.1)
- Expose Sentry config to Jinja2 templates via _inject_global_context;
  empty-string DSN normalized to None so {% if sentry_dsn %} guard works
- Load Sentry Browser SDK bundle.tracing.replay.min.js from the official
  Sentry CDN in base.html when SENTRY_DSN is configured, with Sentry.init()
  for error capture, browser tracing and session replay
- Register new JS settings fields in SETTING_METADATA so they appear on the
  admin Settings → Observability page
- Update .env.demo with commented-out examples for SENTRY_JS_* variables
- Update docs/ConfigurationGuide.md and docs/SentrySetup.md with full
  browser SDK documentation, env-specific examples and troubleshooting
- Add TestSentryJsTemplateContext (5 tests) and TestSentryJsConfig (4 tests)

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
Agent-Logs-Url: https://github.com/christianlouis/DocuElevate/sessions/4a945567-67df-4264-aaed-75eb2e236e9c
This commit is contained in:
copilot-swe-agent[bot]
2026-03-22 14:13:10 +00:00
parent 2ea35d419c
commit b202f10e1a
8 changed files with 347 additions and 17 deletions
+34
View File
@@ -1309,6 +1309,40 @@ class Settings(BaseSettings):
),
)
# ---------------------------------------------------------------------------
# Observability Sentry Browser JavaScript SDK (client-side)
# ---------------------------------------------------------------------------
# The same SENTRY_DSN is reused for the browser SDK. The DSN is a *public*
# key in Sentry's model and is intentionally embedded in client-side code.
# All three settings below default to 0.0 / disabled so that operators opt-in
# to the level of browser monitoring they want.
# ---------------------------------------------------------------------------
sentry_js_traces_sample_rate: float = Field(
default=0.0,
description=(
"Fraction of browser page-loads captured for client-side performance tracing "
"(0.0 1.0). 0.0 disables browser tracing; 1.0 captures every navigation. "
"Only active when SENTRY_DSN is set."
),
)
sentry_js_replay_session_sample_rate: float = Field(
default=0.0,
description=(
"Fraction of sessions recorded by Sentry Session Replay (0.0 1.0). "
"0.0 disables session recording; 1.0 records every session. "
"Only active when SENTRY_DSN is set."
),
)
sentry_js_replay_on_error_sample_rate: float = Field(
default=0.1,
description=(
"Fraction of sessions with an error that will be recorded by Sentry Session "
"Replay (0.0 1.0). Defaults to 0.1 (10 %) so that errors are captured "
"with replay context even when session-level recording is disabled. "
"Only active when SENTRY_DSN is set."
),
)
@model_validator(mode="before")
@classmethod
def strip_outer_quotes(cls, data: Any) -> Any: