> ## Documentation Index
> Fetch the complete documentation index at: https://docs.soundchecklive.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Monitoring

> Error tracking and observability with Sentry

Soundcheck uses Sentry for error tracking across environments. Mobile reports errors and structured logs to `soundcheck-live/react-native`. Mobile tracing, profiling and session replay are disabled.

## Mobile release builds

Set `EXPO_PUBLIC_SENTRY_DSN` for the `react-native` project in each EAS environment used below. Set `SENTRY_AUTH_TOKEN` as a secret upload credential in those environments. The token needs source-map upload access to that project. Never use an `EXPO_PUBLIC_` prefix for the token or put it in Expo `extra`.

Roll out the sanitizer and privacy callbacks before activating the DSN for shared EAS environments. The upload token can be provisioned first because it does not enable runtime reporting. To validate this branch before rollout, supply the DSN only to a controlled local production-profile build or a dedicated EAS validation environment that builds this exact branch. Do not activate the DSN for concurrent builds from branches that lack the sanitizer.

EAS profiles choose credentials independently of the event environment label.

| Build profile | EAS credential environment | Sentry event environment |
| - | - | - |
| `development` | `development` | `development` |
| `preview` | `preview` | `preview` |
| `revyl` | `development` | `revyl` |
| `qa` | `production` | `qa` |
| `production` | `production` | `production` |

`revyl` is a standalone simulator build. It does not provide production acceptance evidence. `qa` shares production credentials but reports its own environment. Release build workers for `preview`, `revyl`, `qa` and `production` warn when the DSN or upload token is missing. Set `SENTRY_REQUIRE=1` to make missing credentials fail the build after provisioning. Local Expo configuration evaluation remains available without these credentials.

The Expo Sentry plugin uploads native release source maps. Metro composes the Sentry and PostHog asset serialization plugins through Expo's single serializer so both use the bundle debug ID. PostHog upload configuration remains independent and uses `POSTHOG_CLI_TOKEN` and `POSTHOG_CLI_ENV_ID`.

The Sentry SDK supplies the native release identifier, `com.soundchecklive.app@<version>+<build>`, and distribution from the native build number. Do not replace the release with the Expo version alone. EAS remote versioning and `autoIncrement` supply each production build's version code or build number.

Mobile disables default PII and sanitizes error events, breadcrumbs and logs before sending them. The sanitizer removes credentials, private request data and personal or financial fields while retaining opaque user IDs and diagnostic stack data. The upload token exists only in the build environment.

### Over-the-air updates

The OTA workflow loads EAS variables with `env:exec`, then sets the event label from the channel before exporting the bundle. This keeps QA labeled `qa` even though it shares production credentials. Profile `env` values in `eas.json` do not apply to OTA updates. The workflow publishes that exact export with `--skip-bundler --environment production` for both supported channels. Keep the DSN readable by the EAS CLI, using plaintext or sensitive visibility.

After publishing the update, the workflow uploads the exported `dist` source maps with `sentry-expo-upload-sourcemaps`. Store `SENTRY_AUTH_TOKEN` separately as a GitHub Actions secret. An EAS variable with Secret visibility is available to remote build workers, not the GitHub-hosted upload command. Until that secret is provisioned, the upload step warns and skips. A configured upload failure fails the workflow.

### Production acceptance

1. Dispatch the mobile build workflow with the EAS `production` profile using its production environment. Confirm the native build finishes with successful Sentry source-map and dSYM upload output.
2. Install that exact artifact on a physical device through TestFlight or the Android internal track. Record the EAS build ID, native version and build number.
3. Capture a controlled exception from a temporary validation build or an explicitly authorized test path. Confirm Sentry receives it in `production` with the expected native release and distribution.
4. Inspect the event in Sentry. Its application frames must show original TypeScript source, file names and line numbers. Confirm the error, breadcrumb and log payloads contain no seeded credentials, email addresses or financial values.
5. Confirm `[TokenCache]` warnings arrive in Sentry logs. Sign in as a crew account, go offline, and open an offer. Check the event and logs contain no email, phone, name or note text.
6. Publish an OTA update to the same channel, confirm its source-map upload succeeds, and repeat the exception, environment, native release, symbolication, TokenCache and offline-offer privacy checks.
7. Remove any temporary validation code before the release. Simulator, Expo Go and development-client results do not satisfy this acceptance check.

See the [Sentry Expo setup](https://docs.sentry.io/platforms/react-native/manual-setup/expo/) and [SDK options](https://docs.sentry.io/platforms/react-native/configuration/options/) for the native integration contract. Documentation placement follows [docs governance](https://docs.soundchecklive.io/engineering/development/docs-governance.md).

## Architecture

The server configuration below uses its existing Sentry project. Server errors are differentiated by the `SENTRY_ENVIRONMENT` tag. Mobile uses the separate `react-native` project described above.

| Environment | Tag Value |
| - | - |
| Dev | `development` |
| QA | `qa` |
| Prod | `production` |

### Why single project?

| Benefit | Description |
| - | - |
| **Simpler setup** | One DSN to manage |
| **Issue tracking** | Same error shares issue ID |
| **Cost efficient** | Single project quota |
| **Easy filtering** | Sentry's environment dropdown |

***

## Configuration

### Environment variables

| Variable | Description | Storage |
| - | - | - |
| `SENTRY_DSN` | Project DSN | Key Vault |
| `SENTRY_ENVIRONMENT` | Environment name | App settings |
| `SENTRY_TRACES_SAMPLE_RATE` | Performance sampling rate | App settings |

### Sampling rates

| Environment | Sample Rate | Reason |
| - | - | - |
| Development | 1.0 (100%) | Full visibility for debugging |
| QA | 1.0 (100%) | Full visibility for testing |
| Production | 1.0 (100%) | Full visibility (low traffic) |

> [!NOTE]
>
> When traffic increases, consider reducing production to 0.1 (10%) for cost savings.

***

## Setup

### Step 1: get your Sentry DSN

**1. Sign in to Sentry**

Go to [sentry.io](https://sentry.io)

**2. Create or select project**

Choose "Go" as the platform

**3. Get DSN**

Navigate to **Settings → Projects → Client Keys (DSN)**

Format: `https://key@o123456.ingest.sentry.io/project-id`

### Step 2: add DSN to GitHub Secrets

**1. Open repository settings**

**Settings → Secrets and variables → Actions**

**2. Create secret**

* Name: `SENTRY_DSN`
* Value: Your DSN from Step 1

> [!NOTE]
>
> The same DSN is used across all environments. Errors are differentiated by `SENTRY_ENVIRONMENT`.

### Step 3: deploy via Terraform

When CI/CD runs:

1. Workflow passes `TF_VAR_sentry_dsn` from GitHub Secret
2. Terraform creates `sentry-dsn` secret in Key Vault
3. App Service receives environment variables

***

## Verification

### Test endpoint (dev only)

```bash theme={null}
curl https://dev01-cus-api-app.azurewebsites.net/debug/sentry-test
```

### Check logs

```bash theme={null}
az webapp log tail \
  --resource-group "dev01-cus-backend-rg" \
  --name "dev01-cus-api-app" \
  --filter "Sentry"
```

***

## Dashboard usage

### Filtering by environment

Use the environment dropdown in Sentry to filter:

* Select "production" for prod-only errors
* Select "development" for dev-only issues

### Setting up alerts

**1. Create Alert Rule**

Go to **Alerts → Create Alert Rule**

**2. Set conditions**

Example: "When an issue is first seen"

**3. Add environment filter**

Add filter: `environment:production`

**4. Configure notifications**

Set up email, Slack, etc.

### Recommended alert rules

| Rule | Purpose |
| - | - |
| First Error Alert | New error type appears |
| Spike Detection | Unusual error volume |
| Critical Path Monitoring | Errors in payment/auth flows |

***

## Troubleshooting

> [accordion] Sentry Not Receiving Events
>
> 1. Verify DSN is set in App Service Configuration
> 2. Check logs for "Sentry initialized" message
> 3. Ensure network allows outbound to `*.ingest.sentry.io`

> [accordion] Events Not Tagged with Environment
>
> 1. Verify `SENTRY_ENVIRONMENT` is set in app\_settings
> 2. Check API is reading the config correctly

> [accordion] Secret Already Exists Error
>
> Soft-delete the secret and re-run pipeline:
>
> ```bash theme={null}
> az keyvault secret delete \
>   --vault-name "dev01-cus-core-kv" \
>   --name "sentry-dsn"
> ```
>
> Vault names by environment:
>
> * Dev: `dev01-cus-core-kv`
> * QA: `qa01-cus-core-kv`
> * Prod: `prod-cus-core-kv`

> [accordion] High Volume/Cost Concerns
>
> Reduce `SENTRY_TRACES_SAMPLE_RATE` in production. For errors (not traces), Sentry uses smart sampling automatically.

***

## Terraform files

| File | Change |
| - | - |
| `modules/security/variable.tf` | Added `sentry_dsn` variable |
| `modules/security/main.tf` | Added Key Vault secret resource |
| `modules/security/outputs.tf` | Added secret URI output |
| `environments/*/variables.tf` | Added `sentry_dsn` variable |
| `environments/*/main.tf` | Added security module param + app\_settings |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.