feat(flags): decouple analytics capture from flag evaluation (POSTHOG_CAPTURE_ENABLED)
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
So a non-prod env can hold the (public) project key and evaluate flags - kill switches, rollout - WITHOUT shipping analytics events to the shared prod PostHog project. The posthog-node client (which powers both capture and local flag eval) now initializes whenever the project key is present; capture() is gated on POSTHOG_CAPTURE_ENABLED (default on; set "false" on dev). Wired into the api + worker compose blocks. This lets dev.sase.tr exercise the kill switches end-to-end while keeping the prod analytics project clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,18 +6,26 @@ import type { PostHog as PostHogClient } from "posthog-node";
|
||||
export class PostHogService implements OnModuleDestroy {
|
||||
private readonly logger = new Logger(PostHogService.name);
|
||||
private client: PostHogClient | null = null;
|
||||
private enabled = false;
|
||||
/** Analytics-capture gate — independent of flag eval so a non-prod env can
|
||||
* evaluate flags without emitting events to the shared prod project. */
|
||||
private captureEnabled = false;
|
||||
/** True once a personal API key is configured → local flag evaluation works. */
|
||||
private flagsEnabled = false;
|
||||
|
||||
constructor(private configService: ConfigService) {
|
||||
const apiKey = this.configService.get<string>("POSTHOG_API_KEY");
|
||||
// Capture is gated SEPARATELY from flag evaluation: a non-prod env can set the
|
||||
// project key to evaluate flags (kill switches, rollout) while keeping capture
|
||||
// off, so it never ships analytics to the shared prod project. Default on.
|
||||
this.captureEnabled = this.configService.get<string>("POSTHOG_CAPTURE_ENABLED") !== "false";
|
||||
if (apiKey) {
|
||||
this.enabled = true;
|
||||
// Lazily import posthog-node to avoid requiring it when not configured
|
||||
// The client powers BOTH capture and local feature-flag evaluation.
|
||||
// Lazily import posthog-node to avoid requiring it when not configured.
|
||||
this.initClient(apiKey);
|
||||
} else {
|
||||
this.logger.warn("PostHog API key not configured — server-side analytics disabled");
|
||||
this.logger.warn(
|
||||
"PostHog project key not configured — server-side analytics & flags disabled",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +58,7 @@ export class PostHogService implements OnModuleDestroy {
|
||||
);
|
||||
} catch (err) {
|
||||
this.logger.error("Failed to initialize PostHog client", (err as Error).stack);
|
||||
this.enabled = false;
|
||||
this.client = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +77,7 @@ export class PostHogService implements OnModuleDestroy {
|
||||
* Uses distinctId from frontend identity when provided; otherwise uses "server".
|
||||
*/
|
||||
capture(event: string, properties?: Record<string, unknown>, distinctId = "server"): void {
|
||||
if (!this.enabled || !this.client) return;
|
||||
if (!this.captureEnabled || !this.client) return;
|
||||
|
||||
try {
|
||||
this.client.capture({ distinctId, event, properties });
|
||||
|
||||
Reference in New Issue
Block a user