Learn Build a Real SaaS with Claude Code Monitoring and Error Tracking

Monitoring and Error Tracking

Intermediate 🕐 17 min Lesson 21 of 25
What you'll learn
  • Explain why this lesson describes a gap in the reference app rather than something already verified working
  • Sign up for a free Sentry account and create a Next.js project to obtain a DSN
  • Run the official Sentry setup wizard for Next.js and identify the config files it generates
  • Explain what a DSN is and why it is project-specific even though it is safe to expose client-side
  • Identify the two real integration points in this codebase (error.tsx and the Stripe webhook route) where Sentry would be wired in next
  • Explain what monitoring catches that a passing test suite cannot

A Gap Worth Naming Honestly

This is the one lesson in this section describing something not yet built into the reference app. The reputation dashboard has no Sentry, no error-tracking service, no monitoring of any kind wired in -- app/dashboard/error.tsx from Lesson 15 logs to console.error and stops there. That is fine for local development, where you are watching the terminal. It stops being fine the moment this app is deployed and you are not watching anything -- a failed webhook, a thrown error in a server component, a Resend API call that silently 401s, all of those happen with nobody's eyes on a console. This lesson covers exactly what you would add next, described accurately from Sentry's own current Next.js SDK documentation, not as something already running in this codebase.

What You Need: A Free Sentry Account

Sign up at sentry.io/signup -- Sentry has a free tier intended for exactly this kind of project, and a credit card is not required to start. After signup, create a project inside Sentry and choose Next.js as the platform; Sentry generates a DSN (Data Source Name) for that project, a URL in the shape https://<key>@o<org-id>.ingest.sentry.io/<project-id>. The DSN is what tells the SDK in your app which Sentry project to send events to -- without it, the SDK has nowhere to report errors. It is not a secret in the way a Stripe key is (it can safely appear in client-side bundles), but it is still project-specific and should come from your own Sentry project, not be copied from someone else's.

Installing the SDK

Sentry's official setup path for Next.js is a wizard, not a manual npm install followed by hand-written config:

npx @sentry/wizard@latest -i nextjs

The wizard logs you into your Sentry account, asks which project to connect, and then generates the SDK's configuration files for you. For a Next.js App Router project, this means an instrumentation-client.ts file for the browser environment, a sentry.server.config.ts for the Node.js server environment, a sentry.edge.config.ts for edge runtime routes, and an instrumentation.ts file that registers the server and edge configs with Next.js's instrumentation hook. It also wraps next.config.ts with withSentryConfig, which enables automatic source map upload so a production stack trace shows your real file names and line numbers instead of minified bundle output.

What Gets Captured Automatically

Once installed, the SDK captures unhandled errors -- including React rendering errors -- automatically, along with performance traces (sampled, by default a higher rate in development than production to control event volume) and, optionally, session replay. For this app specifically, the SDK would catch exactly the class of failure error.tsx currently only logs locally: an unhandled exception thrown inside app/dashboard/page.tsx, a failed database query, or a thrown error inside any server component the dashboard route tree renders.

Where to Hook It Into Code That Already Exists

The most natural integration point in this codebase is the useEffect inside app/dashboard/error.tsx that currently only logs to the console:

useEffect(() => {
  console.error("Dashboard error:", error);
}, [error]);

The next step here -- not yet done in this repo -- would be importing Sentry's captureException and calling it alongside the existing console log, so the same error that a developer would have seen locally in their terminal also reaches the Sentry dashboard from a real deployed instance where nobody is tailing logs. The webhook route is the other natural candidate: app/api/billing/webhook/route.ts currently returns a 400 on a signature failure with no record beyond the HTTP response itself -- wrapping that catch block to also report to Sentry would mean a misconfigured STRIPE_WEBHOOK_SECRET in production surfaces as an alert, not as silent billing data going stale.

What Monitoring Adds That Tests Do Not

Lesson 17's test suite catches regressions before they ship -- it cannot catch a Stripe API outage, a Supabase connection pool exhausting under real traffic, or a Resend account hitting a sending limit, because none of those are bugs in this app's code. Monitoring is the complementary half: visibility into what is actually happening to a live, deployed instance of code that already passed every test. A green test suite answers "does this code behave correctly in the scenarios I thought to test." Monitoring answers "is this code behaving correctly right now, in production, under conditions nobody wrote a test for."

What to Verify Before Treating Sentry as Done

Installing the wizard and seeing a DSN in your config files is not the same as confirming it works. Before trusting it: deliberately throw a test error in a route only reachable in a non-production deployment, confirm it appears in the Sentry project dashboard within a minute or two, and confirm the stack trace shows real file names and line numbers rather than minified output -- that last check confirms source map upload actually worked, not just that an event arrived.

This closes out deployment and observability. The reference app is now live-deployable, environment-scoped correctly, and one wizard command away from real visibility into production failures. The next lesson turns back to the codebase itself for a focused security pass -- auditing every auth check in the app the way a security reviewer would, to confirm none of them are merely decorative.

Key takeaways
  • The reference app has no monitoring tool wired in -- error.tsx logs only to console.error locally, which nobody sees once the app is deployed
  • sentry.io/signup offers a free tier with no credit card required, sufficient for a project this size
  • npx @sentry/wizard@latest -i nextjs is Sentry's official install path for Next.js -- it logs into your account and generates the config files rather than requiring manual setup
  • A DSN (Data Source Name) tells the SDK which Sentry project to report events to -- it is project-specific but safe to include in client-side code, unlike a Stripe secret key
  • The natural next step in this codebase is adding Sentry's captureException inside error.tsx's existing useEffect and inside the Stripe webhook route's signature-failure branch
  • Tests catch regressions before shipping; monitoring catches real-world failures (a third-party outage, a connection pool exhausting) that no test could have been written for