Status: Accepted Date: 2026-02-16 Authors: OSHUN Platform Engineering, OSHUN Data/Analytics Engineering Reviewers: Domain Leads (Tara, Veritas, Nyx, Arete), OSHUN Product Supersedes: N/A Superseded by: N/A
Context and Problem Statement#
OSHUN needs one analytics language across:
- mobile shell (iOS/Android)
- website/PWA shell
- domain adapters (Tara, Veritas, Nyx, Arete)
Current repo patterns are inconsistent:
- OSHUN metrics draft defines shell KPI events as
oshun.*names. - Veritas web behavior tracking uses snake_case event names (
article_view,article_complete,search_query, etc.). - Shared monitoring infra accepts generic
eventType: stringwith no enforced naming taxonomy. - Domain contracts in
libs/contracts/src/events/*already use dot-delimited<domain>.<entity>.<action>naming.
Without a single taxonomy, we get fragmented dashboards, weak KPI comparability across surfaces, and expensive data normalization work.
Decision Drivers#
- Comparability of product metrics across iOS, Android, web, and PWA.
- Cross-domain consistency for Tara, Veritas, Nyx, and Arete reporting.
- Governance with versioned event contracts and validation.
- Implementation pragmatism by reusing existing event styles where possible.
- Privacy/compliance through explicit consent and PII controls.
- Observability with low-cardinality, query-friendly event names.
Considered Options#
Option 1: Keep Domain-Specific Naming, Normalize in Warehouse#
Description: each domain keeps current names; BI layer remaps later.
Pros:
- ✅ Minimal short-term engineering work in apps
- ✅ High domain autonomy
Cons:
- ❌ Expensive and brittle downstream mapping
- ❌ Slower KPI iteration and conflicting metric definitions
- ❌ Harder enforcement of quality and consent rules
Option 2: One Flat Global Event List#
Description: enforce one long list of event names with no namespace layering.
Pros:
- ✅ Simple initial schema
- ✅ Easy to start tracking quickly
Cons:
- ❌ Name collisions over time
- ❌ Poor ownership boundaries by shell/domain
- ❌ Hard to evolve and reason about event families
Option 3: Canonical Dot-Delimited Taxonomy with Namespaces (Chosen)#
Description: enforce <namespace>.<entity>.<action> canonical naming and a
standard envelope; allow adapter-level mapping from legacy names.
Pros:
- ✅ Aligns with existing domain contract style (
veritas.article.published) - ✅ Clear ownership boundaries (
oshun,tara,veritas,nyx,arete) - ✅ Query-friendly and scalable naming model
- ✅ Supports gradual migration from existing snake_case trackers
Cons:
- ❌ Requires migration/adaptation for existing behavior trackers
- ❌ Requires governance and linting discipline
Decision Outcome#
Chosen option: Option 3 - canonical dot-delimited taxonomy.
Canonical Event Name Contract (Normative)#
Event names MUST use:
- format:
<namespace>.<entity>.<action> - lowercase ascii only
- dot-delimited segments
- snake_case words within each segment if needed
- past-tense or completed-action verb in
actionwhere applicable
Examples:
oshun.app.openedoshun.domain.openedoshun.search.executedveritas.article.viewedtara.session.completedarete.checkin.completed
Disallowed examples:
AppOpened(camelCase)article_view(missing namespace/entity separation)oshun.article(no action)oshun..opened(empty segment)
Namespace Ownership#
oshun.*: shell-level and cross-domain normalized KPI events.tara.*,veritas.*,nyx.*,arete.*: domain-native product events.system.*: optional non-product telemetry (ingestion, pipeline, SDK health).
Required Event Envelope (Normative)#
Every analytics event MUST include:
event_id(globally unique id)event_name(canonical name)event_version(integer, starts at1)occurred_at(ISO-8601 UTC timestamp)platform(ios,android,web,pwa)surface(mobile_shell,web_shell,domain_app,bff)session_iddomain_context(oshun_shell,tara,veritas,nyx,arete)consent_analytics(boolean gate)
User identity fields:
user_idwhen authenticatedanonymous_idwhen unauthenticated- at least one of
user_idoranonymous_idis required
Property Standards#
- Use snake_case property names.
- Stable enum properties MUST be documented in contract schemas.
- High-cardinality free text should be minimized and explicitly justified.
- PII (email, phone, full name, raw IP) MUST NOT be sent in event properties.
Event Versioning Rules#
- Additive, backward-compatible property additions: keep same
event_name, increment optional schema metadata as needed. - Breaking changes (rename/remove semantic meaning): increment
event_version. - Name changes require dual-write period and mapping documentation.
Taxonomy Families (Normative)#
OSHUN analytics events MUST be categorized into these families:
lifecycle: app/session open, close, resumeauth: signin, signup, logout, refresh, revocation outcomesnavigation: route transitions, deep-link opens, domain launchesengagement: views, reads, saves, shares, followsvalue_action: normalized high-value outcomes for KPI computationsearch: query, filter, result open, zero-resultnotification: received, opened, dismissed, actionedperformance: web vitals, startup, hydration, launch latencyerror: user-visible failures and recoveriescommerce(if enabled): paywall views, conversion steps, purchase outcomes
Canonical OSHUN KPI Events#
The following normalized events are mandatory for OSHUN KPI computation:
oshun.app.openedoshun.auth.completedoshun.profile.initializedoshun.domain.openedoshun.value_action.completedoshun.item.savedoshun.item.resumedoshun.search.executedoshun.notification.opened
oshun.value_action.completed MUST include:
domain_contextvalue_action_typecompletion_quality(partial,full)entity_id(or equivalent domain entity reference)
Legacy-to-Canonical Mapping Requirements#
Adapter layers MUST map legacy names to canonical names before ingestion into OSHUN KPI datasets.
Initial mapping requirements include:
| Legacy Event | Canonical Event |
|---|---|
oshun.app_opened |
oshun.app.opened |
oshun.auth_completed |
oshun.auth.completed |
oshun.profile_initialized |
oshun.profile.initialized |
oshun.domain_card_opened |
oshun.domain.opened |
oshun.value_action_completed |
oshun.value_action.completed |
oshun.item_saved |
oshun.item.saved |
oshun.item_resumed |
oshun.item.resumed |
oshun.search_executed |
oshun.search.executed |
oshun.notification_opened |
oshun.notification.opened |
article_view (Veritas behavior tracker) |
veritas.article.viewed |
article_complete (Veritas behavior tracker) |
veritas.article.completed |
search_query (Veritas behavior tracker) |
veritas.search.executed |
Consent and Privacy Rules#
- Events with
consent_analytics=falseMUST be excluded from analytics KPI views. - Consent state transitions must be audited as separate
oshun.privacy.*events where policy permits. - Anonymous pre-consent events may be used only for strictly necessary operational telemetry, not product analytics KPIs.
Implementation Guidance#
SDK and Contracts#
- Implement shared types/contracts in
libs/oshun/analytics(planned). - Validate names and required envelope fields at SDK boundary.
- Provide helper APIs to reduce ad hoc string event usage.
Shell and Domain Adapters#
- Shell emits
oshun.*normalized events. - Domain adapters emit domain-native events and optional normalized mirror events for KPI-critical actions.
- BFF enforces envelope validation and rejects malformed events.
Warehouse and BI#
- Keep
event_namecanonical and immutable in curated tables. - Preserve raw event payload in bronze/raw storage for forensics.
- Maintain version-aware transforms for
event_versionchanges.
Implementation Plan#
Phase 1: Contract Finalization#
- Define canonical event-name regex and lint checks.
- Define envelope schema and required enums.
- Publish initial event dictionary with owners.
Phase 2: Adapter Migration#
- Add mapping layer for existing Veritas behavior events.
- Add canonical shell event emitter for mobile/web/PWA.
- Introduce dual-write where migrations are needed.
Phase 3: Enforcement#
- Add CI checks for disallowed event names.
- Add ingestion-side validation with reject/error metrics.
- Add dashboard for unknown/unmapped event names.
Phase 4: Hardening#
- Remove deprecated aliases after migration window.
- Run periodic taxonomy review and cardinality audits.
- Add playbooks for emergency event rollback/deprecation.
Success Metrics#
- 100% of OSHUN KPI dashboards use canonical
event_namevalues. - Unknown/unmapped event rate < 0.5% of daily event volume.
- Consent violation rate for KPI datasets = 0.
- Event schema validation pass rate >= 99.5%.
- Cross-platform metric parity (mobile vs web/PWA definitions) maintained.
Consequences#
Positive Consequences#
- ✅ Clear, scalable analytics naming model across shell and domains.
- ✅ Faster metric development with less downstream remapping.
- ✅ Better governance, auditability, and privacy control.
Negative Consequences#
- ❌ Upfront migration work in tracking adapters and dashboards.
- ❌ Ongoing taxonomy governance overhead.
Risks and Mitigations#
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| Legacy tracker drift continues | Medium | High | CI lint + ingestion validation + owner escalation |
| High-cardinality property explosion | Medium | Medium | event review checklist + cardinality monitoring |
| Dashboard breakage during rename | Medium | High | dual-write period + mapping tables + cutover plan |
| Consent metadata missing in clients | Low | High | SDK-required fields + ingestion reject policy |
Monitoring and Observability#
Track:
- event ingestion acceptance/rejection counts by reason
- unknown event-name frequency
- event-version distribution per
event_name - consented vs non-consented event ratios
- mapping-layer fallback usage during migration
Related Decisions#
docs/adr/ADR-0013-oshun-shell-architecture-and-domain-adapters.mddocs/adr/ADR-0014-oshun-web-and-pwa-strategy.mddocs/adr/ADR-0016-shared-identity-and-cross-domain-session-model.mddocs/adr/ADR-0017-offline-caching-and-sync-strategy.mddocs/adr/ADR-0010-eventing-strategy.md
References#
docs/releases/v1/reports/metrics.mdapps/veritas/web/src/lib/behavior-tracking/types.tsapps/veritas/web/src/lib/behavior-tracking/tracker.tsapps/veritas/mobile/src/services/notifications.tslibs/contracts/src/events/veritas.tslibs/shared/infrastructure/src/types.tslibs/shared/infrastructure/src/monitoring/monitoring-manager.ts