diff --git a/.env.example b/.env.example index 8dba92c3..1b59d08b 100644 --- a/.env.example +++ b/.env.example @@ -12,5 +12,9 @@ VITE_API_URL=https://api.seahavenindustries.com/api # Leave blank to disable telemetry for that build. VITE_SENTRY_DSN= +# Sentry environment label (development, staging, production). Blank falls back +# to the Vite build mode. +#VITE_SENTRY_ENVIRONMENT= + # Development proxy target (used by vite.config.ts) #VITE_API_TARGET=http://localhost:5141 diff --git a/.env.production b/.env.production index 205c2f1a..6ca55486 100644 --- a/.env.production +++ b/.env.production @@ -3,5 +3,8 @@ # and prod builds must override VITE_API_URL per environment (api.staging..., etc.). VITE_API_URL=https://api.dev.seahaven.com/api -# Public browser configuration; deployment must provide the environment's Sentry DSN. -VITE_SENTRY_DSN= +# Public browser configuration; the DSN is public by design and baked into the +# bundle. Blank disables telemetry. These are the DEV deploy values: staging +# and future prod jobs override them per environment. +VITE_SENTRY_DSN=https://902f431c6e762aa849c9a07b77f0c3ac@o4511989453029376.ingest.de.sentry.io/4511990364700752 +VITE_SENTRY_ENVIRONMENT=development diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index eed6460e..708fac98 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -32,6 +32,7 @@ jobs: environment: staging env: VITE_API_URL: https://api.staging.seahaven.com/api + VITE_SENTRY_ENVIRONMENT: staging AWS_REGION: us-east-1 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -68,9 +69,10 @@ jobs: role-to-assume: arn:aws:iam::396287094661:role/githubdeploy-shoc-frontend-new-staging aws-region: us-east-1 - # Builds the SPA with the staging VITE_API_URL (process env overrides the - # dev value committed in .env.production), syncs to the staging bucket, - # and invalidates CloudFront. + # Builds the SPA with the staging VITE_API_URL and Sentry environment + # label (process env overrides the dev values committed in + # .env.production), syncs to the staging bucket, and invalidates + # CloudFront. - name: Build and publish SPA run: bash scripts/deploy-web.sh env: diff --git a/docs/adr/0002-sentry-observability.md b/docs/adr/0002-sentry-observability.md index d29ee772..02c0b549 100644 --- a/docs/adr/0002-sentry-observability.md +++ b/docs/adr/0002-sentry-observability.md @@ -22,14 +22,23 @@ the configured `VITE_API_URL` base. The DSN comes from `VITE_SENTRY_DSN`. It is intentionally treated as public browser configuration because every `VITE_` value is embedded in the built -JavaScript. A missing or blank DSN leaves telemetry inactive without preventing +JavaScript. `.env.production` commits the public DSN of the real +`shoc-frontend` Sentry project, so dev and staging deploys are live; a missing +or blank DSN in any other build leaves telemetry inactive without preventing the application from starting. Default personally identifiable information collection remains disabled. -Source-map upload is outside this change. It requires a Sentry organization, -project, and scoped upload token that are not currently available, plus an -explicit deployment design for handling that credential without exposing it in -the browser bundle. +The Sentry environment label comes from `VITE_SENTRY_ENVIRONMENT` when set and +non-blank, falling back to the Vite build mode otherwise. The committed +`.env.production` labels dev deploys `development`, the staging deploy job +overrides the label to `staging`, and a future production pipeline can set +`production` without code changes. + +Source-map upload is outside this change. The Sentry organization and the +`shoc-frontend` project now exist and receive telemetry through the committed +public DSN, but upload still requires a scoped upload token that is not +currently available, plus an explicit deployment design for handling that +credential without exposing it in the browser bundle. ### Alternatives considered @@ -46,6 +55,9 @@ the browser bundle. - Browser navigations and API requests are recorded as connected transactions when the deployment supplies a valid DSN. +- Events are labeled by `VITE_SENTRY_ENVIRONMENT` (`development` on dev + deploys, `staging` on the staging job), falling back to the Vite build mode + when unset. - Every transaction is sampled. This meets the current requirement but increases event volume and should be reviewed against Sentry quota and retention after real traffic is measured. diff --git a/src/observability/sentry.ts b/src/observability/sentry.ts index 9a37cf51..156e44b1 100644 --- a/src/observability/sentry.ts +++ b/src/observability/sentry.ts @@ -10,11 +10,12 @@ import { import { env } from "@/lib/env"; const sentryDsn = import.meta.env.VITE_SENTRY_DSN?.trim() || undefined; +const sentryEnvironment = import.meta.env.VITE_SENTRY_ENVIRONMENT?.trim() || import.meta.env.MODE; const apiBaseUrl = new URL(env.apiUrl, window.location.origin).toString(); Sentry.init({ dsn: sentryDsn, - environment: import.meta.env.MODE, + environment: sentryEnvironment, integrations: [ Sentry.reactRouterBrowserTracingIntegration({ useEffect, diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 4df1f98f..c7b43287 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -3,6 +3,8 @@ interface ImportMetaEnv { readonly VITE_API_URL: string; readonly VITE_API_TARGET: string; + readonly VITE_SENTRY_DSN?: string; + readonly VITE_SENTRY_ENVIRONMENT?: string; } interface ImportMeta {