feat(analytics): add request-aware feature flag helpers (#3487)#3491
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (3)
WalkthroughAdds request-scoped feature-flag helper functions to the analytics service that automatically derive the PostHog Changes
Sequence DiagramsequenceDiagram
participant Handler as Route Handler
participant Analytics as Analytics Service
participant PostHog as PostHog API
Handler->>Analytics: getFeatureFlagForRequest(flag, req, options)
Analytics->>Analytics: resolveDistinctId(req)
Note over Analytics: req.user?.id → req.sessionID → 'anonymous'
Analytics->>PostHog: getFeatureFlag(flag, distinctId, options)
PostHog-->>Analytics: flag value
Analytics-->>Handler: flag value
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
✨ Finishing Touches📝 Generate docstrings
🧪 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✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3491 +/- ##
==========================================
+ Coverage 85.85% 85.99% +0.14%
==========================================
Files 115 116 +1
Lines 2919 2957 +38
Branches 809 829 +20
==========================================
+ Hits 2506 2543 +37
- Misses 327 328 +1
Partials 86 86 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds request-aware wrappers to the analytics service so Express routes can evaluate PostHog feature flags without manually deriving a distinctId from req (while keeping the existing request-agnostic APIs for jobs/cron).
Changes:
- Added
getFeatureFlagForRequest()/isFeatureEnabledForRequest()plus aresolveDistinctId(req)helper inlib/services/analytics.js. - Added unit tests covering authenticated, session-only, and defensive/no-request cases.
- Documented the optional downstream migration in
MIGRATIONS.md.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| lib/services/analytics.js | Adds request-aware feature-flag helpers that derive distinctId from an Express request. |
| lib/services/tests/analytics.forRequest.unit.tests.js | New unit test suite for the request-aware helpers and edge cases. |
| MIGRATIONS.md | Adds an upgrade note describing the new optional helpers and recommended usage. |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Pull Request Overview
The implementation of the request-aware feature flag helpers follows the intended logic for fallback resolution, but the PR lacks the necessary unit tests to verify these new code paths. Codacy reports indicate that coverage requirements are missing, and no specific test scenarios were identified in the PR. While the structural quality is up to standards, the logic for distinctId coercion and fallback (authenticated user -> session -> anonymous) remains unverified through automation. These tests must be added to prevent regression in user tracking.
About this PR
- The code changes were not fully accessible during the intent verification phase. Please ensure that the actual implementation of the fallback chain (req.user.id -> req.sessionID -> 'anonymous') exactly matches the specification, as it could not be cross-referenced with the source code.
- Jira ticket metadata fields (Key, Title, Description) are currently empty. Please update the PR or the linked ticket to ensure proper traceability.
Test suggestions
- Resolution of distinctId from authenticated user (req.user.id)
- Resolution of distinctId from anonymous user session (req.sessionID)
- Fallback to 'anonymous' when req is null or undefined
- Coercion of numeric user.id to string for PostHog compatibility
- Verification that options are correctly passed to the underlying analytics methods
Prompt proposal for missing tests
Consider implementing these tests if applicable:
1. Resolution of distinctId from authenticated user (req.user.id)
2. Resolution of distinctId from anonymous user session (req.sessionID)
3. Fallback to 'anonymous' when req is null or undefined
4. Coercion of numeric user.id to string for PostHog compatibility
5. Verification that options are correctly passed to the underlying analytics methods
🗒️ Improve review quality by adding custom instructions
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| ErrorProne | 3 high |
🟢 Metrics 29 complexity · 5 duplication
Metric Results Complexity 29 Duplication 5
AI Reviewer: first review requested successfully. AI can make mistakes. Always validate suggestions.
TIP This summary will be updated as you push new changes. Give us feedback
Routes today repeat the same distinctId plumbing for every flag call:
const id = req.user?.id ?? req.sessionID ?? 'anonymous';
await analytics.getFeatureFlag('checkout-v2', id);
This is verbose and the anonymous fallback is easy to forget (flag
evaluated without a user silently returns the default value).
Add two sugar helpers on AnalyticsService that extract the distinctId
from an Express request:
analytics.getFeatureFlagForRequest(flag, req, options)
analytics.isFeatureEnabledForRequest(flag, req, options)
Resolution chain: req.user?.id → req.sessionID → 'anonymous'.
Defensive edge: req == null also resolves to 'anonymous' so the
helper can be called without a pre-check.
Existing getFeatureFlag / isFeatureEnabled remain public — cron,
worker, and scheduled-job callers have no req and keep passing the
identifier explicitly. Non-breaking for downstream.
Tests: 11 unit tests cover the three canonical cases (authenticated
user, session-only, no req), plus defensive edges (null req, non-id
user object, numeric user.id coercion, no-PostHog passthrough).
MIGRATIONS.md: entry documents the new helpers and opt-in migration.
Closes #3487
CodeRabbit/Copilot feedback: truthy checks (`if (req.user?.id)`) would coerce `0` or empty-string identifiers to `'anonymous'`. Switch to `!= null` so any defined id/sessionID is preserved and stringified. Added 2 tests (`id: 0`, empty sessionID) — suite now 13 tests.
ae288b4 to
753d142
Compare
Summary
analytics.getFeatureFlagForRequest(flag, req, options)andanalytics.isFeatureEnabledForRequest(flag, req, options)— sugar wrappers that resolve the PostHogdistinctIdfrom an Express request.req.user?.id→req.sessionID→'anonymous'.req == nullalso resolves to'anonymous'so the helper is safe to call defensively.getFeatureFlag/isFeatureEnabledstay public for cron / worker / job callers without areq. Fully non-breaking.Why
Every route was repeating:
Verbose, and the anonymous fallback is easy to forget — a missed fallback silently evaluates the flag with no user, returning the default.
Usage
Test plan
npm run lint— cleannpm run test:unit— 44 suites / 519 tests passing (508 existing + 11 new)lib/services/tests/analytics.forRequest.unit.tests.jscovers:.id(falls back to sessionID)user.idcoerced to stringMigration
MIGRATIONS.md entry added. Action for downstream: optional, pull via
/update-stack; existing route code keeps working.Coordination
#3486(observability fan-out, open in another agent) also modifieslib/services/analytics.js(addscaptureException). Overlap is at the default-export block — expected small merge conflict handled via rebase at merge time.Closes #3487
Summary by CodeRabbit
Documentation
Tests