feat(billing): emit subscription_changed analytics on plan change (guarded by AnalyticsService.isConfigured)#3769
Conversation
- Add AnalyticsService.isConfigured() to lib/services/analytics.js - Guard analytics emit with isConfigured() — no-op on downstreams without PostHog; non-fatal try/catch protects webhook processing - New unit test: 5 cases (plan change, isDowngrade, not-configured no-op, same-plan no-emit, stale-event no-emit) Restores trawl observability lost in /update-stack #1316. Promoted to devkit: AnalyticsService is a devkit-level abstraction. Cross-ref: trawl#1315, infra plan 2026-06-01-trawl-promote-up-followups
|
Warning Review limit reached
More reviews will be available in 56 minutes and 12 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #3769 +/- ##
===========================================
+ Coverage 59.43% 90.11% +30.67%
===========================================
Files 151 151
Lines 4970 4976 +6
Branches 1577 1579 +2
===========================================
+ Hits 2954 4484 +1530
+ Misses 1491 387 -1104
+ Partials 525 105 -420
Flags with carried forward coverage won't be shown. Click here to find out more. Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR extends the devkit analytics abstraction to support a cheap “configured?” pre-check, and uses it in the billing Stripe webhook to emit a subscription_changed PostHog event when a subscription’s plan changes. It also adds a dedicated unit test suite to validate the analytics emit behavior around plan changes.
Changes:
- Add
AnalyticsService.isConfigured()(PostHog client initialised check) to allow callers to skip payload construction when analytics is disabled. - Emit
subscription_changedanalytics fromhandleSubscriptionUpdatedwhenprevious_attributes.itemsindicates a plan change (includingpreviousPlan,newPlan,isDowngrade). - Add unit tests covering capture/no-op scenarios and downgrade detection.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
lib/services/analytics.js |
Adds isConfigured() helper and exports it on AnalyticsService. |
modules/billing/services/billing.webhook.service.js |
Emits subscription_changed analytics event on plan change (guarded by isConfigured()). |
modules/billing/tests/billing.webhook.subscription-changed-analytics.unit.tests.js |
Adds new unit test suite for the plan-change analytics emit behavior. |
Summary
AnalyticsService.isConfigured()tolib/services/analytics.js— returnsclient !== null; cheap pre-check for callers that want to skip payload construction when PostHog is not active.handleSubscriptionUpdated(billing.webhook.service.js): emitsubscription_changedanalytics event afterplan.changedfires, carryingpreviousPlan/newPlan/isDowngrade. Guarded byisConfigured()— downstreams without PostHog get a clean no-op. Non-fatal try/catch ensures analytics never disrupts webhook processing.Why devkit-level
AnalyticsServiceis a devkit-level abstraction (Node #3640/#3653 PostHog integration). Thesubscription_changedemit is generic — any downstream with PostHog configured gets Stripe plan-change visibility automatically after/update-stack. TheisConfigured()guard makes it safe for downstreams without PostHog.Why now
This restores trawl observability that was correctly dropped by
/update-stack #1316(devkit shouldn't carry trawl-specific code), now promoted to devkit so every downstream benefits.Safety
isConfigured()guard: capture is skipped entirely when PostHog client is not initialised.billingEvents.emit('plan.changed', ...)— no change to existing plan-change flow.Cross-ref
2026-06-01-trawl-promote-up-followups.mdTask 5Test plan
NODE_ENV=test npm run test:unit -- modules/billing/tests/billing.webhook.subscription-changed-analytics→ 5/5 passNODE_ENV=test npm run test:unit -- modules/billing/tests/billing.webhook→ full webhook suite green