Raxx · internal docs

internal · gated

ADR 0145 — PostHog Topology, Taxonomy, and Privacy Posture for Raxx

Status: Proposed — pending operator review of the benefit matrix Date: 2026-07-22 UTC Deciders: software-architect (design), operator (review gate before sub-cards are filed) Scope: getraxx (Vite), Antlers/raxx-next (Next.js App Router, CF Pages edge runtime), Raptor (Flask), iOS (Swift), console (out of scope for Phase 1)


Context

Three prior, independent efforts (#491/#482 demo funnel, #219/#2124 getraxx landing, #3899 Antlers session-replay+funnel) already wired partial PostHog instrumentation against no live PostHog project, using two different event-naming conventions, and with one flag (posthog_session_replay) bundling funnel-event capture together with full session replay. No topology, taxonomy, or privacy posture had been decided before code shipped. This ADR records the decisions needed to unify them: full rationale, matrix, and taxonomy live in posthog-raxx-adoption.md.


Decision

Adopt one PostHog project (raxx) in the existing MooseQuest LLC org, with environment and app as event properties rather than per-environment projects. Standardize on flat snake_case, <object>_<verb_past_tense> event names, rejecting the dot-namespaced convention used only in the unmerged #219 branch. Split the posthog_session_replay flag into an events-only flag (posthog_events_enabled, Phase 1) and a retained replay-only flag (posthog_session_replay, Phase 3, gated further on a masking inventory). Billing/trading/auth-adjacent events are server-captured from Raptor (posthog-python); UI-engagement events are client-captured from whichever surface renders them. distinct_id is the internal user UUID post-signup, never email — set via a client-side posthog.identify(userId) call at signup completion (§5 of the design doc), which is what merges the pre-signup anonymous session into that id; Raptor's server-side identify() sets person properties but cannot perform this merge (it never has access to the browser's anonymous distinct_id).


Language choice rationale

Not applicable — PostHog is consumed as hosted SaaS via SDKs (posthog-js, posthog-python, posthog-ios). No new service, process, or daemon is introduced.


Consequences

Positive

Negative / risks

Neutral


Alternatives considered

Alternative A — Separate raxx-prod / raxx-staging projects

Rejected because it doubles API-key rotation and taxonomy upkeep, and breaks the single-distinct_id funnel query for the sake of an isolation guarantee a saved filter already provides.

Alternative B — Keep dot-namespaced (category:action) event names org-wide

Rejected because the majority of already-shipped instrumentation (demo funnel, Antlers funnel, waitlist_signup) already uses flat snake_case; standardizing on the minority convention would mean renaming more code, not less.

Alternative C — Client-capture everything, including billing/trading state changes

Rejected — a client can be ad-blocked, offline, or compromised; billing/trading/auth state changes already have a server-side audited source of truth (audit_log), and PostHog mirroring should read from that source, not duplicate trust in the client.


Security / GDPR checklist


Revisit when