Files
SlpSoftware/aidlc-docs/features/react-frontend/operations/monitoring/monitoring-setup.md
T
2026-07-25 15:46:58 +02:00

9.3 KiB

Monitoring Setup Instructions

Concrete setup steps for the approaches chosen in monitoring-plan.md: Logging and Dashboards (no Alerting).

Logging

What to log

  • Uncaught JavaScript errors / exceptions (the app already has an ErrorBoundary component from Code Generation — this is the natural hook point).
  • Broken/failed navigation (e.g. an unexpected router error).
  • No user PII, form input, or sensitive data should ever be logged — this is a public marketing site, but keep this discipline regardless.

Destination — decided: Sentry free tier + console

Both the console and Sentry are now active (original Question 3 resolved as a combination):

Console (always on)

  • Errors already surface via console.error inside ErrorBoundary.componentDidCatch — unchanged, zero cost, useful for local/manual debugging.

Sentry free tier (implemented)

  • @sentry/react is a dependency; src/main.tsx calls Sentry.init({ ... }) at startup, but only when a DSN is present — if not configured, Sentry is silently skipped and only console-logging remains active (safe default, no crash on missing config).
  • ErrorBoundary.componentDidCatch calls Sentry.captureException(error, { extra: { componentStack: info.componentStack } }) in addition to console.error.
  • Tracing/performance is also enabled (Sentry's recommended default alongside error monitoring, per the official React SDK setup guide): tanstackRouterBrowserTracingIntegration(router) is wired up so route navigations are captured as transactions, with tracesSampleRate: 1.0 (capture all — appropriate for a low-traffic marketing site; lower this if traffic grows significantly).
  • Environment/release tagging: environment is set to import.meta.env.VITE_APP_ENV ('test' / 'production', set at build time — see below), falling back to import.meta.env.MODE for local development (pnpm dev'development'). This fallback is needed because vite build runs in production mode by default regardless of target environment, so MODE alone cannot distinguish a test build from a production build. release is set to the app version from package.json (injected at build time via vite.config.ts's define: { __APP_VERSION__ }), so events in Sentry can be filtered/grouped per environment and per shipped version.
  • The DSN is injected at build time via Vite's import.meta.env.VITE_SENTRY_DSN (typed in src/vite-env.d.ts). It is not a secret (Sentry DSNs are safe to expose client-side), so it is passed as a Gitea Actions repository variable (vars.VITE_SENTRY_DSN, not a secret) to the Build step in continuous_integration.yaml.
  • Local development DSN: for pnpm dev, Vite automatically loads a .env.local file (already covered by .gitignore's *.local rule, so it is never committed). Copy .env.example to .env.local and set VITE_SENTRY_DSN there to enable Sentry locally — a separate Sentry project/DSN is recommended so local test noise doesn't mix with the test-environment data. Omitting .env.local (or leaving the value empty) simply disables Sentry locally, falling back to console-only logging.
  • 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" (all environments, including local): requests straight to *.ingest.<region>.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, Sentry.init() always sets tunnel: '/sentry-tunnel'. In deployed (test/production) environments, 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). Locally (pnpm dev), the equivalent route is provided by Vite's own dev-server proxy (server.proxy in vite.config.ts), so no ad-blocker whitelisting/disabling is needed anymore for local testing either. 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 both the nginx location /sentry-tunnel block and the Vite server.proxy target must match whatever VITE_SENTRY_DSN/.env.local DSN is actually configured; update all 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.

Temporary manual test tool: SentryTestButton

  • src/components/SentryTestButton.tsx renders a "Break the world" button, mounted globally via RootLayout.tsx, used to manually verify that errors, logs (Sentry.logger.info), and metrics (Sentry.metrics.count) actually arrive in Sentry end-to-end.
  • Visibility: only shown during local development (pnpm dev, via Vite's import.meta.env.DEV) and in the test environment (via the new build-time VITE_APP_ENV variable, set to test by continuous_integration.yaml's Build step). It is hidden by default (including in any future production build) unless one of those conditions is explicitly true.
  • Visual feedback: clicking the button immediately shows a green confirmation toast ("Test error verzonden naar Sentry ", role="status") that auto-hides after 4 seconds, so the user gets clear confirmation that the test action fired — without this, the resulting uncaught error/blank state gave no indication anything happened. The actual log/metric/throw (handleSentryTestErrorClick) is fired on the next tick (setTimeout(..., 0)) so the toast has a chance to render/paint first.
  • Sentry.logger.* requires enableLogs: true in Sentry.init() (src/main.tsx) — added specifically to support this test button (and any future structured logging).
  • The thrown error is intentionally uncaught: React error boundaries do not catch errors thrown from event handlers (only render/lifecycle errors), so this relies on Sentry's own global window.onerror handler, exactly like the official Sentry test snippet.
  • This is a temporary verification tool, not a permanent feature — remove SentryTestButton (and its usage in RootLayout.tsx) once Sentry has been confirmed to receive test errors/logs/metrics end-to-end.

Dashboards

Website analytics

Pick one (all have generous free tiers suitable for a small marketing site):

Option Notes
Plausible / Umami Privacy-friendly, lightweight, no cookie banner typically required; self-hosted or low-cost hosted tier
Google Analytics (GA4) / Search Console Free, widely known, but heavier script and involves third-party data sharing (cookie/consent implications)

Setup (once a tool is picked):

  1. Create an account/site entry with the chosen provider and obtain the tracking snippet or <script> tag.
  2. Add the snippet to index.html (or load it conditionally in src/main.tsx) — this is a documentation/config task, not something the current codebase needs restructuring for.
  3. Key metrics to surface: unique visitors, page views per route (Home, Packages, etc. — see frontend-components.md), and referral sources.

Uptime dashboard

Pick one:

Option Notes
UptimeRobot Free tier: up to 50 monitors, 5-minute check interval, optional e-mail notification on downtime (opportunistic, not a designed alerting feature per monitoring-plan.md)
Better Uptime Free tier available; similar capability, nicer public status page option

Setup (once a tool is picked):

  1. Register the production URL (once hosting is finalized — see operations/deployment/deployment-plan.md "Open Item") as an HTTP(S) monitor, checking for a 200 response.
  2. Optional: publish a public status page if desired for transparency to visitors.
  3. Key metric to surface: uptime percentage / current status.

Summary Table

Concern Approach Status
Client-side errors Logging (console + Sentry free tier) Implemented; VITE_SENTRY_DSN Gitea variable still needs to be created by the user
Visitor/usage insight Analytics dashboard (Plausible/Umami/GA4) Tool selection open item
Site reachability Uptime dashboard (UptimeRobot/Better Uptime) Tool selection + production URL open item
Alerting Out of scope Not configured
Shared infrastructure reuse Out of scope None exists yet