Skip to content

[CI] (cc5471b) react-router/saas-template - #4791

Closed
wizard-ci-bot[bot] wants to merge 2 commits into
mainfrom
wizard-ci-cc5471b-react-router-saas-template
Closed

wizard-ci-bot[bot] wants to merge 2 commits into
mainfrom
wizard-ci-cc5471b-react-router-saas-template

Conversation

@wizard-ci-bot

@wizard-ci-bot wizard-ci-bot Bot commented Oct 28, 2026

Copy link
Copy Markdown

Automated wizard CI run

Source: scheduled
Trigger ID: cc5471b
App: react-router/saas-template
App directory: apps/react-router/saas-template
Workbench branch: wizard-ci-cc5471b-react-router-saas-template
Wizard branch: main
Context Mill branch: main
PostHog (MCP) branch: master
Timestamp: 2026-10-28T17:03:30.460Z
Duration: 484.6s

YARA Scanner

✓ 208 tool calls scanned, 0 violations detected

No violations: ✓ 208 clean scans

@wizard-ci-bot

wizard-ci-bot Bot commented Oct 28, 2026

Copy link
Copy Markdown
Author

PR Evaluation Report

Summary

This PR adds PostHog integration to a React Router v7 framework-mode SaaS template. It installs posthog-js and @posthog/react, initializes PostHog in entry.client.tsx, wraps the app with PostHogProvider and PostHogErrorBoundary, identifies users via a loader in the authenticated layout, resets on logout, and adds capture calls across 10+ components covering org management, onboarding, settings, and pastes.

Files changed Lines added Lines removed
18 +249 -7

Confidence score: 4/5 👍

  • Missing ssr.noExternal in vite.config.ts: The React Router v7 framework mode docs explicitly require ssr: { noExternal: ['posthog-js', '@posthog/react'] } to avoid SSR errors. Multiple components import @posthog/react and are rendered during SSR. [CRITICAL]
  • No reverse proxy configured: Client-side PostHog events are vulnerable to ad blockers. The docs recommend configuring a reverse proxy for React Router apps. [MEDIUM]
  • All capture calls lack event properties: Every posthog.capture() call sends only the event name with zero contextual properties (e.g., organization_id, paste_type, invitation_method), severely limiting the analytical value of these events. [MEDIUM]

File changes

Filename Score Description
app/entry.client.tsx 4/5 PostHog init with env vars, defaults, PostHogProvider + PostHogErrorBoundary wrapping. Good dev-mode error throwing for missing config.
app/entry.server.tsx 4/5 CSP updated for connect-src, script-src, and worker-src to allow PostHog.
app/routes/_authenticated-routes+/_authenticated-routes-layout.tsx 4/5 Loader fetches user.id for identify; useEffect calls identify with dedup check.
app/features/organizations/layout/nav-user.tsx 3/5 Calls posthog.reset() on logout (correct), but uses posthog.logger.info which is a debug console logger, not an event capture mechanism.
app/routes/.../pastes.tsx 3/5 Captures paste_creation_submitted on form submit, but also misuses posthog.logger.info.
vite.config.ts 2/5 Not modified — missing required ssr.noExternal config for PostHog packages.
package.json 5/5 posthog-js and @posthog/react correctly added as dependencies.
.env.example 5/5 PostHog env vars documented.
app/utils/env.server.ts 5/5 PostHog env vars added to schema (optional) and exposed to client via getEnv().
Various component files (×10) 3/5 Capture calls added to meaningful user actions but all lack contextual properties.

App sanity check ⚠️

Criteria Result Description
App builds and runs ⚠️ Missing ssr.noExternal for posthog-js and @posthog/react in vite.config.ts — may cause SSR build/runtime errors per React Router v7 framework mode docs
Preserves existing env vars & configs Yes Existing configs preserved; PostHog additions are additive
No syntax or type errors Yes All changed files have valid TypeScript/TSX syntax
Correct imports/exports Yes posthog-js and @posthog/react imports are correct
Minimal, focused changes Yes All changes are PostHog-related
Pre-existing issues None

Issues

  • Missing ssr.noExternal in vite.config.ts: The React Router v7 framework mode docs explicitly state that posthog-js and @posthog/react must be added to ssr: { noExternal: [...] } in vite.config.ts to avoid SSR errors. Ten+ component files import @posthog/react hooks that are processed during SSR. Add ssr: { noExternal: ['posthog-js', '@posthog/react'] } to the Vite config. [CRITICAL]
  • posthog.logger.info() misuse: In nav-user.tsx and pastes.tsx, posthog?.logger.info(...) is used as if it were an event capture method. This is actually PostHog's internal SDK debug logger — it only outputs to the browser console when debug mode is enabled and sends no data to PostHog. Remove these calls or replace with posthog.capture() if the intent was to send events. [LOW]

Other completed criteria

  • Environment variables documented in .env.example with VITE_PUBLIC_POSTHOG_PROJECT_TOKEN and VITE_PUBLIC_POSTHOG_HOST
  • CSP headers updated in entry.server.tsx for connect-src, script-src, and worker-src
  • .gitignore updated to exclude .env
  • Env schema in env.server.ts updated with optional PostHog vars and getEnv() exposes them to the client
  • Build config (package.json) includes correct dependency versions

PostHog implementation ⚠️

Criteria Result Description
PostHog SDKs installed Yes posthog-js ^1.441.2 and @posthog/react ^1.11.3 added to package.json
PostHog client initialized Yes posthog.init() in entry.client.tsx with api_host, defaults: "2026-08-30", and logs config; wrapped with PostHogProvider client={posthog}
capture() Yes 12+ meaningful capture calls across org creation, settings, invitations, onboarding, and pastes
identify() Yes posthog.identify(user.id, { email }) in authenticated layout via loader + useEffect with dedup check; user.id is a stable auth system ID
Error tracking Yes PostHogErrorBoundary wraps the entire app inside PostHogProvider
Reverse proxy No Not configured — client-side events will be blocked by ad blockers

Issues

  • No reverse proxy: For a full-stack React Router app, the docs recommend setting up a reverse proxy to prevent ad blockers from intercepting PostHog events. This can be done via Next.js-style rewrites, Vercel rewrites, Cloudflare, or PostHog's managed proxy service. [MEDIUM]
  • Redundant env checks on every capture: Every capture call is wrapped in if (window.ENV.VITE_PUBLIC_POSTHOG_PROJECT_TOKEN && window.ENV.VITE_PUBLIC_POSTHOG_HOST). This is unnecessary since posthog?.capture() safely no-ops when PostHog isn't initialized (the initializePostHog() function already guards against missing env vars). This adds boilerplate to every event site. [LOW]

Other completed criteria

  • API key loaded from window.ENV.VITE_PUBLIC_POSTHOG_PROJECT_TOKEN (not hardcoded)
  • Host configured from window.ENV.VITE_PUBLIC_POSTHOG_HOST
  • posthog.reset() called on logout in nav-user.tsx
  • Identify uses stable user.id from auth system, email passed as person property (correct)
  • Dedup check: posthog.get_distinct_id() !== distinctId prevents redundant identify calls

PostHog insights and events ⚠️

Filename PostHog events Description
entry.client.tsx PostHogErrorBoundary Captures uncaught React exceptions via error boundary
_authenticated-routes-layout.tsx identify() Identifies authenticated users with user.id and email
nav-user.tsx reset() Resets PostHog identity on logout
create-organization-form-card.tsx organization_creation_submitted Org creation form submit
danger-zone.tsx (org) organization_deletion_submitted Org deletion confirmation
general-organization-settings.tsx organization_settings_updated Org settings save
invite-by-email-card.tsx team_invitation_submitted Email invite sent
invite-link-card.tsx invite_link_copied, invite_link_generated, invite_link_deactivated Invite link lifecycle
account-settings.tsx account_settings_updated User account settings save
danger-zone.tsx (user) account_deletion_submitted Account deletion confirmation
organization.tsx (onboarding) onboarding_organization_submitted Onboarding org step
user-account.tsx (onboarding) onboarding_user_account_submitted Onboarding user step
pastes.tsx paste_creation_submitted Paste creation form submit

Issues

  • No event properties on any capture call: All 12+ capture calls are bare (posthog.capture('event_name')) with zero properties. This makes it impossible to break down events by org, user role, plan, or any other dimension. For example, organization_deletion_submitted should include organization_id; paste_creation_submitted should include organization_slug; invite_link_generated should include the invite method. [MEDIUM]

Other completed criteria

  • Events represent real user actions mapping to product flows (onboarding → org creation → settings → invite → usage)
  • Events could build a funnel: onboarding_user_account_submitted → onboarding_organization_submitted → paste_creation_submitted
  • Event names are descriptive, consistent snake_case
  • No PII in capture properties; email correctly placed in identify person properties only

Reviewed by wizard workbench PR evaluator

@wizard-ci-bot wizard-ci-bot Bot added the CI/CD label Oct 28, 2026
@wizard-ci-bot wizard-ci-bot Bot closed this Oct 28, 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