From 49be5c9448bed25f707a88c3e0c9b0d2c8f256d3 Mon Sep 17 00:00:00 2001 From: "you@christopherdominic" Date: Sun, 29 Mar 2026 02:18:40 +0100 Subject: [PATCH] feat: integrate Sentry for error tracking - Install @sentry/nestjs in backend and @sentry/nextjs in frontend - Configure Sentry initialization with DSN from environment - Add instrument.ts for backend error capture - Configure Sentry client, server, and edge configs for frontend - Capture unhandled exceptions and promise rejections - Add release tracking tied to git commit SHA - Filter sensitive data (cookies, auth headers) before sending - Add SENTRY_DSN and GIT_COMMIT_SHA to .env.example files - Update CI workflow to inject commit SHA during builds Closes #107 --- .env.example | 6 ++++ .github/workflows/ci.yml | 4 +++ apps/backend/.env.example | 52 ++++++++++++++++++++++++++- apps/backend/package.json | 1 + apps/backend/src/instrument.ts | 24 +++++++++++++ apps/backend/src/main.ts | 1 + apps/frontend/.env.example | 4 +++ apps/frontend/next.config.js | 2 ++ apps/frontend/package.json | 1 + apps/frontend/sentry.client.config.ts | 23 ++++++++++++ apps/frontend/sentry.edge.config.ts | 8 +++++ apps/frontend/sentry.server.config.ts | 18 ++++++++++ 12 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 apps/backend/src/instrument.ts create mode 100644 apps/frontend/.env.example create mode 100644 apps/frontend/sentry.client.config.ts create mode 100644 apps/frontend/sentry.edge.config.ts create mode 100644 apps/frontend/sentry.server.config.ts diff --git a/.env.example b/.env.example index b04b06d..6b96d32 100644 --- a/.env.example +++ b/.env.example @@ -50,6 +50,12 @@ FRONTEND_URL=http://localhost:3001 THROTTLE_TTL=60000 THROTTLE_LIMIT=60 +# Sentry +SENTRY_DSN=your_sentry_dsn_here +GIT_COMMIT_SHA= + # Frontend NEXT_PUBLIC_API_URL=http://localhost:3000 NEXT_PUBLIC_STELLAR_NETWORK=testnet +NEXT_PUBLIC_SENTRY_DSN=your_sentry_dsn_here +NEXT_PUBLIC_GIT_COMMIT_SHA= diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1e47afd..6048409 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,8 @@ jobs: - name: Build backend run: npm run build --workspace=apps/backend + env: + GIT_COMMIT_SHA: ${{ github.sha }} - name: Run unit tests with coverage run: npx jest --coverage --passWithNoTests @@ -125,6 +127,8 @@ jobs: - name: Build frontend run: npm run build --workspace=apps/frontend + env: + NEXT_PUBLIC_GIT_COMMIT_SHA: ${{ github.sha }} chromatic-visual-tests: name: Frontend - Visual Regression Tests (Chromatic) diff --git a/apps/backend/.env.example b/apps/backend/.env.example index 765cfdb..c4f7bd7 100644 --- a/apps/backend/.env.example +++ b/apps/backend/.env.example @@ -1 +1,51 @@ -ALLOWED_ORIGINS=http://localhost:3001,http://localhost:3000,https://yourdomain.com +# Server +PORT=3000 + +# Logging +LOG_LEVEL=info + +# Database +DATABASE_HOST=localhost +DATABASE_PORT=5432 +DATABASE_USER=your_db_user +DATABASE_PASSWORD=your_db_password +DATABASE_NAME=brain-storm + +# Auth +JWT_SECRET=your_jwt_secret + +# Google OAuth +GOOGLE_CLIENT_ID=your_google_client_id +GOOGLE_CLIENT_SECRET=your_google_client_secret +GOOGLE_CALLBACK_URL=http://localhost:3000/auth/google/callback + +# Stellar +STELLAR_NETWORK=testnet +STELLAR_SECRET_KEY=your_stellar_secret_key +STELLAR_HORIZON_URL=https://horizon-testnet.stellar.org + +# Soroban +SOROBAN_RPC_URL=https://soroban-testnet.stellar.org +ANALYTICS_CONTRACT_ID=your_analytics_contract_id +TOKEN_CONTRACT_ID=your_token_contract_id + +# Redis +REDIS_URL=redis://localhost:6379 + +# Throttler +THROTTLE_TTL=60000 +THROTTLE_LIMIT=100 + +# Email +EMAIL_ENABLED=false +EMAIL_HOST=smtp.example.com +EMAIL_PORT=587 +EMAIL_SECURE=false +EMAIL_USER=your_email_user +EMAIL_PASS=your_email_password +EMAIL_FROM="Brain Storm" +FRONTEND_URL=http://localhost:3001 + +# Sentry +SENTRY_DSN=your_sentry_dsn_here +GIT_COMMIT_SHA= diff --git a/apps/backend/package.json b/apps/backend/package.json index 686ec2e..b72ce97 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -27,6 +27,7 @@ "@nestjs/swagger": "^7.0.0", "@nestjs/throttler": "^6.0.0", "@nestjs/typeorm": "^10.0.0", + "@sentry/nestjs": "^8.0.0", "@stellar/stellar-sdk": "^12.0.0", "bcrypt": "^5.1.0", "cache-manager": "^7.2.8", diff --git a/apps/backend/src/instrument.ts b/apps/backend/src/instrument.ts new file mode 100644 index 0000000..5b8a95d --- /dev/null +++ b/apps/backend/src/instrument.ts @@ -0,0 +1,24 @@ +import * as Sentry from '@sentry/nestjs'; +import { nodeProfilingIntegration } from '@sentry/profiling-node'; + +// Initialize Sentry before any other imports +Sentry.init({ + dsn: process.env.SENTRY_DSN, + environment: process.env.NODE_ENV || 'development', + release: process.env.GIT_COMMIT_SHA || 'unknown', + integrations: [ + nodeProfilingIntegration(), + ], + tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0, + profilesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0, + beforeSend(event, hint) { + // Filter out sensitive data + if (event.request) { + delete event.request.cookies; + if (event.request.headers) { + delete event.request.headers['authorization']; + } + } + return event; + }, +}); diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts index 3d29f3b..34f8529 100644 --- a/apps/backend/src/main.ts +++ b/apps/backend/src/main.ts @@ -1,3 +1,4 @@ +import './instrument'; import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; diff --git a/apps/frontend/.env.example b/apps/frontend/.env.example new file mode 100644 index 0000000..2b05172 --- /dev/null +++ b/apps/frontend/.env.example @@ -0,0 +1,4 @@ +NEXT_PUBLIC_API_URL=http://localhost:3000 +NEXT_PUBLIC_STELLAR_NETWORK=testnet +NEXT_PUBLIC_SENTRY_DSN=your_sentry_dsn_here +NEXT_PUBLIC_GIT_COMMIT_SHA= diff --git a/apps/frontend/next.config.js b/apps/frontend/next.config.js index 4ab08fa..59e578c 100644 --- a/apps/frontend/next.config.js +++ b/apps/frontend/next.config.js @@ -8,6 +8,8 @@ const nextConfig = { env: { NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, NEXT_PUBLIC_STELLAR_NETWORK: process.env.NEXT_PUBLIC_STELLAR_NETWORK, + NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN, + NEXT_PUBLIC_GIT_COMMIT_SHA: process.env.NEXT_PUBLIC_GIT_COMMIT_SHA, }, images: { remotePatterns: [ diff --git a/apps/frontend/package.json b/apps/frontend/package.json index 25d6b7a..ee3d7ce 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -25,6 +25,7 @@ "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", + "@sentry/nextjs": "^8.0.0", "@stellar/freighter-api": "^6.0.1", "@stellar/stellar-sdk": "^12.0.0", "axios": "^1.7.0", diff --git a/apps/frontend/sentry.client.config.ts b/apps/frontend/sentry.client.config.ts new file mode 100644 index 0000000..23fcb35 --- /dev/null +++ b/apps/frontend/sentry.client.config.ts @@ -0,0 +1,23 @@ +import * as Sentry from '@sentry/nextjs'; + +Sentry.init({ + dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + environment: process.env.NODE_ENV || 'development', + release: process.env.NEXT_PUBLIC_GIT_COMMIT_SHA || 'unknown', + tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0, + replaysSessionSampleRate: 0.1, + replaysOnErrorSampleRate: 1.0, + integrations: [ + Sentry.replayIntegration({ + maskAllText: true, + blockAllMedia: true, + }), + ], + beforeSend(event, hint) { + // Filter sensitive data + if (event.request) { + delete event.request.cookies; + } + return event; + }, +}); diff --git a/apps/frontend/sentry.edge.config.ts b/apps/frontend/sentry.edge.config.ts new file mode 100644 index 0000000..d54efe5 --- /dev/null +++ b/apps/frontend/sentry.edge.config.ts @@ -0,0 +1,8 @@ +import * as Sentry from '@sentry/nextjs'; + +Sentry.init({ + dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + environment: process.env.NODE_ENV || 'development', + release: process.env.NEXT_PUBLIC_GIT_COMMIT_SHA || 'unknown', + tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0, +}); diff --git a/apps/frontend/sentry.server.config.ts b/apps/frontend/sentry.server.config.ts new file mode 100644 index 0000000..de00de9 --- /dev/null +++ b/apps/frontend/sentry.server.config.ts @@ -0,0 +1,18 @@ +import * as Sentry from '@sentry/nextjs'; + +Sentry.init({ + dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, + environment: process.env.NODE_ENV || 'development', + release: process.env.NEXT_PUBLIC_GIT_COMMIT_SHA || 'unknown', + tracesSampleRate: process.env.NODE_ENV === 'production' ? 0.1 : 1.0, + beforeSend(event, hint) { + // Filter sensitive data + if (event.request) { + delete event.request.cookies; + if (event.request.headers) { + delete event.request.headers['authorization']; + } + } + return event; + }, +});