How to Add an App Event¶
Checklist for adding a new event to the app_events product-analytics stream.
Background and PII rules: App Events Taxonomy.
1. Name the event¶
snake_case, <domain>_<action> (past tense): judgment_viewed,
collection_created. Decide who may emit it:
- Client-emittable — normal product interaction from the browser.
- Server-only — security-relevant (auth-like); must originate from a DB
trigger or a server route, never from
track().
2. Backend allowlist¶
Add the name to EVENT_ALLOWLIST in backend/app/services/app_events.py.
If it is server-only and emitted by a DB trigger, also add it to
DB_TRIGGER_ONLY_EVENTS (that automatically removes it from
API_EVENT_ALLOWLIST).
3. Frontend type (client-emittable events only)¶
Add the name to the ClientEventName union in
frontend/lib/analytics/track.ts. Server-only events are deliberately
excluded from this union — the compiler then blocks track('auth_...').
4. Instrument¶
- Component code:
const trackEvent = useTrackEvent()fromfrontend/hooks/useTrackEvent.ts(keeps locale in sync), thentrackEvent('my_event', { ... }). - Non-React modules (
lib/api/*etc.): importtrackfrom@/lib/analytics/trackdirectly. - Backend code paths:
from app.services.app_events import emit_app_eventand call it fire-and-forget (it never raises).
Properties rules:
- No PII — no emails, tokens, or raw query text (
queryis stripped client-side; usequery_length). See the taxonomy doc for the denylist. - Keep them small (8 KB serialized cap) and flat.
5. Tests¶
- Backend: extend
backend/tests/app/test_app_events.pyif the event has special handling (e.g., a new server-only rule). - Frontend: extend
frontend/__tests__/lib/analytics/track.test.ts(wrapper behaviour) orfrontend/__tests__/api/events-route.test.ts(proxy rules) only when the rules change — plain new event names need no new tests.
6. Document¶
Add the event to the table in
docs/explanation/event-taxonomy.md with: emitter (file path), properties,
and whether it is server-authoritative.
7. Verify¶
Run the affected surface in the dev stack and confirm the row lands: