feat(monitoring): #45 consent-gated Sentry error monitoring (client-only, PII-scrubbed)#145
Merged
Merged
Conversation
…nly, PII-scrubbed) Scaffolds Sentry error monitoring for the static-export app. Client-only (@sentry/react, not @sentry/nextjs — withSentryConfig needs a Next server), gated on analytics consent via ConsentContext (mirrors GoogleAnalytics), and inert until NEXT_PUBLIC_SENTRY_DSN is set (empty DSN = no-op, so it ships now and goes live with zero code change once a DSN is provided). - src/lib/monitoring/scrub.ts — pure PII scrubber (emails, JWTs, Bearer/token k-v, sb-<ref>-auth-token keys; whole-value redaction of message bodies content/plaintext_content/new_content/encrypted_content/password). Used as beforeSend. 15 unit tests. - src/lib/monitoring/sentry.ts — idempotent init (no-op without DSN/on SSR), closeSentry on consent withdrawal, guarded captureAppError. Replay + tracing disabled so the encrypted messaging UI is never recorded. 6 tests. - src/lib/monitoring/SentryMonitor/ — 5-file consent-gated client component. - src/utils/error-handler.ts — single capture chokepoint in sendToService (ErrorBoundary already routes here → exactly one captureException per error). - layout.tsx mounts <SentryMonitor/> + adds Sentry ingest hosts to CSP connect-src (static export has no header CSP; envelopes would be blocked). - .env.example / deploy.yml / README document NEXT_PUBLIC_SENTRY_DSN. Closes #45. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Scaffolds Sentry error monitoring for the static-export app (issue #45). Client-only, consent-gated, PII-scrubbed, and inert until a DSN is configured — so it ships now and goes live with zero code change once
NEXT_PUBLIC_SENTRY_DSNis set.Why client-only
The app is
output: 'export'(GitHub Pages).@sentry/nextjs/withSentryConfig/instrumentation.tsall require a Next server, so this uses@sentry/react(re-exports the browser SDK) and initializes purely on the client, mirroring the existing consent-gatedGoogleAnalytics.How it works
src/lib/monitoring/scrub.ts— pure, SDK-free PII scrubber used asbeforeSend: redacts emails, JWTs,Bearer/access_token/refresh_token,sb-<ref>-auth-tokenkeys, and whole-value-redacts message-body fields (content,plaintext_content,new_content,encrypted_content,password). 15 unit tests.src/lib/monitoring/sentry.ts— idempotentinitSentry(no-op without DSN / on SSR),closeSentryon consent withdrawal, guardedcaptureAppError. Replay + tracing disabled so the E2E-encrypted messaging UI is never recorded. 6 tests.src/lib/monitoring/SentryMonitor/— 5-file consent-gated client component; inits only after analytics consent, shuts down on withdrawal.src/utils/error-handler.ts— single capture chokepoint insendToService(ErrorBoundary already routes here → exactly onecaptureExceptionper handled error). 2 tests.layout.tsx— mounts<SentryMonitor/>beside<GoogleAnalytics/>and adds Sentry ingest hosts to the CSPconnect-src(static export has no header CSP — without this, envelopes are silently blocked)..env.example/deploy.yml/README.md— documentNEXT_PUBLIC_SENTRY_DSN(build-time inlined, so wired into the deploy build env).Going live (for the maintainer)
A DSN is a sentry.io connection string (not DNS, not derivable from the domain). Create a free Next.js project at sentry.io → copy the DSN from Client Keys (DSN) → set it in
.env+ add theNEXT_PUBLIC_SENTRY_DSNActions secret. Monitoring then activates automatically (after the user grants analytics consent).Verification
pnpm run type-check✅pnpm run lint✅pnpm run validate:structure✅ (110/110)pnpm run build✅ — compiles and prerenders with an empty DSN (Sentry no-ops) under static exportCloses #45.
🤖 Generated with Claude Code