Skip to content

batukucukaydin/EventQualityLab

Repository files navigation

EventQualityLab

Spec-driven analytics + automated event correctness tests for iOS.

Most juniors ship UI. This repo showcases analytics data quality at scale — JSON-based event contracts, runtime validation, an in-memory recorder, and deterministic test infrastructure that catches broken analytics before they reach production.


Problem

Analytics data breaking silently affects business decisions, A/B test results, and growth metrics. By the time anyone notices, dashboards have been incorrect for weeks. This project solves that with a contract-first approach — every analytics event is validated against a JSON spec at compile-test time.


Architecture

┌─────────────────────────────────────────────────────┐
│                    SwiftUI App                      │
│  ┌──────────┐  ┌──────────────┐  ┌──────────────┐  │
│  │ Product  │→ │   Product    │→ │   Checkout   │  │
│  │   List   │  │   Detail     │  │   + Pay      │  │
│  └────┬─────┘  └──────┬───────┘  └──────┬───────┘  │
│       │               │                 │           │
│       └───────────────┼─────────────────┘           │
│                       ▼                             │
│            ┌─────────────────────┐                  │
│            │    EventLogger      │ ← track(name, payload)
│            │    (Mini SDK)       │                  │
│            └────────┬────────────┘                  │
│         ┌───────────┼───────────┐                   │
│         ▼           ▼           ▼                   │
│  ┌────────────┐ ┌────────┐ ┌──────────────┐        │
│  │  Validator  │ │Recorder│ │AnalyticsClient│       │
│  │ (vs spec)  │ │ (actor)│ │  (mock net)   │       │
│  └─────┬──────┘ └───┬────┘ └──────────────┘        │
│        ▼            ▼                               │
│  ┌──────────┐  ┌──────────────┐                     │
│  │events.json│ │events_export │                     │
│  │  (spec)   │ │   .json      │                     │
│  └──────────┘  └──────────────┘                     │
└─────────────────────────────────────────────────────┘

Event Spec (events.json)

Every event is defined in a contract:

{
  "schema_version": "1.0",
  "events": {
    "product_viewed": {
      "required": ["product_id", "price", "currency", "timestamp_ms"],
      "optional": ["category"],
      "types": { "product_id": "string", "price": "double", ... },
      "allowed": { "currency": ["TRY", "USD", "EUR"] }
    }
  }
}

The EventValidator checks every track() call against this spec: missing keys, wrong types, unknown fields, and disallowed values all produce clear errors.


How to Run

Requirements

  • Xcode 15+ (Swift 5.9+)
  • iOS 16.0+ simulator

Build & Run

open EventQualityLab.xcodeproj
# ⌘R to run on simulator

Run Tests

# Unit tests
xcodebuild test \
  -project EventQualityLab.xcodeproj \
  -scheme EventQualityLab \
  -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' \
  -only-testing:EventQualityLabTests

# UI tests
xcodebuild test \
  -project EventQualityLab.xcodeproj \
  -scheme EventQualityLab \
  -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' \
  -only-testing:EventQualityLabUITests

Project Structure

EventQualityLab/
├── Core/
│   ├── Models/
│   │   ├── EventSpec.swift          # Spec data models
│   │   ├── EventRecord.swift        # Recorded event model
│   │   ├── CodableValue.swift       # Type-erased Codable wrapper
│   │   └── Product.swift            # Product data model
│   ├── EventSpecLoader.swift        # Load & decode spec from bundle
│   ├── EventValidator.swift         # 5-layer spec validation
│   ├── EventRecorder.swift          # Thread-safe event store (actor)
│   ├── EventLogger.swift            # Main SDK entry point
│   ├── EventLoggerConfiguration.swift # Config + launch arg detection
│   └── AnalyticsClient.swift        # Protocol + mock network
├── Features/
│   ├── ProductList/                 # List screen
│   ├── ProductDetail/               # Detail + add to cart
│   ├── Checkout/                    # Mock payment
│   └── Debug/                       # Export/reset panel
├── Resources/
│   ├── events.json                  # Event spec v1.0
│   ├── events_v2_breaking.json      # Breaking change demo
│   └── products.json                # Product catalog fixture
├── ContentView.swift                # Navigation root
└── EventQualityLabApp.swift         # App entry + config

EventQualityLabTests/
├── EventSpecLoadingTests.swift
├── EventValidatorTests.swift
├── EventLoggerTests.swift
├── EventRecorderTests.swift
└── BreakingChangeTests.swift        # v2 spec breaking change demo

EventQualityLabUITests/
└── EventQualityLabUITests.swift     # Full flow + event verification

Demo

Checkout Flow Event Export Failing Test
Checkout flow Event export Failing test

What Makes This Different

✅ Contract Validation

Every track() call is validated against events.json at runtime. Missing fields, wrong types, and disallowed values are caught immediately — with assertionFailure in DEBUG.

✅ Deterministic UI Testing

UI tests launch with -ui_testing -reset_events_on_launch, navigate the full checkout flow, then export recorded events and verify the exact sequence. No flaky network calls.

✅ In-Memory Recorder with Export

The EventRecorder actor stores all events and exports them as JSON — to a file for debugging, to the clipboard for UI tests.

✅ Breaking Change Detection

events_v2_breaking.json demonstrates what happens when a spec evolves: the BreakingChangeTests prove that old payloads fail under the new contract, catching regressions before they ship.

✅ Mock Network Layer

MockAnalyticsClient writes to a JSONL file instead of hitting a real endpoint. Tests are always deterministic.


CI

GitHub Actions runs on every push and PR:

# .github/workflows/ci.yml
- Build project
- Run unit tests (EventQualityLabTests)
- Run UI tests (EventQualityLabUITests)

Test Results

The project is fully covered by automated tests to ensure data quality at every layer.

Unit Tests: 33/33 PASSED

Test Suite Tests Description
EventValidatorTests 13 Validates types, required fields, and disallowed values
EventSpecLoadingTests 6 Ensures JSON specs are correctly parsed from bundle
EventRecorderTests 6 Verifies thread-safe event storage and JSON export
EventLoggerTests 5 Tests the SDK pipeline (Validate -> Record)
BreakingChangeTests 3 Proves that v2 spec changes correctly catch regressions

UI Tests: PASSED

  • Verifies the full E-Commerce flow: Product List -> Detail -> Checkout -> Payment Success.
  • Validates the exact sequence of 5 analytics events by inspecting the recorder export.

Configuration

Flag Default Description
strictMode true Unknown keys cause validation failure
debugAssertsEnabled true Invalid events crash in DEBUG
isUITesting false Set via -ui_testing launch arg
shouldResetOnLaunch false Set via -reset_events_on_launch
useMockNetwork true Always mock in this demo

👨‍💻 Author

Batuhan Küçükaydın
Software Engineer | Computer Engineer | iOS Developer
📫 LinkedInGitHubMedium


License

MIT

About

A spec-driven analytics demo for iOS focusing on data quality at scale. Features JSON contract validation, thread-safe in-memory recording, and automated Unit/UI tests for event correctness.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages