Skip to content

[CI] (tune-mini-xhigh) next-js/15-app-router-saas#2407

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

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

Conversation

@wizard-ci-bot

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

Copy link
Copy Markdown

Automated wizard CI run

Source: manual
Trigger ID: tune-mini-xhigh
App: next-js/15-app-router-saas
App directory: apps/next-js/15-app-router-saas
Workbench branch: wizard-ci-tune-mini-xhigh-next-js-15-app-router-saas
Wizard branch: 02e5d9e3b5f62084508a42f545c78f7e6bfa865b
Context Mill branch: main
PostHog (MCP) branch: master
Timestamp: 2026-07-03T17:13:44.698Z
Duration: 932.0s

YARA Scanner

✓ 67 tool calls scanned, 0 violations detected

No violations: ✓ 67 clean scans

@wizard-ci-bot

wizard-ci-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown
Author

PR Evaluation Report

Summary

This PR adds PostHog integration to a Next.js 15 App Router SaaS application. It installs both posthog-js and posthog-node, creates a server-side singleton client, and adds server-side event captures for authentication flows (sign in, sign up, sign out), Stripe checkout/webhooks, and a client-side team management event. However, posthog-js is installed but never initialized on the client, there is no PostHogProvider, no identify(), no error tracking, no reverse proxy, and a non-functional /api/posthog/capture endpoint that silently drops events.

Files changed Lines added Lines removed
9 +203 -1

Confidence score: 3/5 🤔

  • No client-side PostHog initialization: posthog-js is added to package.json but never imported or initialized anywhere — no instrumentation-client.ts, no PostHogProvider, no posthog.init(). The client-side SDK is completely non-functional. [CRITICAL]
  • Fake capture endpoint drops events: /api/posthog/capture accepts POST requests but does nothing — it returns { ok: true } without forwarding events. The captureEvent() function in dashboard/page.tsx sends events to this black hole, meaning team_member_removed is never actually tracked. [CRITICAL]
  • No user identification: No posthog.identify() calls anywhere in the codebase. No posthog.reset() on logout. Users are never linked to their events on the client side. [CRITICAL]
  • PII in server-side capture properties: user_signed_in and user_signed_up events include email directly in event properties rather than using person properties via ``. [MEDIUM]
  • No error tracking: No captureException(), no error boundary, no exception autocapture configured. [MEDIUM]

File changes

Filename Score Description
lib/posthog-server.ts 4/5 Server-side singleton client — correct pattern per Next.js docs
app/(login)/actions.ts 2/5 Server-side auth captures with redundant double-nested try/catch and PII in event properties
app/api/stripe/checkout/route.ts 3/5 Checkout capture is reasonable but no await posthog.shutdown()
app/api/stripe/webhook/route.ts 3/5 Webhook capture OK, uses Stripe customer ID as distinctId (not a real user ID)
lib/payments/stripe.ts 2/5 Creates a new PostHog instance instead of using the singleton; uses team.id as distinctId
app/(dashboard)/dashboard/page.tsx 1/5 Client-side captureEvent() sends to a non-functional endpoint — events are silently dropped
app/api/posthog/capture/route.ts 1/5 Endpoint parses JSON then does nothing with it — completely non-functional
package.json 3/5 Both SDKs added, but posthog-js is never used
posthog-setup-report.md 2/5 Reports events (team_member_invited, user_profile_updated) that don't exist in the code

App sanity check ⚠️

Criteria Result Description
App builds and runs Yes No syntax or type errors that would prevent build
Preserves existing env vars & configs Yes Existing code and configs untouched
No syntax or type errors Yes Code is syntactically valid
Correct imports/exports Yes All imports resolve correctly
Minimal, focused changes No Non-functional /api/posthog/capture endpoint adds dead code; posthog-js installed but unused
Pre-existing issues None No pre-existing issues noted

Issues

  • Non-functional capture endpoint: /api/posthog/capture/route.ts parses the request body then discards it, returning { ok: true }. This creates a false impression that client-side events are being captured. Either forward events to PostHog or remove this endpoint and use posthog-js directly. [CRITICAL]
  • posthog-js installed but unused: The package is in package.json but never imported or initialized. This is dead weight. [MEDIUM]
  • Redundant double try/catch: In actions.ts, sign-in, sign-up, and sign-out captures are wrapped in two nested try/catch blocks catching the same error — the outer catch is unreachable. [LOW]
  • .env.example not updated: PostHog environment variables (NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN, NEXT_PUBLIC_POSTHOG_HOST) are not documented in .env.example. [MEDIUM]

Other completed criteria

  • App builds without errors
  • Existing app code and configs preserved
  • No syntax or type errors introduced
  • All imports resolve correctly

PostHog implementation ❌

Criteria Result Description
PostHog SDKs installed Yes posthog-js and posthog-node added to package.json
PostHog client initialized No Server-side singleton exists but posthog-js is never initialized — no instrumentation-client.ts, no PostHogProvider, no posthog.init()
capture() Yes Multiple server-side capture() calls for auth and Stripe events (client-side captures are broken)
identify() No No posthog.identify() calls anywhere; no posthog.reset() on logout
Error tracking No No captureException(), no error boundary, no exception autocapture
Reverse proxy No No reverse proxy configured in next.config.ts

Issues

  • Missing client-side initialization: Per Next.js docs, PostHog should be initialized via instrumentation-client.ts with posthog.init(), and optionally wrapped in a PostHogProvider for React hooks. Neither exists. Without client-side initialization, autocapture (pageviews, clicks) is completely absent. [CRITICAL]
  • No user identification: posthog.identify() is never called — not on login, not on page load for returning users. Server-side captures use database IDs as distinctId, but these are never linked to client-side anonymous sessions. [CRITICAL]
  • No error tracking: No PostHogErrorBoundary, no captureException(), no capture_exceptions: true in init config. [MEDIUM]
  • No reverse proxy: Recommended for Next.js to avoid ad blockers. No rewrites configured. [MEDIUM]
  • Inconsistent client instantiation: lib/payments/stripe.ts creates a new PostHog instance with new PostHog(...) instead of using the getPostHogClient() singleton, leading to potential connection overhead and inconsistency. [LOW]
  • Missing shutdown() on singleton: The singleton posthogClient in posthog-server.ts is never shut down after captures in actions.ts or checkout/route.ts. In short-lived Next.js server functions, events may be lost. [LOW]

Other completed criteria

  • Both PostHog SDKs added to dependencies
  • API key loaded from environment variable (NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN)
  • Host correctly configured via environment variable (NEXT_PUBLIC_POSTHOG_HOST)

PostHog insights and events ⚠️

Filename PostHog events Description
app/(login)/actions.ts user_signed_up, user_signed_in, user_signed_out Server-side auth lifecycle events with email in properties (PII concern)
app/api/stripe/checkout/route.ts checkout_completed Captures successful Stripe checkout with subscription details
app/api/stripe/webhook/route.ts subscription_webhook_received Captures subscription changes from Stripe webhooks; uses Stripe customer ID as distinctId
lib/payments/stripe.ts manage_subscription_clicked Captures portal access; uses team.id as distinctId (not a user ID)
app/(dashboard)/dashboard/page.tsx team_member_removed Non-functional — sends to dead endpoint that discards events

Issues

  • PII in event properties: user_signed_in and user_signed_up include email directly in capture() properties. Per PostHog best practices, email should be set via person properties (``) in an identify() call, not in event properties. [MEDIUM]
  • Setup report lists phantom events: The posthog-setup-report.md claims team_member_invited and user_profile_updated events exist, but they are not present in the diff or any changed files. [LOW]
  • Inconsistent distinctId values: Different events use different ID types — user database IDs (String(user.id)), Stripe customer IDs (String(subscription.customer)), and team IDs (String(team.id)). This fragments data across unlinked persons in PostHog. [MEDIUM]

Other completed criteria

  • Events represent real user actions (sign up, sign in, checkout, subscription management)
  • Events enable product insights (signup → sign in → checkout funnel is possible)
  • Events include contextual properties (team IDs, subscription IDs, product IDs)
  • Event names are descriptive and follow consistent snake_case convention

Reviewed by wizard workbench PR evaluator

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