Skip to content

[CI] (6fb03e7) react-router/saas-template#1486

Closed
wizard-ci-bot[bot] wants to merge 1 commit into
mainfrom
wizard-ci-6fb03e7-react-router-saas-template
Closed

[CI] (6fb03e7) react-router/saas-template#1486
wizard-ci-bot[bot] wants to merge 1 commit into
mainfrom
wizard-ci-6fb03e7-react-router-saas-template

Conversation

@wizard-ci-bot
Copy link
Copy Markdown

@wizard-ci-bot wizard-ci-bot Bot commented May 13, 2026

Automated wizard CI run

Source: scheduled
Trigger ID: 6fb03e7
App: react-router/saas-template
App directory: apps/react-router/saas-template
Workbench branch: wizard-ci-6fb03e7-react-router-saas-template
Wizard branch: main
Context Mill branch: main
PostHog (MCP) branch: master
Timestamp: 2026-05-13T17:45:48.601Z
Duration: 677.0s

@wizard-ci-bot
Copy link
Copy Markdown
Author

wizard-ci-bot Bot commented May 13, 2026

Now I have everything I need to evaluate the PR.


PR Evaluation Report

Summary

This PR integrates PostHog into a React Router v7 framework-mode SaaS template (pastebin app). It adds client-side initialization with PostHogProvider, a server-side middleware using posthog-node with context-based session correlation, user identification, error boundary exception capture, a Vite dev proxy, and 10 custom business events across authentication, onboarding, and billing flows.

Files changed Lines added Lines removed
18 +376 -80

Confidence score: 4/5 👍

  • Reverse proxy not actually used: The Vite proxy is configured at /ingest but api_host in entry.client.tsx points to import.meta.env.VITE_PUBLIC_POSTHOG_HOST (the raw PostHog host), not /ingest. Events bypass the proxy entirely. [CRITICAL]
  • PII in capture event properties: login_email_submitted, registration_email_submitted, and user_signed_up all include email in capture() event properties. Email is PII and should only be in identify() person properties, not in event properties. [CRITICAL]
  • User identified by email, not stable ID: posthog.identify() uses navUserProps.user.email as the distinct_id. Emails can change and are not stable unique identifiers — a database user ID should be used instead. [MEDIUM]
  • PostHog env vars not documented in .env.example: VITE_PUBLIC_POSTHOG_PROJECT_TOKEN and VITE_PUBLIC_POSTHOG_HOST are not added to the existing .env.example file. [MEDIUM]
  • Vite proxy is dev-only: The proxy in vite.config.ts server.proxy only works during vite dev. There is no production reverse proxy configuration (e.g., Vercel rewrites, server middleware). [MEDIUM]

File changes

Filename Score Description
app/entry.client.tsx 3/5 PostHog init with PostHogProvider, tracing headers, but api_host doesn't point to proxy
app/lib/posthog-middleware.server.ts 5/5 Clean server-side middleware with context, session/distinct ID extraction, shutdown
app/root.tsx 5/5 Middleware registered, ErrorBoundary captures exceptions via captureException
app/features/billing/billing-action.server.ts 5/5 Four well-instrumented billing events with enriched properties
app/features/billing/contact-sales/contact-sales-team.tsx 3/5 Captures contact sales event but includes work_email (PII) in event properties
app/routes/.../login.tsx 2/5 Captures login event with email as PII in event properties
app/routes/.../register.tsx 2/5 Captures registration event with email as PII in event properties
app/routes/.../auth.callback.ts 2/5 Server-side signup event with email as PII and as distinct_id
app/routes/.../_sidebar-layout.tsx 3/5 Identify call placed correctly in layout, but uses email as distinct_id
app/routes/.../onboarding+/organization.tsx 4/5 Clean onboarding event capture in submit handler
app/routes/.../onboarding+/user-account.tsx 4/5 Clean onboarding event capture in submit handler
vite.config.ts 3/5 Proxy configured but unused; dev-only; SSR noExternal correct
package.json 5/5 All three SDKs added correctly
posthog-setup-report.md 4/5 Thorough documentation of integration
Other files (dashboard, pastes, etc.) 4/5 Mostly reformatting, no functional issues

App sanity check ⚠️

Criteria Result Description
App builds and runs Yes No syntax errors; SSR noExternal configured for posthog-js and @posthog/react
Preserves existing env vars & configs Yes Existing middleware, routes, and configs preserved; PostHog middleware appended to chain
No syntax or type errors Yes All TypeScript/JSX is valid
Correct imports/exports Yes posthog-js on client, posthog-node on server (.server.ts files)
Minimal, focused changes No Significant reformatting across pastes.tsx, dashboard.tsx, and pastes..tsx (attribute reordering, whitespace)
Pre-existing issues None No pre-existing issues noted

Issues

  • Unnecessary reformatting: pastes.tsx, dashboard.tsx, and pastes..tsx contain extensive attribute reordering and whitespace changes unrelated to PostHog. [LOW]

Other completed criteria

  • Environment variables documented in .env added to .gitignore
  • Build configuration valid — SSR noExternal properly set for posthog packages
  • Package.json is valid with all three PostHog packages added

PostHog implementation ⚠️

Criteria Result Description
PostHog SDKs installed Yes posthog-js, @posthog/react, and posthog-node all added to package.json
PostHog client initialized Yes Client init in entry.client.tsx with PostHogProvider; server middleware creates posthog-node per request with withContext()
capture() Yes 10 meaningful events across client and server
identify() Yes Called in sidebar layout with user email/name, though uses email as distinct_id
Error tracking Yes captureException(error) in root ErrorBoundary
Reverse proxy No Vite proxy configured at /ingest but api_host not updated to use it — events go directly to PostHog host

Issues

  • Reverse proxy misconfigured: The vite.config.ts sets up proxy routes at /ingest, /ingest/array, and /ingest/static, but entry.client.tsx sets api_host to import.meta.env.VITE_PUBLIC_POSTHOG_HOST instead of "/ingest". The proxy is never used. Fix: set api_host: "/ingest" in posthog.init(). [CRITICAL]
  • Identify uses email as distinct_id: posthog.identify(navUserProps.user.email, ...) uses email as the distinct ID. Emails are mutable and not ideal identifiers. Use a stable database user ID instead. [MEDIUM]
  • No posthog.reset() on logout: There is no posthog.reset() call when users log out, which means subsequent users on the same device will be associated with the previous user. [MEDIUM]
  • defaults option present: Good — the defaults: "2026-01-30" option is correctly set. [LOW - positive note]

Other completed criteria

  • API key loaded from environment variable (import.meta.env.VITE_PUBLIC_POSTHOG_PROJECT_TOKEN)
  • Host configured from environment variable
  • Server middleware correctly uses flushAt: 1 and flushInterval: 0 for short-lived requests
  • __add_tracing_headers configured for client-server session correlation
  • posthog.shutdown() called after each server request

PostHog insights and events ⚠️

Filename PostHog events Description
login.tsx login_email_submitted Tracks login form submission — but includes email as PII in event properties
register.tsx registration_email_submitted Tracks registration form submission — but includes email as PII in event properties
auth.callback.ts user_signed_up Server-side: new user created after OAuth callback — includes email as PII
contact-sales-team.tsx contact_sales_submitted Tracks sales contact form — includes work_email as PII
user-account.tsx onboarding_user_account_completed Tracks user account onboarding step completion
organization.tsx onboarding_organization_completed Tracks organization onboarding step with org name
billing-action.server.ts subscription_cancelled, subscription_checkout_started, subscription_resumed, subscription_plan_switched Server-side billing events with org/subscription context
_sidebar-layout.tsx identify() Identifies user with email and name on authenticated pages
root.tsx captureException Captures unhandled errors in ErrorBoundary

Issues

  • PII in event properties: login_email_submitted, registration_email_submitted, user_signed_up, and contact_sales_submitted all include email addresses in posthog.capture() event properties. Email is PII and should only appear in identify() person properties or /, not in event properties. Fix: remove email from capture properties; it's already set via identify(). [CRITICAL]

Other completed criteria

  • Events represent real user actions (signup, login, onboarding, billing lifecycle)
  • Events enable product insights — a full signup-to-subscription funnel can be built
  • Server-side billing events include enriched properties (org_id, subscription_id, price_lookup_key)
  • Event names are descriptive and use consistent snake_case convention

Reviewed by wizard workbench PR evaluator

@wizard-ci-bot wizard-ci-bot Bot added the CI/CD label May 13, 2026
@wizard-ci-bot wizard-ci-bot Bot closed this May 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants