From d62af00a4ac9ae8447f714caea52357f61bb208d Mon Sep 17 00:00:00 2001 From: Ray <11846445+A77AY@users.noreply.github.com> Date: Tue, 28 Jul 2026 18:33:53 +0800 Subject: [PATCH 1/3] feat: configure Sentry with runtime environment and authenticated user context --- .github/workflows/main.yaml | 1 - package.json | 2 +- src/app/initializer.ts | 32 +++++++++++++++++++++----------- src/main.ts | 3 +++ 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index d29c32880..3095c9c74 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -23,7 +23,6 @@ jobs: SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }} with: sourcemaps: ./dist/browser - environment: ${{ startsWith(github.ref_name, 'epic/') && 'staging' || 'production' }} set_commits: skip - name: Remove source maps run: find dist/browser -type f -name '*.map' -delete diff --git a/package.json b/package.json index 18d39a9a7..0be338580 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.0.0", "private": true, "scripts": { - "start": "ng serve --proxy-config proxy.conf.js --port 8000", + "start": ". ./.env && ng serve --proxy-config proxy.conf.js --port 8000 --define \"SENTRY_DSN='${SENTRY_DSN}'\"", "stage": "cross-env NODE_ENV=stage ng serve --proxy-config proxy.conf.js --port 8001 --configuration=stage", "fix": "npm run i18n:extract && npm run spell:fix && npm run lint:fix && npm run format:fix", "build": "ng build", diff --git a/src/app/initializer.ts b/src/app/initializer.ts index 47290e7ea..b9b842d43 100644 --- a/src/app/initializer.ts +++ b/src/app/initializer.ts @@ -1,3 +1,5 @@ +import * as Sentry from '@sentry/angular'; + import { environment } from '../environments'; import { KeycloakService } from './auth/keycloak'; @@ -19,17 +21,25 @@ export const initializer = configService.init({ configUrl: environment.appConfigPath }).then(() => Promise.all([ themeManager.init(), - keycloakService.init({ - config: environment.authConfigPath, - initOptions: { - onLoad: 'login-required', - checkLoginIframe: true, - }, - loadUserProfileAtStartUp: true, - enableBearerInterceptor: true, - bearerExcludedUrls: ['/assets'], - bearerPrefix: 'Bearer', - }), + keycloakService + .init({ + config: environment.authConfigPath, + initOptions: { + onLoad: 'login-required', + checkLoginIframe: true, + }, + loadUserProfileAtStartUp: true, + enableBearerInterceptor: true, + bearerExcludedUrls: ['/assets'], + bearerPrefix: 'Bearer', + }) + .then(async () => { + if (SENTRY_DSN) { + const { id, username, email } = + await keycloakService.loadUserProfile(); + Sentry.setUser({ id, username, email }); + } + }), ]), ), languageService.init(), diff --git a/src/main.ts b/src/main.ts index 5a67c1a0a..d1e11ff49 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,9 +7,12 @@ import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); +} +if (SENTRY_DSN) { Sentry.init({ dsn: SENTRY_DSN, + environment: environment.production ? 'production' : 'development', integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()], tracesSampleRate: 1, replaysSessionSampleRate: 1, From f8bcec9a33d0731f7d97ac76d53b4973a203f6d8 Mon Sep 17 00:00:00 2001 From: Ray <11846445+A77AY@users.noreply.github.com> Date: Tue, 28 Jul 2026 18:49:25 +0800 Subject: [PATCH 2/3] feat: integrate Sentry ErrorHandler into app providers --- src/app/app.module.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ce251c487..eb3ba2ba4 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -2,7 +2,14 @@ import { FlexLayoutModule } from 'ng-flex-layout'; import { CommonModule } from '@angular/common'; import { provideHttpClient, withInterceptorsFromDi, withXhr } from '@angular/common/http'; -import { LOCALE_ID, NgModule, inject, isDevMode, provideAppInitializer } from '@angular/core'; +import { + ErrorHandler, + LOCALE_ID, + NgModule, + inject, + isDevMode, + provideAppInitializer, +} from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { DateAdapter, @@ -27,6 +34,7 @@ import { ErrorModule } from '@dsh/app/shared/services'; import { createDateRangeWithPresetSerializer } from '@dsh/components/date-range-filter'; import { BootstrapIconModule, SpinnerModule } from '@dsh/components/indicators'; import { TRANSLOCO_SCOPE, TranslocoModule, provideTransloco } from '@jsverse/transloco'; +import * as Sentry from '@sentry/angular'; import { QUERY_PARAMS_SERIALIZERS } from '@vality/matez'; @@ -73,6 +81,10 @@ import { TranslocoHttpLoaderService } from './transloco-http-loader.service'; ], providers: [ LanguageService, + { + provide: ErrorHandler, + useValue: Sentry.createErrorHandler(), + }, provideAppInitializer(() => { const initializerFn = initializer( inject(ConfigService), From 647ee58baf4f272e476eadeaf40b057af3b20d8b Mon Sep 17 00:00:00 2001 From: Ray <11846445+A77AY@users.noreply.github.com> Date: Tue, 28 Jul 2026 19:08:44 +0800 Subject: [PATCH 3/3] feat: enable privacy masking and media blocking for Sentry session replays --- src/main.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index d1e11ff49..e715c1e4c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -13,7 +13,14 @@ if (SENTRY_DSN) { Sentry.init({ dsn: SENTRY_DSN, environment: environment.production ? 'production' : 'development', - integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()], + integrations: [ + Sentry.browserTracingIntegration(), + Sentry.replayIntegration({ + maskAllText: true, + maskAllInputs: true, + blockAllMedia: true, + }), + ], tracesSampleRate: 1, replaysSessionSampleRate: 1, replaysOnErrorSampleRate: 1,