Skip to content

feat(analytics): add amplitude to notifications for emails#1991

Merged
baktun14 merged 8 commits intomainfrom
features/amplitude-notfiication
Oct 3, 2025
Merged

feat(analytics): add amplitude to notifications for emails#1991
baktun14 merged 8 commits intomainfrom
features/amplitude-notfiication

Conversation

@baktun14
Copy link
Contributor

@baktun14 baktun14 commented Oct 2, 2025

Summary by CodeRabbit

  • New Features

    • Added Amplitude analytics for notifications; service reports "email_sent" and "email_failed". Email sender now tracks "email_sent" and logs analytics errors. Deterministic, configurable per-user sampling with stricter validation.
  • Tests

    • New/updated unit tests for sampling, event reporting, email-sender analytics integration, and analytics error handling.
  • Chores

    • Added analytics and hashing dependencies and new environment variables for analytics configuration.

@baktun14 baktun14 requested a review from a team as a code owner October 2, 2025 09:11
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 2, 2025

Walkthrough

Adds Amplitude analytics to notifications: new dependencies, env keys, Amplitude and Hash providers, AnalyticsService with deterministic sampling, EmailSenderService integration and tests, and stricter sampling validation in the API analytics service.

Changes

Cohort / File(s) Summary
Dependencies
apps/notifications/package.json
Adds @amplitude/analytics-node@^1.3.8 and murmurhash@^2.0.1.
Env config
apps/notifications/src/modules/notifications/config/env.config.ts
Extends notifications env schema with AMPLITUDE_API_KEY: string and AMPLITUDE_SAMPLING: number (coerced, optional, default 1).
Module wiring
apps/notifications/src/modules/notifications/notifications.module.ts
Registers AmplitudeProvider, HashProvider, and AnalyticsService in NotificationsModule providers.
Providers
apps/notifications/src/modules/notifications/providers/amplitude.provider.ts, apps/notifications/src/modules/notifications/providers/hash.provider.ts
New AmplitudeProvider factory using notifications.AMPLITUDE_API_KEY (getOrThrow); new HashProvider exposing murmurhash.v3 as HASHER.
Notifications analytics service
apps/notifications/src/modules/notifications/services/analytics/analytics.service.ts
Adds AnalyticsService that deterministically samples users via hasher and AMPLITUDE_SAMPLING, conditionally calls Amplitude for email_sent/email_failed, and logs reported events.
Email sender integration
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts
Injects AnalyticsService and LoggerService; after successful send calls analyticsService.track with email_sent payload and logs tracking errors.
Notifications tests
apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts, apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
Adds unit tests for AnalyticsService sampling and payloads; updates email-sender tests to assert analytics tracking and error handling; test setups include mocked Amplitude/Hasher/AnalyticsService/Logger.
API analytics validation
apps/api/src/core/services/analytics/analytics.service.ts, apps/api/src/core/services/analytics/analytics.service.spec.ts
Adds samplingRate field and validateSamplingRate() (reads/validates AMPLITUDE_SAMPLING ∈ [0,1]); uses validated samplingRate in sampling logic; tests updated to supply samplingRate via setup.
Test env
apps/notifications/env/.env.test
Adds AMPLITUDE_API_KEY variable for test environment.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant ES as EmailSenderService
  participant Novu as Novu API
  participant AS as AnalyticsService
  participant Amp as Amplitude SDK

  ES->>Novu: trigger email send
  alt Success
    Novu-->>ES: success
    ES->>AS: track(userId, "email_sent", props)
    AS->>AS: shouldSampleUser(userId)
    alt Sampled
      AS->>Amp: amplitude.track(event, { user_id, ...props })
      AS-->>ES: tracked
    else Not sampled
      AS-->>ES: skipped
    end
  else Failure
    Novu-->>ES: error
    ES-->>ES: rethrow (no analytics tracking)
  end
Loading
sequenceDiagram
  autonumber
  participant DI as Nest DI
  participant CFG as ConfigService
  participant AmpSDK as Amplitude SDK
  participant Hasher as murmurhash

  DI->>CFG: getOrThrow("notifications.AMPLITUDE_API_KEY")
  CFG-->>DI: API_KEY
  DI->>AmpSDK: init(API_KEY)
  Note right of AmpSDK: AmplitudeProvider created
  DI->>Hasher: provide HASHER = murmurhash.v3
  Note right of Hasher: HashProvider created
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • stalniy

Poem

I nibble bytes and count the hops,
I hash each hare and mark the spots,
Emails flutter, trails of light,
I track a hop — a tiny byte. 🥕🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title precisely indicates that this feature adds Amplitude analytics to email notifications, clearly reflecting the primary change without extraneous details or noise.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch features/amplitude-notfiication

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d5f59c0 and ef30bfb.

📒 Files selected for processing (2)
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts (4 hunks)
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts
🧠 Learnings (2)
📚 Learning: 2025-07-21T08:25:07.474Z
Learnt from: CR
PR: akash-network/console#0
File: .cursor/rules/setup-instead-of-before-each.mdc:0-0
Timestamp: 2025-07-21T08:25:07.474Z
Learning: Applies to **/*.spec.{ts,tsx} : Don't specify return type of `setup` function

Applied to files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
📚 Learning: 2025-07-21T08:25:07.474Z
Learnt from: CR
PR: akash-network/console#0
File: .cursor/rules/setup-instead-of-before-each.mdc:0-0
Timestamp: 2025-07-21T08:25:07.474Z
Learning: Applies to **/*.spec.{ts,tsx} : `setup` function should accept a single parameter with inline type definition

Applied to files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
🧬 Code graph analysis (2)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts (2)
apps/deploy-web/src/services/analytics/analytics.service.ts (1)
  • AnalyticsService (142-271)
apps/notifications/test/mocks/provider.mock.ts (1)
  • MockProvider (4-6)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (3)
apps/api/src/core/services/config/config.service.ts (1)
  • ConfigService (9-22)
apps/deploy-web/src/services/analytics/analytics.service.ts (1)
  • AnalyticsService (142-271)
packages/logging/src/services/logger/logger.service.ts (1)
  • error (107-109)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
🔇 Additional comments (5)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts (3)

21-55: LGTM! Analytics tracking properly tested.

The test correctly verifies that analytics are tracked when an email is sent, including the proper event name and payload structure.


57-81: LGTM! Error handling properly tested.

The test correctly verifies that email sending continues even when analytics tracking fails, and that errors are properly logged. This ensures resilience in the service.


84-104: Verify if setup function needs a configuration parameter.

The coding guidelines state: "setup function should accept a single parameter with inline type definition." However, this setup function accepts no parameters. If no configuration is needed (which appears to be the case here), this may be acceptable. However, consider if future test cases might benefit from configurable setup options.

As per coding guidelines.

apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (2)

20-27: LGTM!

The constructor properly injects the new dependencies (AnalyticsService and LoggerService) and initializes the logger context with the class name, which is a best practice for structured logging.


52-60: AnalyticsService.track is synchronous; existing try-catch correctly handles all errors. No changes required.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (5)
apps/notifications/src/modules/notifications/providers/amplitude.provider.ts (1)

13-17: Consider configuring Amplitude initialization options.

The SDK is initialized without any options. For a server-side analytics service, you may want to configure flush intervals, batch sizes, or retry behavior to optimize performance and reliability.

Apply this diff to add recommended server-side options:

   useFactory: (configService: ConfigService<NotificationsConfig>) => {
     const apiKey = configService.getOrThrow("notifications.AMPLITUDE_API_KEY");
-    amplitude.init(apiKey);
+    amplitude.init(apiKey, {
+      flushIntervalMillis: 10000,
+      flushQueueSize: 100,
+      flushMaxRetries: 3
+    });
     return { track: amplitude.track };
   },

Based on learnings: The modern @amplitude/analytics-node SDK supports configuration options for batching and retry logic, which improve server-side event delivery reliability.

apps/notifications/src/modules/notifications/services/analytics/analytics.service.ts (3)

25-27: Consider adding error handling for Amplitude track failures.

The amplitude.track call can throw errors (e.g., network issues, invalid payload). Currently, these errors would propagate and could disrupt the email sending flow. Consider wrapping the call in a try-catch to log errors without breaking the primary operation.

Apply this diff:

  track(userId: string, eventName: AnalyticsEvent, eventProperties: Record<string, unknown> = {}) {
    if (this.shouldSampleUser(userId)) {
-     this.amplitude.track(eventName, eventProperties, {
-       user_id: userId
-     });
-     this.loggerService.debug({ event: "ANALYTICS_EVENT_REPORTED", userId, eventName });
+     try {
+       this.amplitude.track(eventName, eventProperties, {
+         user_id: userId
+       });
+       this.loggerService.debug({ event: "ANALYTICS_EVENT_REPORTED", userId, eventName });
+     } catch (error) {
+       this.loggerService.error({ event: "ANALYTICS_EVENT_FAILED", userId, eventName, error });
+     }
    }
  }

Based on learnings: The Amplitude Node SDK batches events and flushes asynchronously, so track() itself is typically non-blocking, but defensive error handling ensures analytics failures don't impact core functionality.


32-36: Consider using getOrThrow or providing a default for AMPLITUDE_SAMPLING.

Line 35 uses configService.get(...) which returns undefined if the key is missing. This would result in NaN when multiplied by 100, causing the comparison to always be false and disabling sampling entirely. While the environment config likely defines a default, using getOrThrow or configService.get(...) ?? 1.0 would make the behavior explicit and prevent silent failures.

Apply this diff to use getOrThrow:

-    return percentage < this.configService.get("notifications.AMPLITUDE_SAMPLING") * 100;
+    return percentage < this.configService.getOrThrow("notifications.AMPLITUDE_SAMPLING") * 100;

Or provide an explicit default:

-    return percentage < this.configService.get("notifications.AMPLITUDE_SAMPLING") * 100;
+    return percentage < (this.configService.get("notifications.AMPLITUDE_SAMPLING") ?? 1.0) * 100;

28-28: Consider PII implications of logging userId.

The debug log includes userId, which may be personally identifiable information. While debug logs are typically disabled in production and the userId is already sent to Amplitude, consider whether logging it is necessary or if it should be redacted/hashed for additional privacy protection.

apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts (1)

49-61: Fix the setup helper signature. Our testing guidelines require the setup helper to accept a single parameter with an inline type. Please change this to something like async function setup({ sampling = "1.0" }: { sampling?: string }) { ... } so future overrides remain type-safe and the convention stays consistent.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5ac1d5 and a74d095.

📒 Files selected for processing (9)
  • apps/notifications/package.json (2 hunks)
  • apps/notifications/src/modules/notifications/config/env.config.ts (1 hunks)
  • apps/notifications/src/modules/notifications/notifications.module.ts (1 hunks)
  • apps/notifications/src/modules/notifications/providers/amplitude.provider.ts (1 hunks)
  • apps/notifications/src/modules/notifications/providers/hash.provider.ts (1 hunks)
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts (1 hunks)
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.ts (1 hunks)
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts (4 hunks)
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts
  • apps/notifications/src/modules/notifications/providers/hash.provider.ts
  • apps/notifications/src/modules/notifications/providers/amplitude.provider.ts
  • apps/notifications/src/modules/notifications/config/env.config.ts
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.ts
  • apps/notifications/src/modules/notifications/notifications.module.ts
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts
  • apps/notifications/src/modules/notifications/providers/hash.provider.ts
  • apps/notifications/src/modules/notifications/providers/amplitude.provider.ts
  • apps/notifications/src/modules/notifications/config/env.config.ts
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.ts
  • apps/notifications/src/modules/notifications/notifications.module.ts
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
🧬 Code graph analysis (6)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (3)
apps/api/src/core/services/config/config.service.ts (1)
  • ConfigService (9-22)
apps/notifications/src/lib/types/namespaced-config.type.ts (1)
  • Namespaced (1-3)
apps/deploy-web/src/services/analytics/analytics.service.ts (1)
  • AnalyticsService (142-271)
apps/notifications/src/modules/notifications/providers/amplitude.provider.ts (1)
apps/api/src/core/services/config/config.service.ts (1)
  • ConfigService (9-22)
apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts (5)
apps/notifications/src/modules/notifications/providers/amplitude.provider.ts (1)
  • Amplitude (7-9)
apps/notifications/src/modules/notifications/providers/hash.provider.ts (1)
  • Hasher (4-4)
apps/api/src/core/services/config/config.service.ts (1)
  • ConfigService (9-22)
apps/notifications/src/lib/types/namespaced-config.type.ts (1)
  • Namespaced (1-3)
apps/notifications/src/modules/notifications/config/env.config.ts (1)
  • NotificationEnvConfig (10-10)
apps/notifications/src/modules/notifications/services/analytics/analytics.service.ts (6)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (1)
  • Injectable (17-64)
apps/notifications/src/modules/notifications/providers/amplitude.provider.ts (1)
  • Amplitude (7-9)
apps/notifications/src/modules/notifications/providers/hash.provider.ts (1)
  • Hasher (4-4)
apps/api/src/core/services/config/config.service.ts (1)
  • ConfigService (9-22)
apps/notifications/src/lib/types/namespaced-config.type.ts (1)
  • Namespaced (1-3)
apps/notifications/src/modules/notifications/config/env.config.ts (1)
  • NotificationEnvConfig (10-10)
apps/notifications/src/modules/notifications/notifications.module.ts (4)
apps/notifications/src/modules/notifications/config/env.config.ts (1)
  • schema (3-8)
apps/notifications/src/modules/notifications/providers/amplitude.provider.ts (1)
  • AmplitudeProvider (11-19)
apps/notifications/src/modules/notifications/providers/hash.provider.ts (1)
  • HashProvider (6-9)
apps/deploy-web/src/services/analytics/analytics.service.ts (1)
  • AnalyticsService (142-271)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts (2)
apps/deploy-web/src/services/analytics/analytics.service.ts (1)
  • AnalyticsService (142-271)
apps/notifications/test/mocks/provider.mock.ts (1)
  • MockProvider (4-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (9)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts (4)

20-54: LGTM! Analytics tracking verified on email success.

The test correctly verifies that analyticsService.track is called with the expected event name "email_sent" and payload when an email is sent successfully. The assertions cover all relevant properties: recipient_count, subject, and workflow_id.


56-77: LGTM! Analytics tracking verified on email failure.

The test correctly verifies that analytics tracking occurs even when the email send fails. The error message is properly captured in the event payload, and the test uses rejects.toThrow to verify the error is still propagated.


80-85: Remove the explicit return type from setup.

The coding guidelines specify that the setup function should not have an explicit return type.

As per coding guidelines.

Apply this diff:

-  async function setup(): Promise<{
-    service: EmailSenderService;
-    novu: MockProxy<Novu>;
-    analyticsService: MockProxy<AnalyticsService>;
-    novuWorkflowId: string;
-  }> {
+  async function setup() {

20-77: LGTM! Comprehensive test coverage for analytics integration.

The tests correctly verify that:

  • Analytics tracking occurs on successful email sends with the email_sent event.
  • Analytics tracking occurs on failures with the email_failed event and error details.
  • Both tests properly use the arrange-act-assert pattern and validate the complete payload structure.
apps/notifications/src/modules/notifications/providers/amplitude.provider.ts (3)

7-9: LGTM! Minimal type surface matches actual usage.

The Amplitude type intentionally exposes only the track method, which aligns with how AnalyticsService uses the provider. This restricted interface clarifies the intended API surface while the factory returns the full SDK instance.


11-19: LGTM! Clean provider factory with appropriate error handling.

The provider correctly uses getOrThrow to ensure the API key is present, failing fast at startup if missing. The factory pattern and dependency injection are properly structured.


15-15: Amplitude.init is synchronous; no await needed. init() configures the SDK synchronously and events are queued for async sending, so you can call track immediately.

apps/notifications/src/modules/notifications/services/analytics/analytics.service.ts (2)

12-36: LGTM! Clean service design with correct deterministic sampling.

The service is well-structured with:

  • Proper dependency injection and logger context setup.
  • Type-safe event names via the AnalyticsEvent union type.
  • A correct deterministic sampling algorithm that ensures consistent behavior per user (hash-based modulo 100 distribution).

The sampling logic will correctly sample users based on the configured percentage, with the same user always getting the same sampling decision.


25-27: No changes required for the amplitude.track call signature. The @amplitude/analytics-node SDK supports the track(eventName, eventProperties, options) form used here.

Comment on lines +41 to +42
expect(amplitude.track).toHaveBeenCalledWith("email_failed", { error: "Network timeout" }, { user_id: "user123" });
expect(loggerService.debug).toHaveBeenCalledWith({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Align expectations with real Amplitude Node API. @amplitude/analytics-node exposes track(eventObject); it doesn't accept (eventName, props, options) like the browser SDK. The assertions (and corresponding service implementation) currently expect that signature, so the tests will fail once the correct client is wired. Please update the service/tests to send { event_type, user_id, event_properties } via a client instance returned by init.

🤖 Prompt for AI Agents
In
apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts
around lines 41-42, the test expects amplitude.track to be called with
(eventName, props, options) but @amplitude/analytics-node requires a single
event object; update the test (and the service if necessary) to call
amplitude.track({ event_type: "email_failed", user_id: "user123",
event_properties: { error: "Network timeout" } }) and change the expectation to
toHaveBeenCalledWith that single object returned by the init client instance.

@codecov
Copy link

codecov bot commented Oct 2, 2025

Codecov Report

❌ Patch coverage is 93.10345% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 45.53%. Comparing base (f5ac1d5) to head (ef30bfb).
⚠️ Report is 2 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...i/src/core/services/analytics/analytics.service.ts 84.61% 2 Missing ⚠️
...ifications/services/analytics/analytics.service.ts 92.59% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1991      +/-   ##
==========================================
+ Coverage   45.46%   45.53%   +0.07%     
==========================================
  Files        1005     1008       +3     
  Lines       28506    28560      +54     
  Branches     7457     7474      +17     
==========================================
+ Hits        12961    13006      +45     
+ Misses      15163    14343     -820     
- Partials      382     1211     +829     
Flag Coverage Δ
api 81.53% <84.61%> (-0.07%) ⬇️
deploy-web 23.82% <ø> (ø)
log-collector 75.35% <ø> (ø)
notifications 88.16% <95.55%> (+0.21%) ⬆️
provider-console 81.48% <ø> (ø)
provider-proxy 84.98% <ø> (ø)
Files with missing lines Coverage Δ
...ules/notifications/providers/amplitude.provider.ts 100.00% <100.00%> (ø)
...c/modules/notifications/providers/hash.provider.ts 100.00% <100.00%> (ø)
...ions/services/email-sender/email-sender.service.ts 100.00% <100.00%> (ø)
...i/src/core/services/analytics/analytics.service.ts 93.10% <84.61%> (-6.90%) ⬇️
...ifications/services/analytics/analytics.service.ts 92.59% <92.59%> (ø)

... and 202 files with indirect coverage changes

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/notifications/src/modules/notifications/config/env.config.ts (1)

7-7: Clamp AMPLITUDE_SAMPLING between 0 and 1.

We still accept values outside the [0, 1] range, which breaks sampling semantics. Enforce the bounds when coercing so misconfigured envs can’t silently slip through.

-  AMPLITUDE_SAMPLING: z.number({ coerce: true }).optional().default(1)
+  AMPLITUDE_SAMPLING: z.coerce.number().min(0).max(1).default(1)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a74d095 and 5fb1d5d.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (4)
  • apps/api/src/core/services/analytics/analytics.service.ts (2 hunks)
  • apps/notifications/src/modules/notifications/config/env.config.ts (1 hunks)
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.ts (1 hunks)
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/notifications/src/modules/notifications/config/env.config.ts
  • apps/api/src/core/services/analytics/analytics.service.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/notifications/src/modules/notifications/config/env.config.ts
  • apps/api/src/core/services/analytics/analytics.service.ts
🧬 Code graph analysis (1)
apps/api/src/core/services/analytics/analytics.service.ts (3)
apps/api/src/core/providers/amplitude.provider.ts (2)
  • AMPLITUDE (6-6)
  • Amplitude (16-18)
apps/deploy-web/src/services/analytics/analytics.service.ts (2)
  • Amplitude (138-138)
  • AnalyticsService (142-271)
apps/api/src/core/providers/hash.provider.ts (2)
  • HASHER (4-4)
  • Hasher (8-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts (2)

17-17: Amplitude API signature mismatch (previously flagged).

The test expects amplitude.track(eventName, props, options) but @amplitude/analytics-node requires a single event object: amplitude.track({ event_type, user_id, event_properties }). This issue was already flagged in previous review comments.


46-46: Amplitude API signature mismatch (previously flagged).

The test expects amplitude.track(eventName, props, options) but @amplitude/analytics-node requires a single event object. This issue was already flagged in previous review comments on these lines.

🧹 Nitpick comments (2)
apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts (1)

25-39: Refactor to use setup function with parameters.

This test creates mocks inline instead of using the setup function, which is inconsistent with the other tests. Refactor it to use setup with a parameter to configure the sampling behavior.

Apply this diff to refactor the test:

-  it("should not track events when user is not sampled", async () => {
-    const amplitude = mock<Amplitude>();
-    const hasher = mock<Hasher>();
-    const configService = mock<ConfigService<Namespaced<"notifications", NotificationEnvConfig>>>();
-    const loggerService = mock<LoggerService>();
-
-    jest.spyOn(configService, "getOrThrow").mockReturnValue("0.0");
-    hasher.hash.mockReturnValue(50); // Hash value that would normally be sampled
-
-    const service = new AnalyticsService(amplitude, hasher, configService, loggerService);
+  it("should not track events when user is not sampled", async () => {
+    const { service, amplitude } = await setup({ samplingRate: "0.0" });
 
     service.track("user123", "email_sent", { recipient_count: 1 });
 
     expect(amplitude.track).not.toHaveBeenCalled();
   });

And update the setup function to accept parameters:

-  async function setup() {
+  async function setup(options?: { samplingRate?: string }) {
     const amplitude = mock<Amplitude>();
     const hasher = mock<Hasher>();
     const configService = mock<ConfigService<Namespaced<"notifications", NotificationEnvConfig>>>();
     const loggerService = mock<LoggerService>();
 
-    jest.spyOn(configService, "getOrThrow").mockReturnValue("1.0");
+    jest.spyOn(configService, "getOrThrow").mockReturnValue(options?.samplingRate ?? "1.0");
     hasher.hash.mockReturnValue(50); // Mock hash value that will be sampled
 
     const service = new AnalyticsService(amplitude, hasher, configService, loggerService);
 
     return { service, amplitude, hasher, configService, loggerService };
   }
apps/api/src/core/services/analytics/analytics.service.spec.ts (1)

151-168: Setup function is compliant with coding guidelines.

The function correctly:

  • Accepts a single parameter with inline type definition
  • Has no return type annotation
  • Uses jest-mock-extended for mocking
  • Has no shared state
  • Is positioned at the bottom of the root describe block

However, consider making the config mock more specific to prevent future issues:

Apply this diff to make the config mock more specific:

-    config.get.mockReturnValue(input.samplingRate ?? "1.0");
+    config.get.calledWith("AMPLITUDE_SAMPLING").mockReturnValue(input.samplingRate ?? "1.0");

This ensures the mock only returns the sampling rate when specifically querying "AMPLITUDE_SAMPLING", preventing unexpected behavior if the service calls config.get with other keys in the future.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5fb1d5d and ea483d2.

📒 Files selected for processing (2)
  • apps/api/src/core/services/analytics/analytics.service.spec.ts (6 hunks)
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/api/src/core/services/analytics/analytics.service.spec.ts
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/api/src/core/services/analytics/analytics.service.spec.ts
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/api/src/core/services/analytics/analytics.service.spec.ts
  • apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts
🧬 Code graph analysis (2)
apps/api/src/core/services/analytics/analytics.service.spec.ts (2)
apps/api/src/core/providers/amplitude.provider.ts (1)
  • Amplitude (16-18)
apps/api/src/core/providers/hash.provider.ts (1)
  • Hasher (8-8)
apps/notifications/src/modules/notifications/services/analytics/analytics.service.spec.ts (5)
apps/notifications/src/modules/notifications/providers/amplitude.provider.ts (1)
  • Amplitude (7-9)
apps/notifications/src/modules/notifications/providers/hash.provider.ts (1)
  • Hasher (4-4)
apps/api/src/core/services/config/config.service.ts (1)
  • ConfigService (9-22)
apps/notifications/src/lib/types/namespaced-config.type.ts (1)
  • Namespaced (1-3)
apps/notifications/src/modules/notifications/config/env.config.ts (1)
  • NotificationEnvConfig (10-10)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: validate (apps/stats-web) / validate-unsafe
  • GitHub Check: validate (apps/api) / validate-unsafe
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
🔇 Additional comments (4)
apps/api/src/core/services/analytics/analytics.service.spec.ts (4)

1-8: LGTM! Clean imports with proper type safety.

The imports correctly use jest-mock-extended for mocking and properly import types using the type keyword, which is good for tree-shaking and clarity.


10-17: LGTM! Constructor test is properly structured.

The test correctly verifies that the logger context is set during service initialization.


19-78: LGTM! Track method tests are comprehensive and correct.

All three test cases properly validate:

  1. Event tracking when user is sampled (hash < threshold)
  2. Event skipping when user is not sampled (hash >= threshold)
  3. Default empty object for properties when none provided

The sampling logic is tested correctly with the explicit samplingRate parameter.


80-149: LGTM! Comprehensive coverage of sampling logic edge cases.

The tests thoroughly validate:

  1. Sampling decisions at the threshold boundary
  2. 100% sampling rate (all users included)
  3. 0% sampling rate (all users excluded)
  4. Negative hash value handling

All assertions correctly reflect the expected deterministic sampling behavior based on hash values and thresholds.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/notifications/env/.env.test (1)

10-11: Silence dotenv-linter by fixing order and trailing newline.

dotenv-linter currently warns that the new key is out of order and the file lacks a trailing newline; please reorder the entry and re-add the newline so the check passes cleanly.

 RPC_NODE_ENDPOINT=https://consolerpc.akashnet.net
-API_NODE_ENDPOINT=https://consoleapi.akashnet.net
+AMPLITUDE_API_KEY=AMPLITUDE_API_KEY
+API_NODE_ENDPOINT=https://consoleapi.akashnet.net
 APP_NAME=local
 POSTGRES_BASE_URL=postgres://postgres:password@localhost:5432
 EVENT_BROKER_POSTGRES_URI=postgres://postgres:password@localhost:5432/events
 NOTIFICATIONS_POSTGRES_URL=postgres://postgres:password@localhost:5432/notification_service
 NOVU_SECRET_KEY=some-dummy-string
 NOVU_MAILER_WORKFLOW_ID=generic-v2
 CONSOLE_WEB_URL=console.akash.network
 STD_OUT_LOG_FORMAT=pretty
-AMPLITUDE_API_KEY=AMPLITUDE_API_KEY
+
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ea483d2 and 8fd30c5.

📒 Files selected for processing (1)
  • apps/notifications/env/.env.test (1 hunks)
🧰 Additional context used
🪛 dotenv-linter (3.3.0)
apps/notifications/env/.env.test

[warning] 11-11: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 11-11: [UnorderedKey] The AMPLITUDE_API_KEY key should go before the API_NODE_ENDPOINT key

(UnorderedKey)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build

stalniy
stalniy previously approved these changes Oct 3, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8fd30c5 and d10d6d3.

📒 Files selected for processing (2)
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts (4 hunks)
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/no-jest-mock.mdc)

Don't use jest.mock() to mock dependencies in test files. Instead, use jest-mock-extended to create mocks and pass mocks as dependencies to the service under test.

**/*.spec.{ts,tsx}: Use setup function instead of beforeEach in test files
setup function must be at the bottom of the root describe block in test files
setup function creates an object under test and returns it
setup function should accept a single parameter with inline type definition
Don't use shared state in setup function
Don't specify return type of setup function

Files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
🧠 Learnings (2)
📚 Learning: 2025-07-21T08:25:07.474Z
Learnt from: CR
PR: akash-network/console#0
File: .cursor/rules/setup-instead-of-before-each.mdc:0-0
Timestamp: 2025-07-21T08:25:07.474Z
Learning: Applies to **/*.spec.{ts,tsx} : Don't specify return type of `setup` function

Applied to files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
📚 Learning: 2025-07-21T08:25:07.474Z
Learnt from: CR
PR: akash-network/console#0
File: .cursor/rules/setup-instead-of-before-each.mdc:0-0
Timestamp: 2025-07-21T08:25:07.474Z
Learning: Applies to **/*.spec.{ts,tsx} : `setup` function should accept a single parameter with inline type definition

Applied to files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
🧬 Code graph analysis (2)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (3)
apps/api/src/core/services/config/config.service.ts (1)
  • ConfigService (9-22)
apps/notifications/src/lib/types/namespaced-config.type.ts (1)
  • Namespaced (1-3)
apps/deploy-web/src/services/analytics/analytics.service.ts (1)
  • AnalyticsService (142-271)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts (2)
apps/deploy-web/src/services/analytics/analytics.service.ts (1)
  • AnalyticsService (142-271)
apps/notifications/test/mocks/provider.mock.ts (1)
  • MockProvider (4-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: provider-proxy-ci
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
🔇 Additional comments (6)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (2)

8-8: LGTM! Standard dependency injection.

The import and injection of AnalyticsService follows the established NestJS pattern consistently with other dependencies.

Also applies to: 22-22


21-21: LGTM! Improved type safety.

Adding the explicit type parameter to ConfigService provides compile-time safety for configuration access and aligns with the established pattern.

apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts (4)

8-8: LGTM! Standard import.

The import of AnalyticsService for testing purposes is correct.


20-21: LGTM! Clear test intent.

The test name accurately reflects the behavior being verified, and the destructuring pattern is clean.


49-53: LGTM! Comprehensive assertion.

The test thoroughly verifies that analytics tracking is called with the correct userId, event name, and all expected properties.


57-57: LGTM! Adheres to coding guidelines.

The setup function correctly:

  • Omits the explicit return type (as per coding guidelines)
  • Registers AnalyticsService as a mocked provider
  • Returns the mocked analyticsService for test assertions

As per coding guidelines and learnings.

Also applies to: 59-59, 73-73

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d10d6d3 and c13bb41.

📒 Files selected for processing (2)
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts (4 hunks)
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.spec.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts
🧬 Code graph analysis (1)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (4)
apps/api/src/core/services/config/config.service.ts (1)
  • ConfigService (9-22)
apps/notifications/src/lib/types/namespaced-config.type.ts (1)
  • Namespaced (1-3)
apps/deploy-web/src/services/analytics/analytics.service.ts (1)
  • AnalyticsService (142-271)
packages/logging/src/services/logger/logger.service.ts (1)
  • error (107-109)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
🔇 Additional comments (2)
apps/notifications/src/modules/notifications/services/email-sender/email-sender.service.ts (2)

6-6: LGTM!

The imports for LoggerService and AnalyticsService are correctly added and follow the project's import conventions.

Also applies to: 9-9


20-27: LGTM!

The constructor correctly injects AnalyticsService and LoggerService following NestJS patterns, and properly initializes the logger context.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
apps/api/src/core/services/analytics/analytics.service.ts (1)

40-53: Restore default sampling rate when unset.

As flagged in a previous review, validateSamplingRate() now throws when AMPLITUDE_SAMPLING is missing, whereas the previous logic defaulted to 1. Any environment (tests, dev, CI) that hasn't set this variable will crash during DI resolution.

Apply this diff to default to 1 when undefined while still validating range:

  private validateSamplingRate(): number {
    const rawValue = this.coreConfigService.get("AMPLITUDE_SAMPLING");
+
+    if (rawValue === undefined) {
+      return 1;
+    }
+
    const samplingRate = Number(rawValue);

    if (!Number.isFinite(samplingRate)) {
      throw new Error(`Invalid AMPLITUDE_SAMPLING value: "${rawValue}". Must be a finite number.`);
    }

    if (samplingRate < 0 || samplingRate > 1) {
      throw new Error(`Invalid AMPLITUDE_SAMPLING value: ${samplingRate}. Must be between 0 and 1 (inclusive).`);
    }

    return samplingRate;
  }
🧹 Nitpick comments (1)
apps/api/src/core/services/analytics/analytics.service.ts (1)

24-32: Remove redundant cast.

The eventProperties parameter is already typed as Record<string, unknown>, making the cast on line 26 redundant.

Apply this diff to remove the unnecessary cast:

  track(userId: string, eventName: AnalyticsEvent, eventProperties: Record<string, unknown> = {}) {
    if (this.shouldSampleUser(userId)) {
-      const amplitudeProperties = eventProperties as Record<string, unknown>;
-      this.amplitude.track(eventName, amplitudeProperties, {
+      this.amplitude.track(eventName, eventProperties, {
        user_id: userId
      });
      this.loggerService.debug({ event: "ANALYTICS_EVENT_REPORTED", userId, eventName });
    }
  }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c13bb41 and d5f59c0.

📒 Files selected for processing (1)
  • apps/api/src/core/services/analytics/analytics.service.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/api/src/core/services/analytics/analytics.service.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/api/src/core/services/analytics/analytics.service.ts
🧬 Code graph analysis (1)
apps/api/src/core/services/analytics/analytics.service.ts (3)
apps/api/src/core/providers/amplitude.provider.ts (2)
  • AMPLITUDE (6-6)
  • Amplitude (16-18)
apps/deploy-web/src/services/analytics/analytics.service.ts (1)
  • Amplitude (138-138)
apps/api/src/core/providers/hash.provider.ts (2)
  • HASHER (4-4)
  • Hasher (8-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: test-build
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build
🔇 Additional comments (2)
apps/api/src/core/services/analytics/analytics.service.ts (2)

12-12: LGTM!

The samplingRate field is properly declared as private readonly and will be initialized in the constructor.


21-21: LGTM!

The samplingRate is correctly initialized during construction. Note that if validateSamplingRate() throws, DI resolution will fail (see comments on the validation method below).

@baktun14 baktun14 merged commit 6dd78ab into main Oct 3, 2025
66 of 68 checks passed
@baktun14 baktun14 deleted the features/amplitude-notfiication branch October 3, 2025 08:42
ygrishajev pushed a commit that referenced this pull request Oct 6, 2025
* feat(analytics): add amplitude to notifications for emails

* fix(notifications): pr fixes

* fix: analytics tests

* fix: add test amplitude key

* fix(analytics): remove fail send amplitude

* fix(analytics): don't fail on analytics track

* fix: don't throw when undefined

* fix: logging
ygrishajev pushed a commit that referenced this pull request Oct 6, 2025
* feat(analytics): add amplitude to notifications for emails

* fix(notifications): pr fixes

* fix: analytics tests

* fix: add test amplitude key

* fix(analytics): remove fail send amplitude

* fix(analytics): don't fail on analytics track

* fix: don't throw when undefined

* fix: logging
stalniy pushed a commit that referenced this pull request Nov 20, 2025
* feat(analytics): add amplitude to notifications for emails

* fix(notifications): pr fixes

* fix: analytics tests

* fix: add test amplitude key

* fix(analytics): remove fail send amplitude

* fix(analytics): don't fail on analytics track

* fix: don't throw when undefined

* fix: logging
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments