-
Notifications
You must be signed in to change notification settings - Fork 3
ANALYTICS_DEVELOPMENT
For contributors extending the analytics engine — architecture, the opt-out contract every
tracker must honour, how to add a backend or a tracker, the Compose companion, and testing. For
using the engine, see ANALYTICS.md. Module dev-state SoT (parity matrix, versions)
lives in cmp-firebase/DEVELOPMENT.md per
RULE-LIB-DEVELOPMENT-MD-001.
Two modules, one interface:
cmp-firebase — the engine (Compose-free, 19 KMP targets)
analytics/
AnalyticsHelper — the single interface everything is written against
AnalyticsEvent / Param — validated event + param value types
EventTypes / ParamKeys — shared constants (cross-app consistency)
AnalyticsConfig — capability flags + autoEnabled() gate helper
di/AnalyticsModule — factory: Mode.Firebase | Stub | NoOp (+ performanceTracker)
Firebase/NoOp/Stub/Test helpers
mp/ — MeasurementProtocolAnalyticsHelper (HTTP fallback tier)
PerformanceTracker — P50/P95/P99, fast/slow/very_slow tagging
AppLifecycleTracker — app_launch cold-start + fg/bg
MemoryTracker — provider-based memory sampling
OfflineEventQueue — AnalyticsHelper decorator; buffers offline, flushes on reconnect
Funnel / EventCatalog — conversion funnels + typed-event base (events live in the app)
AnalyticsExtensions — batch(), startTiming(), event builder
net/ — analyticsTelemetryPlugin (Ktor) + attachNetworkTelemetry
cmp-firebase-compose — Compose auto-tracking companion (~9 Compose targets)
compose/
AnalyticsCompose — LocalAnalyticsHelper, TrackScreenView, TrackComposableLifecycle, Modifier.trackClick
NavAnalytics — NavController.trackScreenViews() → screen_view + screen_transition
Why two modules: the engine stays Compose-free so non-Compose consumers (services, CLIs, the 19
targets) never pull Compose. Compose reaches fewer targets, so cmp-firebase-compose is the only
place that depends on compose.* + navigation-compose. It api-depends on cmp-firebase.
Design rule — the library ships patterns, never a consumer's domain events. EventCatalog /
Funnel are builders; concrete event catalogs (e.g. a MifosAnalyticsEvents) live in the
consumer app, not in this library.
There is exactly one master switch — AnalyticsHelper.setCollectionEnabled(Boolean) — and every
automatic emitter must consult it (directly, or via an AnalyticsConfig flag) before emitting.
-
AnalyticsConfig.autoEnabled(capability, collectionEnabled)returnscollectionEnabled && capability. - Trackers that take an
enabled: () -> Booleangate (analyticsTelemetryPlugin,attachNetworkTelemetry) must be passed{ config.autoNetworkTelemetry }(or equivalent) by the wiring so the master switch composes. -
TestAnalyticsHelper.logEventearly-returns when collection is off — the test-double models the same cascade, which is what theoptout_cascade_suppresses_auto_trackerstest asserts.
When you add an emitter, you MUST wire it into this cascade. A tracker that emits while
setCollectionEnabled(false) is a correctness bug and will fail the opt-out test.
- Implement
AnalyticsHelper(overridelogEvent(AnalyticsEvent)at minimum; overridesetCollectionEnabled/setConsent/setUserId/setUserPropertywhere the backend supports them). - If it's platform-specific, provide it through the
expect fun provideAnalyticsHelper()seam in the relevant source set (mirrorFirebaseAnalyticsHelperinfirebaseMain). - Add a
Modeentry indi/AnalyticsModuleonly if it's a first-class choice for consumers; otherwise consumers can pass their own instance. - Honour the opt-out contract (respect
setCollectionEnabled).
- Take
AnalyticsHelper(or decorate it, likeOfflineEventQueue) in the constructor. - Add a
Booleanflag toAnalyticsConfig(defaulttrue) and gate emission onconfig.autoEnabled(flag, collectionEnabled)— or accept anenabled: () -> Boolean. - Emit through
helper.logEvent(...)withEventTypes/ParamKeysconstants (add new constants there rather than inline strings). - Add a test to
AnalyticsEngineTestproving (a) it emits when on, (b) it's silent when the master switch is off. - Document it in ANALYTICS.md §Event reference.
Everything reads the helper from LocalAnalyticsHelper (default NoOpAnalyticsHelper). New
composables should rememberAnalyticsHelper() rather than take a helper param, so previews/tests
stay silent by default. Keep the companion Compose-only — engine logic belongs in cmp-firebase.
- Unit tests:
cmp-firebase/src/commonTest/.../analytics/AnalyticsEngineTest.kt(opt-out cascade, percentile math, offline-queue buffer/flush) +AnalyticsCollectionTest.kt. - Offline-queue tests use
FakeNetworkMonitor().setOnline(false/true)fromcmp-network-monitor'stesting/package (available via theapidep) withrunTest/runCurrent/backgroundScope. - Run:
./gradlew :cmp-firebase:jvmTest(fast) —Mode.Firebaseis unavailable off-device (GitLive JVM analytics is a stub), so tests useTestAnalyticsHelper/Mode.NoOp.
Both modules are under Binary Compatibility Validator. Any public API change requires an
apiDump:
./gradlew :cmp-firebase:apiDump :cmp-firebase-compose:apiDump
./gradlew :cmp-firebase:apiCheck :cmp-firebase-compose:apiCheck # must be green before commitBaselines: cmp-firebase/api/jvm/*.api, cmp-firebase-compose/api/jvm/*.api.
- Kotlin
2.4.0/ Compose1.11.1. GitLive has no watchOS, and this module also omitswasmWasion purpose (see the comment incmp-firebase/build.gradle.kts). Keep target sets aligned with thecmp-network-monitor*siblings.
(Corrected 2026-09-03: an earlier revision claimed alpha01 "droppediosX64/macosX64". That was wrong — the module declaresiosX64(),iosArm64(),iosSimulatorArm64(),macosX64()andmacosArm64(), and:cmp-firebase:linkDebugTestMacosX64builds green.) -
wasmJs moved to the native Firebase tier in alpha02 — it is no longer a
Measurement-Protocol target and now reads
FirebaseConfig.web. Crashlytics is the one exception: upstream did not addwasmjsthere, so wasmJs keeps the logging fallback. - After changing dependencies, JS/Wasm yarn locks need both
./gradlew kotlinUpgradeYarnLockandkotlinWasmUpgradeYarnLock(the JS one alone is insufficient). - Prefer targeted module builds (
:cmp-firebase:build) over a full-repo build (OOM-prone).
Versioned by the kmptoolkit.version gradle property; published to Maven Central via the vanniktech
plugin (same pipeline as every cmp-* module). For local consumer verification (e.g. the template
migration) use ./gradlew :cmp-firebase:publishToMavenLocal :cmp-firebase-compose:publishToMavenLocal
and consume from mavenLocal().
- ANALYTICS.md — consumption guide
- SETUP.md — install + per-platform Firebase config + GA4
-
cmp-firebase/DEVELOPMENT.md— module dev-state SoT - Design record:
docs/superpowers/specs/2026-08-11-gitlive-firebase-3.0.0-alpha01-adoption-design.md
** Partials**
App Intents
Bubble
Clipboard
Cookbook
- Clipboard Copy Text
- Clipboard Read Text
- Consumer Anon Key Setup
- Crashlytics Attribution Per Library
- Ifonline Block
- Index
- Index
- Index
- Index
- Open Url Compose
- Pick And Share Image
- React To Offline
- Register Firebase Hooks
- Share Pdf Android
- Share Text
- Wifi Vs Cellular
Firebase
In App Update
Intent Launcher
Inter App Comms
Modules
- Cmp App Intents
- Cmp App Intents Compose
- Cmp Bubble
- Cmp Clipboard
- Cmp Deep Link
- Cmp Firebase
- Cmp In App Update
- Cmp Intent Launcher
- Cmp Intent Launcher Compose
- Cmp Library
- Cmp Network Monitor
- Cmp Network Monitor Compose
- Cmp Observe
- Cmp Observe Koin
- Cmp Open Url
- Cmp Pdf Generator
- Cmp Product Tickets
- Cmp Remote Config
- Cmp Share
- Cmp Share Compose
- Cmp Toast
Network Monitor
Open Url
Pdf Generator
Remote Config
Share
Superpowers
Toast
User Tickets
General