Skip to content

[CI] (gpt5-trial-2) next-js/15-app-router-saas#2404

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

[CI] (gpt5-trial-2) next-js/15-app-router-saas#2404
wizard-ci-bot[bot] wants to merge 1 commit into
mainfrom
wizard-ci-gpt5-trial-2-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: gpt5-trial-2
App: next-js/15-app-router-saas
App directory: apps/next-js/15-app-router-saas
Workbench branch: wizard-ci-gpt5-trial-2-next-js-15-app-router-saas
Wizard branch: 1eb16c89a1ac295f0887a96381fff7314e999b05
Context Mill branch: main
PostHog (MCP) branch: master
Timestamp: 2026-07-03T16:21:40.904Z
Duration: 448.0s

YARA Scanner

✓ 68 tool calls scanned, 1 violation detected

  [BLOCKED] pii_in_capture_call (HIGH) — PostToolUse:Edit

No violations: ✓ 67 clean scans

⚠️ YARA violations detected — see report above

@wizard-ci-bot

wizard-ci-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown
Author

Now I have all the context needed to write the evaluation.


PR Evaluation Report

Summary

This PR integrates PostHog into a Next.js 15 App Router SaaS app with both client-side (posthog-js via instrumentation-client.ts) and server-side (posthog-node via singleton wrapper) SDKs. It adds a reverse proxy via Next.js rewrites, captures checkout and auth form submission events on the client, and a subscription_updated event on the server via Stripe webhook. However, there are several issues: a dead import, a missing pricing_viewed event that the report claims exists, no identify() call, and no shutdown() call in the webhook route.

Files changed Lines added Lines removed
11 +127 -5

Confidence score: 4/5 👍

  • Ghost event pricing_viewed: The setup report claims a pricing_viewed event is captured in pricing/page.tsx, but the actual code only adds a no-op comment — no posthog.capture() call exists. Similarly, subscription_activated is listed in the report but never captured in checkout/route.ts. [CRITICAL]
  • No identify() call: The login form captures signin_submitted/signup_submitted events but never calls posthog.identify() to link the user. The app has auth context available but doesn't use it. [CRITICAL]
  • Dead import in checkout route: getPostHogClient is imported in app/api/stripe/checkout/route.ts but never used — dead code that suggests an incomplete implementation. [MEDIUM]
  • Missing shutdown() in webhook route: The Stripe webhook handler calls posthog.capture() but never calls await posthog.shutdown(), so events may be lost in short-lived serverless functions. [MEDIUM]
  • Webhook uses hardcoded distinct_id: 'stripe_webhook': This creates a fake "user" in PostHog rather than resolving to the actual customer. [MEDIUM]

File changes

Filename Score Description
instrumentation-client.ts 4/5 Correct Next.js 15+ initialization pattern with posthog-js, reverse proxy host, exception autocapture
lib/posthog-server.ts 4/5 Proper singleton pattern for posthog-node with flushAt:1/flushInterval:0
next.config.ts 4/5 Correct reverse proxy rewrites for /ingest with static + array asset routes
package.json 5/5 Both posthog-js and posthog-node added
.env.example 5/5 Environment variables documented
app/(login)/login.tsx 3/5 Captures auth events but missing identify; wraps form action correctly
app/(dashboard)/pricing/submit-button.tsx 4/5 Clean checkout_started capture in onClick handler
app/(dashboard)/pricing/page.tsx 1/5 Only adds comments, no actual event capture despite report claiming pricing_viewed
app/api/stripe/checkout/route.ts 1/5 Dead import of getPostHogClient, no capture call, no subscription_activated event
app/api/stripe/webhook/route.ts 2/5 Captures subscription_updated but with hardcoded distinct_id and no shutdown()
posthog-setup-report.md 2/5 Lists events that don't exist in code (pricing_viewed, subscription_activated)

App sanity check ⚠️

Criteria Result Description
App builds and runs Yes No syntax errors; dead import won't break build
Preserves existing env vars & configs Yes Existing env vars preserved; next.config comments replaced with rewrites but functionality intact
No syntax or type errors Yes All syntax valid; @ts-ignore used for formAction typing
Correct imports/exports No getPostHogClient imported but never used in checkout/route.ts
Minimal, focused changes No Comments-only change in pricing/page.tsx adds no value; dead import in checkout route
Pre-existing issues None

Issues

  • Dead import in checkout route: getPostHogClient is imported in app/api/stripe/checkout/route.ts but never called. This is dead code suggesting an incomplete implementation — the report claims a subscription_activated event should be captured here. [MEDIUM]
  • No-op comments in pricing page: The pricing page change adds only comments about tracking with no actual implementation. The comment even says "This is a no-op comment to document event in plan." [MEDIUM]

Other completed criteria

  • App builds without syntax errors
  • Existing environment variables and configurations are preserved
  • No type errors introduced (TypeScript valid)
  • Build configuration (package.json, next.config.ts) is valid
  • Environment variables documented in .env.example

PostHog implementation ⚠️

Criteria Result Description
PostHog SDKs installed Yes posthog-js ^1.396.6 and posthog-node ^5.39.4 added to package.json
PostHog client initialized Yes Client: instrumentation-client.ts with posthog.init(). Server: singleton in lib/posthog-server.ts
capture() Yes checkout_started, signin_submitted, signup_submitted on client; subscription_updated on server
identify() No No posthog.identify() call anywhere. Login form captures events but doesn't identify users. No posthog.reset() on logout either
Error tracking Yes capture_exceptions: true in instrumentation-client.ts enables exception autocapture
Reverse proxy Yes Next.js rewrites correctly proxy /ingest/static/* and /ingest/array/* to us-assets.i.posthog.com, and /ingest/* to us.i.posthog.com

Issues

  • No identify() call: The app has authentication (login/signup forms with email) but never calls posthog.identify(). This means all events remain anonymous and cannot be linked to specific users. The login handler should call posthog.identify(user.id, { email, name }) after successful authentication. [CRITICAL]
  • No reset() on logout: Without posthog.reset() on logout, shared devices would merge different users' events. [MEDIUM]
  • Missing shutdown() in webhook: The Stripe webhook route calls posthog.capture() via the singleton but never calls await posthog.shutdown(). In serverless environments, events may be lost before the function terminates. [MEDIUM]
  • Hardcoded distinct_id in webhook: distinctId: 'stripe_webhook' creates a phantom user in PostHog. Should resolve to the actual customer's distinct_id from the subscription metadata or customer email. [MEDIUM]

Other completed criteria

  • API key loaded from environment variable (NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN)
  • API host correctly configured via reverse proxy (/ingest) with ui_host fallback
  • Both client and server SDKs properly initialized
  • Reverse proxy correctly routes static and array assets

PostHog insights and events ⚠️

Filename PostHog events Description
instrumentation-client.ts autocapture, ``, captureException Client init with exception autocapture and default autocapture
app/(dashboard)/pricing/submit-button.tsx checkout_started Captures when user clicks a pricing plan's checkout button
app/(login)/login.tsx signin_submitted, signup_submitted Captures auth form submissions with contextual properties (has_redirect, has_price_id, has_invite_id)
app/api/stripe/webhook/route.ts subscription_updated Server-side capture on Stripe subscription change webhook
app/(dashboard)/pricing/page.tsx (none — comments only) Report claims pricing_viewed but no capture call exists
app/api/stripe/checkout/route.ts (none — dead import) Report claims subscription_activated but no capture call exists

Issues

  • Ghost events in report: The setup report lists pricing_viewed and subscription_activated as implemented events, but neither has an actual posthog.capture() call in the code. This is misleading and means the claimed funnel (pricing → checkout → subscription) has gaps. [CRITICAL]
  • Hardcoded webhook distinct_id: subscription_updated uses distinctId: 'stripe_webhook' instead of a real user identifier, making the event useless for per-user analytics. [MEDIUM]

Other completed criteria

  • Event names use consistent snake_case naming convention
  • Events represent real user actions (checkout, auth submissions, subscription changes)
  • Auth events include relevant contextual properties (has_redirect, has_price_id, has_invite_id)
  • No PII in capture() event properties — email is not sent in event properties

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