Skip to content

[CI] (362fa9c) next-js/15-app-router-saas#313

Closed
wizard-ci-bot[bot] wants to merge 1 commit intomainfrom
wizard-ci-362fa9c-next-js-15-app-router-saas
Closed

[CI] (362fa9c) next-js/15-app-router-saas#313
wizard-ci-bot[bot] wants to merge 1 commit intomainfrom
wizard-ci-362fa9c-next-js-15-app-router-saas

Conversation

@wizard-ci-bot
Copy link

@wizard-ci-bot wizard-ci-bot bot commented Feb 11, 2026

Automated wizard CI run

Source: manual
Trigger ID: 362fa9c
App: next-js/15-app-router-saas
App directory: apps/next-js/15-app-router-saas
Workbench branch: wizard-ci-362fa9c-next-js-15-app-router-saas
Wizard branch: main
Context Mill branch: main
PostHog (MCP) branch: master
Timestamp: 2026-02-11T17:36:28.523Z
Duration: 538.6s

@wizard-ci-bot
Copy link
Author

wizard-ci-bot bot commented Feb 11, 2026

Now I have all the information needed to provide a comprehensive PR evaluation. Let me compile my review:


PR Evaluation Report

Summary

This PR integrates PostHog analytics into a Next.js 15 App Router SaaS application, adding both client-side and server-side tracking. The implementation includes automatic pageview tracking via instrumentation-client.ts, server-side event capture for Stripe webhooks, user identification on authentication, and a reverse proxy configuration to bypass ad blockers. A total of 12 custom events are tracked across authentication, subscription management, and team operations.

Files changed Lines added Lines removed
14 +558 -14

Confidence score: 4/5 👍

  • Server-side PostHog client missing await posthog.shutdown() calls in API routes: The server-side client in checkout and webhook routes doesn't await shutdown/flush, which means events may not be sent before the response completes. [MEDIUM]
  • Email used as distinctId in login.tsx poses privacy concern: Using raw email as the PostHog distinct ID (line 29: posthog.identify(email, { email })) exposes PII in analytics. Should use a hashed or user ID value instead. [MEDIUM]
  • Webhook distinctId uses Stripe customer ID, not user email: The webhook events use subscription.customer (Stripe customer ID) as distinctId, creating inconsistent user identification vs other events that use email. [MEDIUM]

File changes

Filename Score Description
instrumentation-client.ts 4/5 New file - Client-side PostHog initialization with proper reverse proxy config, exception capture, and debug mode. Uses defaults: '2026-01-30' which is a valid config option.
lib/posthog-server.ts 4/5 New file - Singleton server-side PostHog client with flushAt: 1 and flushInterval: 0 for immediate flush. Includes shutdown helper.
next.config.ts 5/5 Properly configured reverse proxy rewrites for /ingest and /ingest/static paths with skipTrailingSlashRedirect: true.
package.json 5/5 Added posthog-js and posthog-node dependencies with appropriate versions.
app/(login)/login.tsx 3/5 Added user identification and auth events. Uses email as distinctId which exposes PII. Event tracking fires before form action completes.
app/(dashboard)/dashboard/page.tsx 4/5 Added subscription, team invite, and team removal events with relevant properties.
app/(dashboard)/dashboard/general/page.tsx 4/5 Added account update event. Correctly avoids sending actual name/email values, only boolean flags.
app/(dashboard)/dashboard/security/page.tsx 4/5 Added password update and account deletion request events. No sensitive data captured.
app/(dashboard)/pricing/submit-button.tsx 4/5 Added pricing plan selection event. Simple integration.
app/api/stripe/checkout/route.ts 4/5 Server-side checkout completion event with relevant properties. Uses email as distinctId. Missing await on posthog operations.
app/api/stripe/webhook/route.ts 3/5 Server-side subscription events. Uses Stripe customer ID as distinctId (inconsistent with email used elsewhere). Missing flush/shutdown.
.gitignore 5/5 Properly ignores .env.local to prevent committing secrets.
pnpm-lock.yaml 5/5 Lock file updated with PostHog dependencies.
posthog-setup-report.md 4/5 Comprehensive documentation of the integration with event catalog and next steps.

App sanity check: 4/5 ✅

Criteria Result Description
App builds and runs Yes (conditional) TypeScript compilation passes. Build fails only due to missing POSTGRES_URL env var (not related to PostHog changes).
Preserves existing env vars & configs Yes Original next.config.ts structure preserved, PostHog config added additively.
No syntax or type errors Yes TypeScript compiles without errors.
Correct imports/exports Yes All imports are correct (posthog-js, posthog-node, local modules).
Minimal, focused changes Yes Changes are focused on PostHog integration only. Existing logic preserved.

Issues

  • Build requires database environment: Build fails without POSTGRES_URL - expected behavior for this app, not a PostHog issue. [LOW]

Other completed criteria

  • Original form action logic preserved (formAction still called after event capture)
  • No modifications to existing business logic
  • Error handling in original code unaffected
  • Component structure and patterns maintained

PostHog implementation: 4/5 ✅

Criteria Result Description
PostHog SDKs installed Yes posthog-js@^1.345.5 and posthog-node@^5.24.15 added to package.json
PostHog client initialized Yes Client-side via instrumentation-client.ts (Next.js 15.3+ pattern), server-side via singleton in lib/posthog-server.ts
capture() Yes 12 events captured across client and server
Identify() Yes posthog.identify(email, { email }) called on sign-in/sign-up
Error tracking Yes capture_exceptions: true enabled in client config
Reverse proxy Yes Configured via /ingest rewrites in next.config.ts to us.i.posthog.com

Issues

  • PII in distinctId: Using raw email as the distinct ID exposes personally identifiable information in PostHog. Should use a hashed identifier or internal user ID. [MEDIUM]
  • Inconsistent user identification: Client-side uses email, server-side webhook uses Stripe customer ID. This will create separate user profiles in PostHog. [MEDIUM]
  • Missing shutdown/flush in API routes: Server-side events in checkout and webhook routes don't await posthog.shutdown() before response, risking event loss. [MEDIUM]

Other completed criteria

  • API host correctly configured via environment variable
  • UI host properly set for PostHog dashboard links
  • Debug mode enabled only in development
  • Pageview tracking enabled via instrumentation file
  • Session replay enabled via defaults config

PostHog insights and events: 4/5 ✅

Filename PostHog events Description
login.tsx sign_in_submitted, sign_up_submitted Authentication funnel tracking with redirect/pricing context
submit-button.tsx pricing_plan_selected Conversion intent tracking
checkout/route.ts checkout_completed Server-side payment completion with plan details
webhook/route.ts subscription_updated, subscription_canceled Subscription lifecycle events with status properties
dashboard/page.tsx manage_subscription_clicked, team_member_invited, team_member_removed Team and billing engagement tracking
security/page.tsx password_updated, account_deletion_requested Security and churn risk signals
general/page.tsx account_updated Profile engagement tracking
instrumentation-client.ts Pageviews, exceptions Automatic tracking via SDK configuration

Issues

  • Events capture intent, not outcome: Events like password_updated and account_deletion_requested fire on form submission, not on success. Consider adding success/failure tracking. [MEDIUM]
  • Missing pricing plan context: pricing_plan_selected doesn't include which plan was selected - the form submits this data but the event doesn't capture it. [MEDIUM]

Other completed criteria

  • Events follow clear naming conventions
  • Properties are enriched with contextual data (plan names, subscription status, roles)
  • Sensitive data like passwords not captured
  • Events support funnel analysis (sign-up → pricing → checkout)
  • Documentation includes suggested dashboard insights

Reviewed by wizard workbench PR evaluator

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