Skip to content

[CI] (1776c51) laravel/laravel12-saas#2722

Closed
wizard-ci-bot[bot] wants to merge 1 commit into
mainfrom
wizard-ci-1776c51-laravel-laravel12-saas
Closed

[CI] (1776c51) laravel/laravel12-saas#2722
wizard-ci-bot[bot] wants to merge 1 commit into
mainfrom
wizard-ci-1776c51-laravel-laravel12-saas

Conversation

@wizard-ci-bot

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

Copy link
Copy Markdown

Automated wizard CI run

Source: wizard-pr
Trigger ID: 1776c51
App: laravel/laravel12-saas
App directory: apps/laravel/laravel12-saas
Workbench branch: wizard-ci-1776c51-laravel-laravel12-saas
Wizard branch: release-please--branches--main--components--wizard
Context Mill branch: main
PostHog (MCP) branch: master
Timestamp: 2026-07-10T23:30:08.929Z
Duration: 322.3s

YARA Scanner

✓ 134 tool calls scanned, 0 violations detected

No violations: ✓ 134 clean scans

@wizard-ci-bot

wizard-ci-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown
Author

PR Evaluation Report

Summary

This PR adds PostHog analytics integration to a Laravel 12 SaaS application through a dedicated PostHogService class, configuration via config/services.php and .env.example, initialization in AppServiceProvider, exception tracking in bootstrap/app.php, and event capture across authentication, subscription, profile, and dashboard flows. However, the posthog/posthog-php package was never added to composer.json, meaning the app will not run.

Files changed Lines added Lines removed
18 +293 -19

Confidence score: 4/5 👍

  • PostHog PHP SDK not added to composer.json — The wizard's own report admits "posthog/posthog-php" was never installed. Every file imports PostHog\PostHog, so the app will crash with a class-not-found error at runtime. [CRITICAL]
  • Double PostHog::init() callsAppServiceProvider::boot() calls PostHog::init(), and PostHogService::__construct() also calls PostHog::init() with its own static guard. This is redundant and confusing; one path should be removed. [MEDIUM]
  • pricing_viewed uses session ID as distinct_id for anonymous userssession()->getId() produces a new value every session, creating orphan person profiles that can never be merged with an authenticated user. A better approach would be to skip capture for anonymous visitors or use a cookie-based identifier. [MEDIUM]

File changes

Filename Score Description
app/Services/PostHogService.php 3/5 New service class wrapping PostHog SDK calls with enable-check guards; has redundant PostHog::init()
app/Providers/AppServiceProvider.php 3/5 Adds PostHog initialization in boot() (correct pattern) but duplicates init logic from service
bootstrap/app.php 4/5 Adds exception reporting via PostHogService::captureException() with URL and method context
config/services.php 5/5 Clean config entry for PostHog with api_key, host, disabled
.env.example 5/5 Documents all three PostHog env vars
app/Models/User.php 5/5 Adds getPostHogDistinctId() (returns primary key) and getPostHogProperties() helper methods
app/Http/Controllers/SubscriptionController.php 5/5 Comprehensive subscription event tracking across checkout, activation, swap, and billing portal
app/Http/Controllers/Auth/SocialiteController.php 5/5 Tracks social login with provider and new-user flag
app/Http/Controllers/Auth/VerifyEmailController.php 5/5 Tracks email verification completion
app/Livewire/Dashboard.php 4/5 Tracks dashboard views with subscription info
resources/views/livewire/pages/auth/login.blade.php 5/5 Tracks login with identify call
resources/views/livewire/pages/auth/register.blade.php 5/5 Tracks signup with identify call
resources/views/livewire/pages/auth/forgot-password.blade.php 4/5 Tracks password reset request using session ID
resources/views/livewire/profile/*.blade.php 5/5 Tracks profile update, password change, account deletion
routes/web.php 3/5 Converts pricing route to closure for tracking; uses session ID for anonymous users
posthog-setup-report.md Wizard-generated report, not production code

App sanity check ❌

Criteria Result Description
App builds and runs No posthog/posthog-php not in composer.json; all use PostHog\PostHog statements will fail
Preserves existing env vars & configs Yes Existing configs and env vars untouched; only additions made
No syntax or type errors Yes All PHP syntax is valid
Correct imports/exports Yes All use statements reference correct namespaces (assuming SDK installed)
Minimal, focused changes Yes Changes are focused on PostHog integration
Pre-existing issues None

Issues

  • PostHog SDK not in composer.json: The posthog/posthog-php package is referenced throughout the codebase but never added to composer.json. Run composer require posthog/posthog-php and commit the updated composer.json and composer.lock. [CRITICAL]
  • Double initialization: PostHog::init() is called in both AppServiceProvider::boot() and PostHogService::__construct(). Remove the init from the service constructor since the service provider already handles it. [MEDIUM]

Other completed criteria

  • Environment variables documented in .env.example with POSTHOG_PROJECT_TOKEN, POSTHOG_HOST, and POSTHOG_DISABLED
  • PostHog config correctly placed in config/services.php using env() helper
  • Existing app functionality (auth, subscriptions, Cashier) preserved

PostHog implementation ⚠️

Criteria Result Description
PostHog SDKs installed No posthog/posthog-php not added to composer.json
PostHog client initialized Yes PostHog::init() called in AppServiceProvider::boot() with api_key and host from config (matches docs pattern)
capture() Yes 14 meaningful capture calls across auth, subscription, profile, and dashboard flows
identify() N/A Server-only app
Error tracking Yes PostHog::captureException() called in bootstrap/app.php exception handler with URL and method context
Reverse proxy N/A Server-only app

Issues

  • SDK package missing from composer.json: Without the dependency declared, composer install won't fetch the SDK and the app will crash. [CRITICAL]
  • Anonymous distinct_id strategy: session()->getId() used for anonymous users in pricing_viewed and password_reset_requested creates ephemeral distinct IDs that fragment analytics data. Consider omitting capture for unauthenticated users or documenting this limitation. [MEDIUM]

Other completed criteria

  • API key loaded from environment variable via config('services.posthog.api_key') — not hardcoded
  • Host correctly configured with default https://us.i.posthog.com
  • PostHogService provides clean abstraction with isEnabled() guard
  • captureException correctly passes authenticated user's distinct ID and request context
  • getPostHogDistinctId() returns database primary key (string cast) — correct distinct ID strategy

PostHog insights and events ✅

Filename PostHog events Description
routes/web.php pricing_viewed Tracks pricing page views for authenticated and anonymous visitors
register.blade.php user_signed_up Tracks new email registrations with signup method
login.blade.php user_logged_in Tracks email/password logins with identify
SocialiteController.php social_login_completed Tracks OAuth logins with provider and new-user flag
forgot-password.blade.php password_reset_requested Tracks password reset requests
VerifyEmailController.php email_verification_completed Tracks email verification with method
update-profile-information-form.blade.php profile_updated Tracks profile changes with field-change flags
update-password-form.blade.php password_updated Tracks password changes
delete-user-form.blade.php account_deleted Tracks account deletions before user is removed
Dashboard.php dashboard_viewed Tracks dashboard loads with subscription state
SubscriptionController.php subscription_checkout_started, subscription_activated, subscription_plan_changed, billing_portal_opened Full subscription lifecycle tracking with plan details and pricing
bootstrap/app.php captureException Captures all Laravel-reported exceptions with URL and method context

Issues

  • No critical or medium issues with event quality.

Other completed criteria

  • Events represent real user actions mapping to product flows (signup → checkout → activation funnel)
  • Events enable product insights: signup funnel, subscription conversion, retention via dashboard views
  • Events include contextual properties (plan details, login method, subscription state, field-change flags)
  • No PII in event properties — email/name set via identify() on person profile only
  • Event names follow consistent snake_case [object]_[verb] convention

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