Skip to content

[CI] (e2f7ab0) next-js/15-app-router-saas#2427

Closed
wizard-ci-bot[bot] wants to merge 1 commit into
mainfrom
wizard-ci-e2f7ab0-next-js-15-app-router-saas
Closed

[CI] (e2f7ab0) next-js/15-app-router-saas#2427
wizard-ci-bot[bot] wants to merge 1 commit into
mainfrom
wizard-ci-e2f7ab0-next-js-15-app-router-saas

Conversation

@wizard-ci-bot

@wizard-ci-bot wizard-ci-bot Bot commented Jul 6, 2026

Copy link
Copy Markdown

Automated wizard CI run

Source: wizard-pr
Trigger ID: e2f7ab0
App: next-js/15-app-router-saas
App directory: apps/next-js/15-app-router-saas
Workbench branch: wizard-ci-e2f7ab0-next-js-15-app-router-saas
Wizard branch: release-please--branches--main--components--wizard
Context Mill branch: main
PostHog (MCP) branch: master
Timestamp: 2026-07-06T22:10:10.232Z
Duration: 534.8s

YARA Scanner

✓ 69 tool calls scanned, 0 violations detected

No violations: ✓ 69 clean scans

@wizard-ci-bot

wizard-ci-bot Bot commented Jul 6, 2026

Copy link
Copy Markdown
Author

PR Evaluation Report

Summary

This PR integrates PostHog into a Next.js 15 App Router SaaS application with both client-side (posthog-js via instrumentation-client.ts) and server-side (posthog-node) analytics. It includes user identification, reverse proxy, error tracking, session reset on logout, and comprehensive server-side event capture across authentication, account management, team operations, and Stripe billing flows.

Files changed Lines added Lines removed
14 +234 -2

Confidence score: 4/5 👍

  • Webhook distinct_id is fabricated: The Stripe webhook handler uses stripe_customer_ as the distinctId, which won't link to the real user (String(user.id)) used everywhere else, creating orphaned person profiles and fragmented analytics. Should look up the user associated with the Stripe customer. [MEDIUM]
  • No .env.example updated: Environment variables NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN and NEXT_PUBLIC_POSTHOG_HOST are not documented in any .env.example file — only mentioned in the wizard's setup report as a TODO. [MEDIUM]

File changes

Filename Score Description
instrumentation-client.ts 5/5 Client-side PostHog init with env vars, reverse proxy host, error tracking, and debug mode
lib/posthog-server.ts 5/5 Server-side PostHog client factory with proper flushAt: 1 and flushInterval: 0 for short-lived contexts
next.config.ts 5/5 Reverse proxy rewrites correctly routing /ingest/static/* and /ingest/array/* to assets origin
package.json 5/5 Both posthog-js and posthog-node added to dependencies
components/posthog-identify.tsx 4/5 Identifies users via SWR user data; PII correctly placed in person properties
app/(login)/actions.ts 4/5 Comprehensive server-side captures for auth and team operations with proper shutdown() calls
app/api/stripe/webhook/route.ts 3/5 Captures subscription events but uses fabricated stripe_customer_ distinct_id
app/api/stripe/checkout/route.ts 5/5 Checkout completion captured with enriched plan/subscription properties
app/(dashboard)/dashboard/page.tsx 5/5 Client-side capture for manage subscription click with plan context
app/(dashboard)/pricing/submit-button.tsx 4/5 Captures checkout_started but with no properties
app/(dashboard)/layout.tsx 5/5 posthog.reset() on sign-out — correct pattern
app/layout.tsx 5/5 PostHogIdentify component added at root layout level
.gitignore 5/5 Excludes .env.local
posthog-setup-report.md 5/5 Wizard-generated setup report with event table and next steps

App sanity check ⚠️

Criteria Result Description
App builds and runs Yes No syntax or type errors; all imports resolve correctly
Preserves existing env vars & configs Yes Existing next.config.ts structure preserved; rewrites added cleanly
No syntax or type errors Yes All TypeScript is valid; non-null assertions on env vars are standard for Next.js
Correct imports/exports Yes posthog-js imported client-side only, posthog-node server-side only
Minimal, focused changes Yes All changes directly related to PostHog integration
Pre-existing issues None No pre-existing issues observed

Issues

  • Missing .env.example: NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN and NEXT_PUBLIC_POSTHOG_HOST are used but not documented in any env example file. Collaborators won't know what variables to set. [MEDIUM]

Other completed criteria

  • Build configuration is valid — package.json dependencies are correct, next.config.ts rewrites are properly structured
  • All existing app functionality preserved — no code removed or broken

PostHog implementation ⚠️

Criteria Result Description
PostHog SDKs installed Yes posthog-js@^1.398.0 and posthog-node@^5.39.4 added to package.json
PostHog client initialized Yes Client init in instrumentation-client.ts (recommended for Next.js 15.3+); server client factory in lib/posthog-server.ts with flushAt: 1, flushInterval: 0
capture() Yes 13 distinct events captured across client and server
identify() Yes PostHogIdentify component identifies users with String(user.id) + person properties; server-side identify on signup
Error tracking Yes capture_exceptions: true in posthog.init() config
Reverse proxy Yes Next.js rewrites route /ingest/* through proxy; /ingest/static/* and /ingest/array/* correctly routed to us-assets.i.posthog.com

Issues

  • Webhook fabricated distinct_id: The Stripe webhook handler captures subscription_updated and subscription_canceled with distinctId: \stripe_customer_`. This doesn't match the String(user.id)` used everywhere else, so these events won't associate with actual user profiles. Look up the user by Stripe customer ID from your database before capturing. [MEDIUM]

Other completed criteria

  • API key loaded from process.env.NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN — not hardcoded
  • Host correctly configured via env var for server, reverse proxy /ingest for client
  • posthog.reset() called on sign-out to unlink sessions
  • ui_host correctly set to https://us.posthog.com when using reverse proxy
  • Server-side client properly calls await posthog.shutdown() after every capture

PostHog insights and events ✅

Filename PostHog events Description
app/(login)/actions.ts user_signed_in, user_signed_up, user_signed_out, password_updated, account_deleted, account_updated, team_member_removed, team_member_invited Server-side auth & team management events with team_id, role, and invitation context
app/api/stripe/checkout/route.ts checkout_completed Captures successful Stripe checkout with plan name, product ID, and subscription ID
app/api/stripe/webhook/route.ts subscription_updated, subscription_canceled Stripe webhook events with subscription status and plan info
app/(dashboard)/pricing/submit-button.tsx checkout_started Client-side click on checkout button
app/(dashboard)/dashboard/page.tsx manage_subscription_clicked Client-side click with plan name and subscription status properties
instrumentation-client.ts captureException (via capture_exceptions: true) Automatic exception capture enabled

Issues

  • checkout_started lacks properties: The event is captured bare with no properties (e.g., plan name, price). Adding plan context would enable richer funnel analysis. [LOW]

Other completed criteria

  • Events represent real user actions mapping to actual product flows (signup → checkout → subscription lifecycle)
  • Events enable product insights — clear funnel from checkout_startedcheckout_completed, retention via user_signed_in, churn via subscription_canceled
  • Most events include contextual properties (team_id, plan_name, subscription_status, role)
  • No PII in event properties — email and name only passed via identify() person properties
  • Consistent snake_case naming convention across all events

Reviewed by wizard workbench PR evaluator

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