Objective
- Replace the current Sentry-based observability setup with PostHog as the primary tool for error tracking and session replay, with parity to today’s Sentry behavior.
- Stand up the PostHog account and project configuration so engineering can rely on one platform before broader product analytics work (e.g. report-page funnels).
- Deliver a first phase that is a one-for-one swap of Sentry — not a full redesign of how the team observes the product.
Background
- Attik uses Sentry across web, API, and mobile today; there is no PostHog in any repo yet.
- The team wants PostHog introduced as the replacement path for errors and replay, then expanded later for funnels and event analytics.
- Current Sentry capabilities to match or consciously defer:
- Exception capture (global handlers, route errors,
captureExceptionhelpers) - Session replay on the Next.js client (sampled session + on-error replay)
- Distributed tracing via
sentry-trace/baggagebetween frontend and backend - Structured logs (
Sentry.logger/sentryLogger/frontendLogger) tied to traces - User and company context on scope (staff tools, portal pay flows, mobile inspector session)
- Release and source map linkage for readable stack traces in production
- This work is distinct from report-page product analytics: that is separate instrumentation once PostHog is a baseline capability.
Scope
Frontend (attik-frontend)
- Sentry is wired through
@sentry/nextjs: client init insrc/instrumentation-client.ts(replay + browser tracing, Doppler-driven sample rates), server insentry.server.config.ts, edge insentry.edge.config.ts, andwithSentryConfiginnext.config.jsfor build-time source map upload. - Shared filtering and env:
src/util/sentry/sharedConfig.ts(sentryBeforeSend,sentryEnvironment,sentryRelease), trace sampling insrc/util/sentry/tracesSamplerConfig.ts. - Identity/context:
src/components/sentry/SentryAttikScope.tsx(staff session — user,company_id,attik_user_id,surface); portal pay sets tags insrc/app/client/job/[slug]/pay-beta/PaymentBetaClient.tsx. - Trace propagation to backend:
src/util/functions/sentry/applySentryTraceHeaders.tsused fromcallApiServerRoute.ts,useMultiServer.ts, and some API routes (e.g.src/app/api/data-exports/ai-generate-stream/route.ts). - Structured logging wrappers:
src/util/functions/sentry/sentryLoggerCore.ts,frontendLogger.ts, domain helpers (authLog.ts,paymentLog.ts,schedulingLog.ts,fetchLog.ts,observability.ts). - Global error surface:
src/app/global-error.tsx; tools shell mounts scope viasrc/app/tools/provider.tsx. - Decision needed: PostHog SDK placement (Next.js app router patterns), env vars (replacing
NEXT_PUBLIC_SENTRY_DSN, replay rate vars, etc.), and whether to keep parallel Sentry during cutover or remove in one pass. - Decision needed: Source maps / release tracking equivalent to current Sentry + Vercel build upload (
docs/SENTRY_SOURCEMAPS_SETUP.md, disabled workflows under.github/workflows/sentry-sourcemaps-*.yml.disabled).
Backend (attik-backend)
- Early init in
src/instrumentation.ts: Express, HTTP, Mongo, Vercel AI, profiling (@sentry/profiling-node), parent-based trace sampling,beforeSendfromsrc/util/functions/sentry/sharedConfig.ts. - Request middleware in
src/app.tsreadssentry-trace, tags spans, exposes trace ids onres.locals; CORS allowssentry-traceandbaggage. - Auth scope:
src/util/functions/sentry/requestScope.ts(applyAuthenticatedSentryScope, portalclient-tokenidentity, scheduler contact header); used fromsrc/routes/login.tswithsentryExpressTransactionNamingMiddleware. - Error path:
src/util/functions/errorHandling/requestError.tscaptures exceptions with scope; helpers insrc/util/functions/sentry/errorCapture.ts,sentryLogger.ts, domain logs (paymentRouteLog.ts,aiSentryWrapper.ts, etc.). - CI release upload:
.github/workflows/sentry-release-deploy.yml,.github/actions/sentry-upload/action.yml. - Decision needed: PostHog server-side error capture vs keeping trace header contract with the frontend during transition.
- Decision needed: Fate of structured
sentryLoggercall sites across routes and workers (migrate to PostHog logging/events vs thin adapter).
Mobile (attik-mobile)
- Init in
lib/sentry.ts(@sentry/react-native, routing integration,Sentry.wraponapp/_layout.tsx); user/tags incontexts/AuthContext.tsx; trace headers onlib/api.tsandlib/apiClient.ts; Expo plugin inapp.config.js, Metro viametro.config.js. - Decision needed: Whether mobile is in scope for phase 1 or a follow-up after web + API parity.
Config / ops
- PostHog project setup, environments (dev/staging/prod), sampling for replay, and alert/routing — decision needed who owns dashboards and on-call handoff from Sentry.
- Remove or repoint Sentry DSNs, GitHub Actions, and Doppler secrets once cutover is validated — decision needed rollback plan if parity gaps appear.
Out of scope for this ticket (unless explicitly expanded)
- Report-page funnel events and tutorial/repair-list instrumentation (separate product-analytics work once PostHog is live).
- Re-architecting all domain log schemas — only what’s needed for Sentry parity in phase 1.
References
- PostHog docs
- PostHog error tracking
- PostHog session replay
- Frontend Sentry entry:
attik-frontend/src/instrumentation-client.ts,attik-frontend/src/components/sentry/SentryAttikScope.tsx - Backend Sentry entry:
attik-backend/src/instrumentation.ts,attik-backend/src/util/functions/sentry/requestScope.ts - Mobile Sentry entry:
attik-mobile/lib/sentry.ts