feat: add PostHog analytics with full event tracking across app

Integrate self-hosted PostHog (SPM) with AnalyticsManager singleton wrapping
all SDK calls. Adds ~40 type-safe events covering trip planning, schedule,
progress, IAP, settings, polls, export, and share flows. Includes session
replay, autocapture, network telemetry, privacy opt-out toggle in Settings,
and super properties (app version, device, pro status, selected sports).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Trey t
2026-02-10 15:12:16 -06:00
parent 5389fe3759
commit 2917ae22b1
20 changed files with 989 additions and 23 deletions

View File

@@ -137,6 +137,46 @@ TripCreationView → TripCreationViewModel → PlanningRequest
- CloudKit container ID: `iCloud.com.88oakapps.SportsTime`
- `PDFGenerator` and `ExportService` are `@MainActor final class` (not actors) because they access MainActor-isolated UI properties and use UIKit drawing
### Analytics (PostHog)
All analytics go through `AnalyticsManager.shared` — never call PostHog SDK directly.
**Architecture** (`Core/Analytics/`):
- `AnalyticsManager.swift` - `@MainActor` singleton wrapping PostHogSDK. Handles init, tracking, opt-in/out, super properties, session replay.
- `AnalyticsEvent.swift` - Type-safe enum with ~40 event cases, each with `name: String` and `properties: [String: Any]`.
**Self-hosted backend:** `https://analytics.88oakapps.com`
**API key:** Set in `AnalyticsManager.apiKey` (replace placeholder before shipping)
**Features enabled:**
- Event capture + autocapture
- Session replay (`screenshotMode` for SwiftUI, text inputs masked)
- Network telemetry capture
- Super properties (app version, device model, OS, pro status, selected sports)
- Privacy opt-out toggle in Settings (persisted via UserDefaults `"analyticsOptedOut"`)
**Adding new analytics:**
```swift
// 1. Add case to AnalyticsEvent enum
case myNewEvent(param: String)
// 2. Add name and properties in the computed properties
// 3. Call from anywhere:
AnalyticsManager.shared.track(.myNewEvent(param: "value"))
```
**Correct Usage:**
```swift
// CORRECT - Use AnalyticsManager
AnalyticsManager.shared.track(.tripSaved(tripId: id, stopCount: 3, gameCount: 5))
AnalyticsManager.shared.trackScreen("TripDetail")
// WRONG - Never call PostHog SDK directly
PostHogSDK.shared.capture("trip_saved") // NO!
```
**Initialization:** Called during app bootstrap in `SportsTimeApp.performBootstrap()` (Step 7). Super properties refreshed on `.active` scene phase. Flushed on `.background`.
### Themed Background System
All views use `.themedBackground()` modifier for consistent backgrounds app-wide.