feat(flags): server-side feature flags + upstream kill switches + live backfill config

Add server-side PostHog feature-flag evaluation to the API and wire three
high-leverage uses. The flags live in PostHog (project 127747), dormant and
fail-open, so this commit is a no-op until POSTHOG_PERSONAL_API_KEY is set and
a switch is flipped.

Phase 1 - upstream kill switches:
  PostHogService gains local flag evaluation (onlyEvaluateLocally +
  sendFeatureFlagEvents:false -> zero decode latency, no VIN leak) and
  isSourceLive(). Guards at each source's decode entry (parts-catalogs, emex,
  pl24 whole-source + per-brand via LEGACY_ARCH_SOURCE_TAG) let a flailing
  upstream be disabled from the PostHog UI in ~5s instead of a
  code-fix -> dev -> prod redeploy. Fail-open: any unresolved flag keeps the
  source live, so a PostHog outage can never black out decoding.

Phase 2 - guarded rollout primitive:
  isEnabled()/variant() with VIN bucketing, ready to ramp a new decode/parser
  path 0->100% behind a decode-*-v2 flag (recipe in feature-flags-strategy.md).

Phase 4 - remote-config ops tuning:
  prefetch-worker reads cfg-backfill-tuning to retune backfill
  batchSize/maxBacklog/businessHoursOnly live; malformed/missing -> the
  compiled-in constants.

POSTHOG_PERSONAL_API_KEY wired into the api + worker compose blocks (empty ->
flags inert, no added latency). Tests updated for the new constructor params.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 00:21:52 +03:00
parent 6daf59fe8a
commit ed45021d71
9 changed files with 187 additions and 12 deletions

View File

@@ -98,6 +98,11 @@ export const envSchema = z.object({
// PostHog — product analytics (server-side)
POSTHOG_API_KEY: z.string().optional(),
POSTHOG_HOST: z.string().url().default("https://t.sase.tr"),
// Personal API key (or feature-flags secure key) → enables LOCAL server-side
// feature-flag evaluation: source kill switches, guarded decode rollout, and
// remote-config ops tuning. Without it those flags fail open (no effect, no
// added latency). Keep secret — never expose to the browser.
POSTHOG_PERSONAL_API_KEY: z.string().optional(),
// Sentry — error tracking
SENTRY_DSN: z.string().url().optional(),