diff --git a/aidlc-docs/features/react-frontend/audit.md b/aidlc-docs/features/react-frontend/audit.md index d63e40e..ecf0642 100644 --- a/aidlc-docs/features/react-frontend/audit.md +++ b/aidlc-docs/features/react-frontend/audit.md @@ -516,3 +516,15 @@ **Context**: Post-workflow follow-up (feature already marked Complete); continues the `feature/sentry_error_logging` branch. Build/lint/test re-verified after the change. --- + +## Post-Completion Follow-up: Sentry "Tunnel" Added to Bypass Ad-Blocker on Test Environment + +**Timestamp**: 2026-07-25T15:30:00Z + +**User Input**: "Op de testomgeving heb ik hetzelfde. Laten we de tunnel-fix toevoegen" (confirming the same `ERR_BLOCKED_BY_CLIENT` ad-blocker issue also occurs on the test environment, after previously choosing "just disable the ad-blocker" for local development). + +**AI Response**: "Added `tunnel: import.meta.env.DEV ? undefined : '/sentry-tunnel'` to `Sentry.init()` in `src/main.tsx`, so built (test/production) environments route Sentry traffic through the app's own domain instead of posting straight to `*.ingest.de.sentry.io` — this makes the request first-party from the browser's perspective, so ad-blockers no longer recognize/block it as third-party tracking. Local development is left untouched (tunnel stays `undefined`), since the user already resolved that case by disabling the ad-blocker. Added a `location /sentry-tunnel` block to `nginx/reverse-proxy-nginx.conf.example` that forwards to Sentry's envelope endpoint for the specific org/project baked into the DSN, with a comment flagging that this must be kept in sync if the Sentry project/DSN ever changes. Updated `monitoring-setup.md` with a new bullet explaining the tunnel approach, why it works here (full control over the reverse-proxy Pi's nginx config) and its limitation (would not work on a third-party host without reverse-proxy access)." + +**Context**: Post-workflow follow-up (feature already marked Complete); continues the `feature/sentry_error_logging` branch. `pnpm run build`, `pnpm run lint` and `pnpm run test` re-verified successfully after the change. Changes not yet committed/pushed. + +--- diff --git a/aidlc-docs/features/react-frontend/operations/deployment/nginx/reverse-proxy-nginx.conf.example b/aidlc-docs/features/react-frontend/operations/deployment/nginx/reverse-proxy-nginx.conf.example index 15b20a6..6c53633 100644 --- a/aidlc-docs/features/react-frontend/operations/deployment/nginx/reverse-proxy-nginx.conf.example +++ b/aidlc-docs/features/react-frontend/operations/deployment/nginx/reverse-proxy-nginx.conf.example @@ -35,6 +35,24 @@ server { root /var/www/certbot; } + # Sentry "tunnel" endpoint (see src/main.tsx's Sentry.init tunnel option). + # Browser ad-blockers/privacy extensions commonly block requests that go + # straight to *.ingest..sentry.io (ERR_BLOCKED_BY_CLIENT), since + # that looks like third-party tracking. By forwarding this path server-side + # to Sentry instead, the browser only ever talks to our own domain + # (test.slpsoftware.nl), so it is no longer recognized/blocked as + # third-party tracking. + # + # LET OP: de org-/project-id in de proxy_pass hieronder MOET overeenkomen + # met de VITE_SENTRY_DSN die voor DEZE omgeving is ingesteld (de + # `VITE_SENTRY_DSN` Gitea repository variable voor de testomgeving). Pas + # dit aan als je ooit van Sentry-project/DSN wisselt. + location /sentry-tunnel { + proxy_pass https://o4511795618185216.ingest.de.sentry.io/api/4511795622838352/envelope/; + proxy_set_header Host o4511795618185216.ingest.de.sentry.io; + proxy_ssl_server_name on; + } + location / { proxy_pass http://192.168.1.103:80; proxy_set_header Host $host; diff --git a/aidlc-docs/features/react-frontend/operations/monitoring/monitoring-setup.md b/aidlc-docs/features/react-frontend/operations/monitoring/monitoring-setup.md index c6ae220..04fb196 100644 --- a/aidlc-docs/features/react-frontend/operations/monitoring/monitoring-setup.md +++ b/aidlc-docs/features/react-frontend/operations/monitoring/monitoring-setup.md @@ -25,6 +25,7 @@ Both the console and Sentry are now active (original Question 3 resolved as a co - **Manual follow-up required**: create a free Sentry project (https://sentry.io) for this app, copy its DSN, and set it as the `VITE_SENTRY_DSN` repository variable in Gitea (Repository Settings → Actions → Variables). Until that variable is set, the build still succeeds and the site still works — Sentry reporting simply stays inactive. - Free tier limits (error volume, retention) are typically sufficient for a low-traffic marketing site. - **Not (yet) implemented, by explicit choice**: automatic source map upload (via `@sentry/vite-plugin`), which the official Sentry setup guide also recommends so stack traces show real source code instead of minified code. This requires a Sentry auth token/org/project as a new Gitea secret; deliberately left out of scope for now — revisit if readable production stack traces become a priority. +- **Ad-blocker mitigation via a Sentry "tunnel" (test/production only)**: requests straight to `*.ingest..sentry.io` are commonly blocked client-side by ad-blockers/privacy extensions (`ERR_BLOCKED_BY_CLIENT`), because they resemble third-party tracking. To avoid this in deployed environments, `Sentry.init()` sets `tunnel: '/sentry-tunnel'` (disabled — `undefined` — during local `pnpm dev`, where the ad-blocker itself is disabled instead, per earlier decision). The reverse-proxy Pi (`nginx/reverse-proxy-nginx.conf.example`) forwards that path server-side to Sentry's envelope endpoint, so the browser only ever talks to the first-party domain (e.g. `test.slpsoftware.nl`). This relies on full control over the reverse-proxy's nginx config, which is the case here (self-hosted on the user's own Raspberry Pi's) — it would not work on a third-party/shared host without reverse-proxy access. **Important**: the org-/project-id hardcoded in that nginx `location /sentry-tunnel` block must match whatever `VITE_SENTRY_DSN` is actually configured for that environment; update both together if the Sentry project/DSN ever changes. **Log level strategy**: only errors are logged (no verbose/info-level client logging) — this is a static site with no meaningful "business events" beyond page views, which are covered by analytics (see Dashboards below), not logging. diff --git a/src/main.tsx b/src/main.tsx index a0bb275..5b98daa 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -20,6 +20,13 @@ if (sentryDsn) { tracesSampleRate: 1.0, // Required for Sentry.logger.* calls (e.g. the temporary SentryTestButton) to actually be sent. enableLogs: true, + // Ad-blockers/privacy extensions commonly block requests straight to *.ingest.sentry.io + // (ERR_BLOCKED_BY_CLIENT), because it looks like third-party tracking. Routing through our + // own domain via a reverse-proxy "tunnel" avoids that (see nginx/reverse-proxy-nginx.conf.example). + // Only enabled for built (test/production) environments — local dev (`pnpm dev`) has no such + // proxy route available, so it keeps posting straight to Sentry (resolved by disabling the + // ad-blocker locally instead). + tunnel: import.meta.env.DEV ? undefined : '/sentry-tunnel', }); }