Skip to content

[CI] (6fb03e7) next-js/15-pages-router-saas#1475

Closed
wizard-ci-bot[bot] wants to merge 1 commit into
mainfrom
wizard-ci-6fb03e7-next-js-15-pages-router-saas
Closed

[CI] (6fb03e7) next-js/15-pages-router-saas#1475
wizard-ci-bot[bot] wants to merge 1 commit into
mainfrom
wizard-ci-6fb03e7-next-js-15-pages-router-saas

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: next-js/15-pages-router-saas
App directory: apps/next-js/15-pages-router-saas
Workbench branch: wizard-ci-6fb03e7-next-js-15-pages-router-saas
Wizard branch: main
Context Mill branch: main
PostHog (MCP) branch: master
Timestamp: 2026-05-13T17:25:49.770Z
Duration: 550.4s

@wizard-ci-bot
Copy link
Copy Markdown
Author

wizard-ci-bot Bot commented May 13, 2026

Now I have all the context needed. Let me produce the evaluation.


PR Evaluation Report

Summary

This PR integrates PostHog into a Next.js 15 Pages Router SaaS app, adding both client-side (posthog-js via instrumentation-client.ts) and server-side (posthog-node) tracking. It includes a reverse proxy, user identification, error tracking, and 10 custom events across auth, checkout, subscription, and team management flows.

Files changed Lines added Lines removed
15 +196 -2

Confidence score: 4/5 👍

  • PII in capture event properties: Multiple posthog.capture() calls include email (and sometimes name) directly in event properties — user_signed_in, user_signed_up, account_updated, team_member_invited. PII must go in person properties via identify(), not in event properties. [CRITICAL]
  • Webhook distinct_id mismatch: pages/api/stripe/webhook.ts uses the raw Stripe customer ID (cus_xxx) as distinctId, but everywhere else uses email. These won't link to the same person in PostHog, causing fragmented user data. [CRITICAL]
  • Env vars not documented in .env.example: The pre-existing .env.example was not updated with NEXT_PUBLIC_POSTHOG_KEY or NEXT_PUBLIC_POSTHOG_HOST. New developers won't know these are required. [MEDIUM]
  • Email as distinct_id: Using raw email as the distinct ID (in identify(), server-side capture, etc.) is not recommended — a stable database user ID should be used instead. Email changes can cause identity issues. [MEDIUM]

File changes

Filename Score Description
instrumentation-client.ts 5/5 Client-side PostHog init via instrumentation-client.ts pattern, correct for Next.js 15.3+
lib/posthog-server.ts 4/5 Singleton server-side client with proper flushAt/flushInterval settings
next.config.ts 5/5 Reverse proxy rewrites with correct static/array/catch-all routes
package.json 5/5 Both posthog-js and posthog-node added with appropriate versions
components/login.tsx 2/5 Identify + capture + exception handling, but PII in event properties and email as distinct_id
components/header.tsx 5/5 Correct posthog.reset() on logout
pages/api/auth/sign-in.ts 3/5 Server-side identify + alias pattern, but uses email as distinct_id
pages/api/auth/sign-up.ts 3/5 Same pattern as sign-in
pages/api/stripe/create-checkout.ts 3/5 Server-side capture with useful properties, but email as distinct_id
pages/api/stripe/webhook.ts 2/5 Captures subscription events but uses Stripe customer ID as distinct_id — won't match other events
pages/dashboard/index.tsx 3/5 Good events but team_member_invited includes email in event properties
pages/dashboard/general.tsx 3/5 account_updated includes email and name in event properties
pages/pricing.tsx 5/5 Clean checkout_started capture with relevant properties
.gitignore 5/5 Correctly ignores .env.local
posthog-setup-report.md 4/5 Comprehensive report documenting all changes and next steps

App sanity check ⚠️

Criteria Result Description
App builds and runs Yes No syntax errors, valid TypeScript, correct imports
Preserves existing env vars & configs Yes Existing next.config.ts extended, no existing code removed
No syntax or type errors Yes All changes are syntactically valid
Correct imports/exports Yes posthog-js imported client-side, posthog-node server-side — correct separation
Minimal, focused changes Yes All changes relate to PostHog integration
Pre-existing issues None Base app appears clean

Issues

  • Env vars not documented: .env.example was not updated with NEXT_PUBLIC_POSTHOG_KEY and NEXT_PUBLIC_POSTHOG_HOST. New developers cloning the repo won't know these env vars are needed. [MEDIUM]

Other completed criteria

  • Build configuration is valid — package.json and next.config.ts are well-formed
  • posthog-js is only imported in client-side components, posthog-node in server-side files
  • Existing functionality (auth flow, Stripe webhooks) is preserved

PostHog implementation ⚠️

Criteria Result Description
PostHog SDKs installed Yes posthog-js@^1.373.4 and posthog-node@^5.34.1 in package.json
PostHog client initialized Yes instrumentation-client.ts calls posthog.init() with env var key, reverse proxy host, defaults, and exception capture. Server-side singleton in lib/posthog-server.ts
capture() Yes 10 meaningful events across client and server
identify() Yes Called on sign-in/sign-up both client and server-side, with alias for anonymous→identified linking. However, uses email as distinct_id instead of database user ID
Error tracking Yes capture_exceptions: true in init config for automatic exception capture, plus manual captureException() calls in catch blocks
Reverse proxy Yes Next.js rewrites in next.config.ts with correct /ingest/static/*, /ingest/array/*, and /ingest/* routes pointing to correct PostHog origins

Issues

  • Email used as distinct_id: posthog.identify(data.email, { email: data.email }) and all server-side captures use email as the distinct ID. Should use a stable database user ID (e.g., foundUser.id). If a user changes their email, events will fragment across different identities. [MEDIUM]
  • Webhook distinct_id mismatch: pages/api/stripe/webhook.ts uses subscription.customer (Stripe customer ID like cus_xxx) as distinctId. This doesn't match the email-based distinct_id used everywhere else, so subscription events won't be associated with the correct user profile. Should resolve the Stripe customer to the app's user and use the same identifier. [CRITICAL]

Other completed criteria

  • API key loaded from NEXT_PUBLIC_POSTHOG_KEY environment variable, not hardcoded
  • Host correctly configured — client uses /ingest reverse proxy, server uses NEXT_PUBLIC_POSTHOG_HOST
  • posthog.reset() correctly called on logout in header.tsx
  • Server-side alias pattern links anonymous pre-login events to identified user
  • Session/distinct ID headers passed from client to server for session correlation

PostHog insights and events ⚠️

Filename PostHog events Description
components/login.tsx user_signed_in, user_signed_up, captureException Tracks auth events on successful login/signup; captures exceptions on error. ⚠️ Email in event properties
components/header.tsx reset() Unlinks session on logout
pages/pricing.tsx checkout_started, captureException Tracks plan selection with plan name, price_id, and interval
pages/dashboard/index.tsx manage_subscription_clicked, team_member_removed, team_member_invited, captureException Tracks subscription management and team operations. ⚠️ team_member_invited includes invited_email
pages/dashboard/general.tsx account_updated, captureException Tracks profile updates. ⚠️ Includes email and name in event properties
pages/api/auth/sign-in.ts identify, alias Server-side user identification and anonymous→identified linking
pages/api/auth/sign-up.ts identify, alias Server-side new user identification
pages/api/stripe/create-checkout.ts checkout_session_created Server-side checkout tracking with price_id, team context
pages/api/stripe/webhook.ts subscription_updated, subscription_cancelled Server-side Stripe webhook events. ⚠️ Uses Stripe customer ID as distinct_id

Issues

  • PII in event properties: Email appears in event properties of user_signed_in, user_signed_up, account_updated, and team_member_invited. Names appear in account_updated. PII must be set via person properties (e.g., in identify() calls or ``), not in capture() event properties. Remove `email` and `name` from these capture calls. [CRITICAL]
  • Webhook distinct_id fragmentation: Subscription events use Stripe customer ID, making them impossible to associate with the user's PostHog profile. Look up the app user from the Stripe customer and use the same distinct_id. [CRITICAL]

Other completed criteria

  • Events represent real user actions mapped to actual product flows (auth, checkout, subscription, team management)
  • Events enable product insights — can build signup→checkout funnel, track churn, monitor team growth
  • Most events include relevant contextual properties (plan name, price_id, team_id, subscription_status)
  • 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