Skip to content

feat(pos-app): add Sentry observability - #613

Open
ignaciosantise wants to merge 3 commits into
mainfrom
feat/mobile-analytics-crashes
Open

feat(pos-app): add Sentry observability#613
ignaciosantise wants to merge 3 commits into
mainfrom
feat/mobile-analytics-crashes

Conversation

@ignaciosantise

Copy link
Copy Markdown
Collaborator

Summary

  • add Sentry v8 initialization with internal/development/production environments
  • enable masked replay and first-party performance tracing
  • add payment, printer, NFC, and screen-display spans
  • configure Expo source-map upload support

Verification

  • npx prettier --check utils/sentry.ts app/_layout.tsx app.json
  • npx eslint utils/sentry.ts app/_layout.tsx
  • npm test -- --runInBand __tests__/utils/build-variant.test.ts

@vercel

vercel Bot commented Sep 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pos-demo Ready Ready Preview Sep 3, 2026 3:43pm UTC
2 Skipped Deployments
Project Deployment Actions Updated
react-native-appkit Ignored Ignored Preview Sep 3, 2026 3:43pm UTC
react-native-walletkit Ignored Ignored Preview Sep 3, 2026 3:43pm UTC

Request Review

@ignaciosantise

Copy link
Copy Markdown
Collaborator Author

@claude review

@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown

Claude finished @ignaciosantise's task in 2m 56s —— View job


Code Review

  • Gather context
  • Read changed files
  • Subagents (license ✅, breaking changes ✅, data classification ✅)
  • Compile findings
Found 7 issue(s)

Issue 1: Sentry Expo plugin removed — EAS builds will produce unsymbolicated crash reports

ID: brk-appjson-sentry-plugin-removed-a3c2
File: dapps/pos-app/app.json:137
Severity: HIGH
Category: breaking_change

Context:

  • Pattern: "@sentry/react-native" was removed from the plugins array. This plugin handles build-time tasks: injecting release/dist metadata, configuring the Metro serializer to emit source-map artifacts, and wiring up EAS Build hooks for sentry-cli uploads. These are not handled by Sentry.init() at runtime.
  • Risk: All EAS production and internal builds will produce unsymbolicated Sentry crash reports — JavaScript frames will show minified identifiers, native stacks won't resolve to source locations.
  • Impact: The entire observability investment in this PR is undermined for shipped builds. Metro dev builds are unaffected.
  • Trigger: First EAS build after merge.

Recommendation: Restore the plugin:

"plugins": [
  "@sentry/react-native",
  "expo-image",
  "expo-status-bar"
]

Verify the correct entry for v8 with npx @sentry/react-native@8 info or the v7→v8 migration guide.

Fix this →


Issue 2: Navigation container not registered — screen-level performance metrics lost

ID: sentry-nav-integration-missing-a3f1 (also: brk-sentryts-nav-container-unregistered-f17e)
File: dapps/pos-app/utils/sentry.ts:22-35
Severity: HIGH
Category: breaking_change

Context:

  • Pattern: The old _layout.tsx used Sentry.reactNavigationIntegration() + navigationIntegration.registerNavigationContainer(navigationRef). The new initSentry() uses reactNativeTracingIntegration only — no nav integration and no container registration anywhere.
  • Risk: reactNativeTracingIntegration still requires the navigation container to be registered for per-screen transactions. Sentry.TimeToFullDisplay (added in activity.tsx:225 and scan.tsx:320) has no parent transaction to attach to — making those additions no-ops.
  • Impact: All screen-level performance data (TTID, TTFD, Mobile Vitals) is silently absent. The PR's "screen-display spans" are not fulfilled.
  • Trigger: Every app run after merge.

Recommendation:

// sentry.ts — add and export the nav integration
export const navigationIntegration = Sentry.reactNavigationIntegration({
  enableTimeToInitialDisplay: true,
});
// include in integrations array alongside reactNativeTracingIntegration
// _layout.tsx — restore registration
import { useNavigationContainerRef } from "expo-router";
import { initSentry, navigationIntegration } from "@/utils/sentry";
// in useEffect after hydration + fonts:
navigationIntegration.registerNavigationContainer(navigationRef);

Fix this →


Issue 3: Session replay enabled without explicit financial data masking

ID: dcl-sentry-replay-unmask-financial-a4f2
File: dapps/pos-app/utils/sentry.ts:35-36
Severity: MEDIUM
Category: data_classification

Context:

  • Pattern: replaysOnErrorSampleRate: 1.0 and replaysSessionSampleRate: 0.1 enable replay in production, but no mobileReplayIntegration({ maskAllText: true, blockAllMedia: true }) is configured anywhere. The scan screen displays payment amounts and QR codes; the activity screen renders a full transaction list.
  • Risk: Payment amounts (Confidential) and transaction IDs (Internal) can be captured in Sentry replay recordings. The beforeSend hook only strips event.request from error events — it has no effect on the replay pipeline, which is a separate code path.
  • Impact: Compliance gap for financial data sent to Sentry's servers on 10% of production sessions and 100% of error sessions.
  • Trigger: Any production session on the scan or activity screen with an active error.

Recommendation:

import { mobileReplayIntegration } from "@sentry/react-native";

integrations: [
  mobileReplayIntegration({ maskAllText: true, blockAllMedia: true }),
  Sentry.reactNativeTracingIntegration({ ... }),
  // ...
],

Without mobileReplayIntegration being explicitly instantiated, the sample rate settings may be inert in the current SDK version — but protection is also not guaranteed.

Fix this →


Issue 4: beforeBreadcrumb drops all non-navigation breadcrumbs

ID: sentry-breadcrumb-filter-b72c
File: dapps/pos-app/utils/sentry.ts:51-53
Severity: MEDIUM
Category: code_quality

Context:

  • Pattern: beforeBreadcrumb: (b) => b?.category === "navigation" ? b : null discards HTTP requests, console events, and UI interaction breadcrumbs.
  • Risk: Sentry Issues will have almost no breadcrumb trail. Multi-step payment flows (API call → NFC → printer) will be impossible to reconstruct from error context on low-end POS hardware.

Recommendation:

beforeBreadcrumb: (breadcrumb) => {
  const { category } = breadcrumb;
  if (category === "navigation") return breadcrumb;
  if (category === "fetch" || category === "xhr") return breadcrumb;
  if (category === "console" && breadcrumb.level === "error") return breadcrumb;
  return null;
},

Issue 5: Printer connection errors swallowed — not captured as Sentry Issues

ID: printer-connect-error-capture-d4e8
File: dapps/pos-app/utils/printer.ts:26-80
Severity: MEDIUM
Category: code_quality

Context:

  • Pattern: connectPrinter catches all exceptions inside the startSpan callback and returns { connected: false, error } without re-throwing. The span callback always resolves, so startSpan never auto-captures these errors as Issues.
  • Risk: Printer failures are invisible in the Sentry Issues tab. The operator may not know the printer is broken until receipts stop printing.

Recommendation: Add Sentry.captureException(error) before the soft return in the catch block.


Issue 6: No beforeSendTransaction — payment IDs in URL paths flow unfiltered into performance data

ID: dcl-sentry-missing-tx-filter-c1b8
File: dapps/pos-app/utils/sentry.ts:48-55
Severity: LOW
Category: data_classification

Context:

  • Pattern: beforeSend strips event.request from error events, but there is no beforeSendTransaction. Sentry's performance pipeline is a separate code path. The cancelPayment span hits /payments/${paymentId}/cancel, embedding the payment ID in the URL of a traced HTTP child span.
  • Risk: Payment IDs flow into Sentry performance data without scrubbing, creating an Internal-tier data handling gap and a future risk if amount data is added to spans.

Recommendation:

beforeSendTransaction: (transaction) => {
  delete transaction.request;
  return transaction;
},

Issue 7: /^\/api\// regex dead entry in tracePropagationTargets

ID: sentry-trace-targets-regex-f19a
File: dapps/pos-app/utils/sentry.ts:17
Severity: LOW
Category: code_quality

Context: React Native fetch always uses absolute URLs; this relative-path regex never matches. Remove it to avoid misleading future maintainers.

License compliance:@sentry/react-native v8 is MIT — no issue.

@ignaciosantise

Copy link
Copy Markdown
Collaborator Author

Follow-up on the seven findings:

  1. Sentry Expo plugin: Declined. @sentry/react-native/expo remains configured in app.json, and metro.config.js uses getSentryExpoConfig. The removed bare @sentry/react-native plugin entry was redundant.

  2. Expo Router navigation: Declined. With tracing enabled, Sentry v8 installs its default Expo Router integration, which discovers and registers Expo Router’s navigation container. The manual registration was deliberately removed.

  3. Replay masking: Declined. In this SDK version, replay sample rates automatically enable mobile replay; its defaults mask all text, images, and vectors. blockAllMedia is not the mobile React Native replay option.

  4. Breadcrumb filtering: Declined by design. We intentionally keep navigation context only and do not use Sentry as a second logging pipeline.

  5. Printer connection errors: Declined by design. Handled errors do not create Sentry Issues; printer/network diagnosis remains in the backend and local app logs.

  6. Payment IDs in spans: Addressed in 930524f. HTTP span descriptions now normalize ID-like path segments to :id.

  7. Relative /api/* target: Declined. This app also runs on web, where the Vercel proxy uses relative /api/* requests; the regex is therefore intentional.

@ignaciosantise
ignaciosantise force-pushed the feat/mobile-analytics-crashes branch from 930524f to 5b64fe9 Compare September 2, 2026 19:35
@ignaciosantise
ignaciosantise marked this pull request as ready for review September 2, 2026 19:35
Copilot AI lite review requested due to automatic review settings September 2, 2026 19:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Replay is enabled for production/error cases but masked replay isn’t explicitly configured, which can risk capturing sensitive POS UI data.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds Sentry v8 observability to the dapps/pos-app sample, centralizing initialization and instrumenting key POS flows (payment, printer, NFC, and screen display) while updating Expo/Sentry build-time integration for sourcemaps.

Changes:

  • Introduces centralized Sentry initialization with build-variant-based environments and span sanitization hooks.
  • Adds custom spans around printer/payment/NFC operations and screen TTFD markers.
  • Upgrades @sentry/react-native to 8.23.0 and updates the lockfile; adjusts Expo plugin configuration accordingly.
File summaries
File Description
dapps/pos-app/utils/sentry.ts New centralized Sentry init (env tagging, tracing targets, span/request scrubbing).
dapps/pos-app/utils/printer.ts Wraps printer connect/print flows in Sentry spans.
dapps/pos-app/utils/build-variant.ts Adds build variant detection (development/internal/production).
dapps/pos-app/services/payment.ts Adds Sentry spans for payment create/cancel requests.
dapps/pos-app/package.json Bumps @sentry/react-native to v8.23.0.
dapps/pos-app/package-lock.json Lockfile updates for Sentry v8 dependency graph.
dapps/pos-app/jest.setup.js Mocks expo-application.applicationId and adds @sentry/react-native mocks for tests.
dapps/pos-app/hooks/use-nfc-payment.ts Adds an NFC activation span; normalizes caught errors.
dapps/pos-app/app/scan.tsx Adds TimeToFullDisplay marker for scan screen readiness.
dapps/pos-app/app/activity.tsx Adds TimeToFullDisplay marker for activity screen readiness.
dapps/pos-app/app/_layout.tsx Moves Sentry init into initSentry() and reports Sentry.appLoaded() after hydration/fonts.
dapps/pos-app/app.json Removes the old Sentry plugin entry (keeps @sentry/react-native/expo).
dapps/pos-app/tests/utils/build-variant.test.ts Adds unit tests for build variant detection logic.
Review details

Files not reviewed (1)

  • dapps/pos-app/package-lock.json: Generated file
  • Files reviewed: 12/13 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread dapps/pos-app/utils/sentry.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants