feature: route LicenseService heartbeat through TelemetryPort adapter#89
Closed
feature: route LicenseService heartbeat through TelemetryPort adapter#89
Conversation
…r, and factory Introduce provider-agnostic telemetry pattern matching the existing StoragePort/StorageClientFactory architecture. UsageTelemetryService now delegates to an injected TELEMETRY_CLIENT token instead of owning HTTP logic directly. Factory reads config from NestJS ConfigService and returns NoopAdapter when telemetry is disabled or misconfigured. Closes #71
- Guard sendEvent against empty instanceId (no licenseService case) - Fix payload spread order: base properties override caller payload - Use NestJS Logger instead of console.warn in factory and module - Add PostHog stub warning when API key is set but adapter not implemented - Catch shutdown errors in onModuleDestroy (non-fatal teardown) - Handle both boolean and string 'false' for BETTERDB_TELEMETRY - Warn and fall back to noop when ENTITLEMENT_URL path is invalid - Add factory tests for http, posthog, unknown provider, and URL fallback - Restructure integration tests: guard behavior + identity lifecycle
feature: implement PosthogTelemetryClientAdapter with posthog-node Thin wrapper around posthog-node: capture(), identify(), and shutdown() delegate directly to the PostHog client. Remove stub warning from factory since adapter is now real. Closes #73
…iguration Returns instanceId, telemetryEnabled, provider, and optional posthog fields. Frontend uses this at runtime to initialize the correct telemetry client without build-time env vars. Closes #74
… refactor (#85) * feature: frontend TelemetryConfigProvider, ApiTelemetryClient, and hook refactor Add TelemetryClient interface, NoopTelemetryClient, ApiTelemetryClient. TelemetryConfigProvider fetches GET /telemetry/config on mount, selects the correct client, and exposes it via useTelemetry() context hook. Falls back to ApiTelemetryClient on config fetch failure. Refactor useNavigationTracker and useIdleTracker to use useTelemetry() instead of direct fetchApi calls. useConnection telemetry left as-is since it creates context at a level above the provider. Closes #75 * fix: remove nonexistent 'api' provider case, use 'http' consistently * chore: move useTelemetry hook to hooks/ directory * chore: replace TelemetryConfigProvider with singleton useTelemetry hook Remove the context provider — config loading now lives in useTelemetry hook with a module-level singleton. Config is fetched once, cached, and shared across all consumers. Hook returns { client, ready }. No provider wrapping needed in App. * chore: simplify useTelemetry to async function with module-level promise * feature: block app render until telemetry client is ready in ServerStartupGuard * chore: use TanStack Query for telemetry config fetching in useTelemetry * chore: use 30min stale time and default retry for telemetry config query
* feature: frontend PosthogTelemetryClient with posthog-js Thin wrapper around posthog-js: capture() maps page_view to native $pageview, identify() and shutdown() delegate directly. Wired into useTelemetry hook — activated when backend returns provider=posthog and VITE_POSTHOG_API_KEY is set at build time. Falls back to ApiTelemetryClient when key is missing. Closes #76 * chore: add telemetry env vars to .env.example * chore: add frontend telemetry env vars to .env.example * fix: set Vite envDir to monorepo root so .env vars are loaded * refactor: update PostHog client to use instance-based API, adjust env vars and tests Switch from the global `posthog` instance to an instance-based approach with `PostHog`. Updated env vars for clarity (`VITE_POSTHOG_*` to `VITE_PUBLIC_POSTHOG_*`). Refactored `useTelemetry` to manage lifecycle via `useEffect` and updated tests to mock the new client structure. * fix: store posthog.init() instance, use || for empty string host fallback - Use returned PostHog instance from init() instead of global - Use || instead of ?? so empty string host falls back to default - Remove debug console.log
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
TELEMETRY_CLIENTintoLicenseServiceas@Optional()and delegatetelemetry_pingheartbeat events through theTelemetryPortadapter viacapture()instead of direct HTTPlatestVersion/releaseUrl) continues to work via periodicvalidateLicense()calls to the entitlement URLsendStartupError()remains unchanged — direct HTTP, bypasses telemetry opt-outTELEMETRY_CLIENTtoken fromTelemetryModuleso other modules can inject itTest plan
capture()BETTERDB_TELEMETRY=false@Optional())validateLicense()pnpm buildpassesCloses #79
Note
Medium Risk
Introduces new telemetry providers (PostHog/HTTP/noop) across API and web and reroutes license heartbeat and frontend event tracking through these clients, which could affect outbound telemetry behavior and startup gating if misconfigured. Risk is mitigated by opt-out handling, noop fallbacks, and added unit/integration tests.
Overview
Adds a pluggable telemetry layer end-to-end. The API now defines a
TelemetryPort, providesnoop/http(stub)/posthogadapters plus aTelemetryClientFactory, exposesGET /telemetry/config, and injects aTELEMETRY_CLIENTintoTelemetryModulewith graceful shutdown.Reworks telemetry emission to go through the injected client:
UsageTelemetryServiceswitches from direct HTTPfetchtotelemetryClient.capture()/identify(), andLicenseServiceroutes its periodictelemetry_pingheartbeat via the optionalTELEMETRY_CLIENTwhile keeping version checks via periodicvalidateLicense().On the web app, introduces
useTelemetryand telemetry clients (ApiTelemetryClientposting to/telemetry/event, andPosthogTelemetryClientviaposthog-js), updates idle/navigation tracking to callclient.capture(), and blocksServerStartupGuarduntil telemetry config fetch resolves. Environment/config updates add telemetry-related vars and validation, and extensive new tests cover provider selection, config endpoint behavior, and adapter delegation.Written by Cursor Bugbot for commit 893ab63. This will update automatically on new commits. Configure here.