# System Design: mixpanel-react-native

## Architectural Overview

The Mixpanel React Native library implements a **dual-path architecture** with sophisticated queue management, persistent state, and graceful fallback mechanisms. The system prioritizes data reliability over performance, ensuring no analytics events are lost.

## 🏗️ High-Level Architecture

```
┌─────────────────────────────────────────────────────────────────┐
│                     Application Layer                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐  │
│  │   Mixpanel  │  │   People    │  │    MixpanelGroup        │  │
│  │   (Events)  │  │ (Profiles)  │  │   (Group Analytics)     │  │
│  └─────────────┘  └─────────────┘  └─────────────────────────┘  │
└─────────────────────┬───────────────────────────────────────────┘
                      │ Public API (index.js)
┌─────────────────────┴───────────────────────────────────────────┐
│                   Implementation Router                        │
│                                                                 │
│  ┌─────────────────────┐      ┌─────────────────────────────┐   │
│  │   Native Mode       │      │    JavaScript Mode          │   │
│  │  (iOS Swift +       │ OR   │   (Pure JS Implementation)  │   │
│  │  Android Java)      │      │                             │   │
│  └─────────────────────┘      └─────────────────────────────┘   │
└─────────────────────────────────┬───────────────────────────────┘
                                  │
┌─────────────────────────────────┴───────────────────────────────┐
│                    Shared Infrastructure                       │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐  │
│  │ Queue Mgmt  │  │ Persistence │  │       Network           │  │
│  │ (In-Memory  │  │  (Storage   │  │   (HTTP + Retry)        │  │
│  │ + Durable)  │  │ Abstraction)│  │                         │  │
│  └─────────────┘  └─────────────┘  └─────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘
```

## 🔄 Data Flow Architecture

### 1. Event Tracking Flow

```
User Code
    │ mixpanel.track("Event", {props})
    │
    ▼
┌─────────────────────────────────────────────┐
│           Input Validation Layer            │
│  • Parameter validation (StringHelper)     │
│  • Type checking (ObjectHelper)            │
│  • Error throwing with helpful messages    │
└─────────────────┬───────────────────────────┘
                  │ ✓ Valid input
                  ▼
┌─────────────────────────────────────────────┐
│         Implementation Router               │
│  if (useNative && MixpanelReactNative) {   │
│    → Native Implementation                 │
│  } else {                                  │
│    → JavaScript Implementation             │
│  }                                         │
└─────────────────┬───────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────┐
│            Event Enrichment                 │
│  • Add metadata (device info, lib version) │
│  • Merge super properties                  │
│  • Add identity fields (distinct_id, etc)  │
│  • Calculate event timing if applicable    │
│  • Add session metadata                    │
└─────────────────┬───────────────────────────┘
                  │ Enriched event object
                  ▼
┌─────────────────────────────────────────────┐
│               Opt-out Check                 │
│  if (persistent.getOptedOut(token)) {      │
│    → Log skip message and return           │
│  }                                         │
└─────────────────┬───────────────────────────┘
                  │ ✓ User opted in
                  ▼
┌─────────────────────────────────────────────┐
│            Queue Management                 │
│  • Add to in-memory queue                  │
│  • Persist to storage (AsyncStorage)       │
│  • Trigger batch processing if needed      │
└─────────────────┬───────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────┐
│             Batch Processing                │
│  • Collect events in batches (default: 50) │
│  • Process every 10s (JS) or 60s (native) │
│  • Handle network requests with retries    │
└─────────────────┬───────────────────────────┘
                  │ HTTP POST to Mixpanel API
                  ▼
┌─────────────────────────────────────────────┐
│              Mixpanel Servers               │
└─────────────────────────────────────────────┘
```

### 2. Identity Management Flow

```
User Action: mixpanel.identify("user123")
    │
    ▼
┌─────────────────────────────────────────────┐
│            Validation Layer                 │
│  StringHelper.isValid(distinctId)          │
└─────────────────┬───────────────────────────┘
                  │ ✓ Valid string
                  ▼
┌─────────────────────────────────────────────┐
│         Persistence Layer Update            │
│  • Update in-memory identity cache          │
│  • Persist to AsyncStorage                  │
│  • Set userId (for People Analytics)       │
└─────────────────┬───────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────┐
│          Queue Identity Update              │
│  • Update existing USER queue records      │
│  • Ensure consistent identity fields       │
│  • Minimize object copying (performance)   │
└─────────────────────────────────────────────┘
```

## 🏛️ System Layers

### Layer 1: Public API (index.js)
**Responsibility**: Type-safe interface with comprehensive validation

```javascript
// Clean, typed interface with validation
export class Mixpanel {
  track(eventName, properties) {
    if (!StringHelper.isValid(eventName)) {
      StringHelper.raiseError(PARAMS.EVENT_NAME);
    }
    // Route to implementation...
  }
}
```

**Key Characteristics**:
- Input validation with helpful error messages
- Implementation routing (native vs JS)
- Promise-based API for async operations
- TypeScript definitions for developer experience

### Layer 2: Implementation Layer
**Responsibility**: Platform-specific optimization

#### Native Path (iOS Swift + Android Java)
- Direct integration with official Mixpanel SDKs
- Platform-optimized performance
- Native queue management (60s flush interval)
- iOS: Background flushing support

#### JavaScript Path (mixpanel-main.js)
- Pure JavaScript implementation
- Expo and React Native Web compatibility
- Aggressive flushing (10s interval)
- Comprehensive retry logic

### Layer 3: Core Processing (mixpanel-core.js)
**Responsibility**: Shared business logic

```javascript
export const MixpanelCore = (storage) => {
  // Queue processing with batching
  const processQueue = async (token, type) => {
    const batch = queue.slice(0, batchSize);
    try {
      await MixpanelNetwork.sendRequest({...});
      // Remove successful items
    } catch (error) {
      handleBatchError(token, error, type, processBatch);
    }
  };
};
```

**Key Features**:
- Event queue management with batching
- Automatic retry with exponential backoff
- Corrupt data detection and removal
- Session metadata injection

### Layer 4: Persistence Layer (mixpanel-persistent.js)
**Responsibility**: State management across app sessions

```javascript
export class MixpanelPersistent {
  // Token-scoped state management
  constructor(storageAdapter) {
    this._identity = {};      // distinctId, deviceId, userId per token
    this._superProperties = {}; // Global event properties per token
    this._timeEvents = {};     // Event timing per token
    this._optedOut = {};       // Opt-out status per token
  }
}
```

**Storage Strategy**:
- Token-scoped keys: `MIXPANEL_{token}_{type}_{field}`
- Lazy loading on first access
- Write-through caching (memory + storage)
- Graceful failure with in-memory fallback

### Layer 5: Infrastructure Layer

#### Queue Management (mixpanel-queue.js)
```javascript
export const MixpanelQueueManager = (() => {
  let _queues = {}; // In-memory queues per token
  
  const enqueue = async (token, type, data) => {
    _queues[token][type].push(data);
    await updateQueueInStorage(token, type); // Persist immediately
  };
})();
```

**Queue Types**:
- `EVENTS`: `/track/` - Analytics events
- `USER`: `/engage/` - People profile updates  
- `GROUPS`: `/groups/` - Group analytics updates

#### Network Layer (mixpanel-network.js)
```javascript
export const MixpanelNetwork = (() => {
  const sendRequest = async ({...params, retryCount = 0}) => {
    try {
      const response = await fetch(url, {...});
      // Handle response...
    } catch (error) {
      if (retryCount < maxRetries) {
        const backoff = Math.min(2 ** retryCount * 2000, 60000);
        await new Promise(resolve => setTimeout(resolve, backoff));
        return sendRequest({...params, retryCount: retryCount + 1});
      }
    }
  };
})();
```

**Retry Strategy**:
- Exponential backoff: 2s, 4s, 8s, 16s, 32s, 60s (max)
- Max 5 retries before giving up
- 400 errors bypass retry (corrupted data)

#### Storage Abstraction (mixpanel-storage.js)
```javascript
export class AsyncStorageAdapter {
  constructor(storage) {
    // Try AsyncStorage, fall back to in-memory
    if (!storage) {
      try {
        this.storage = require("@react-native-async-storage/async-storage");
      } catch {
        this.storage = new InMemoryStorage();
      }
    }
  }
}
```

## 🔧 Configuration Management

### Token-Scoped Configuration (mixpanel-config.js)
```javascript
export class MixpanelConfig {
  static getInstance() { /* Singleton */ }
  
  // All configuration is per-token
  setFlushBatchSize(token, batchSize) {
    this._config[token] = {...this._config[token], batchSize};
  }
}
```

**Configuration Hierarchy**:
1. User-provided values (highest priority)
2. Default constants from mixpanel-constants.js
3. Fallback values in getters

## 🎯 Design Decisions & Trade-offs

### 1. Reliability Over Performance
**Decision**: Persist every event immediately to storage
**Trade-off**: Storage I/O overhead vs. zero data loss
**Justification**: Analytics data is business-critical

### 2. Token-Based Multi-Tenancy
**Decision**: Support multiple Mixpanel projects per app
**Trade-off**: Memory overhead vs. flexibility
**Justification**: Enterprise customers need project isolation

### 3. Dual Implementation Strategy
**Decision**: Maintain both native and JS implementations
**Trade-off**: Code duplication vs. platform compatibility
**Justification**: Expo support essential for adoption

### 4. Aggressive Error Handling
**Decision**: Validate all inputs, handle all errors
**Trade-off**: Code verbosity vs. developer experience
**Justification**: SDK failures should never crash apps

### 5. Queue-Based Architecture
**Decision**: Async event processing with batching
**Trade-off**: Complexity vs. performance and reliability
**Justification**: Network efficiency and offline support

## 🚀 Performance Characteristics

### Memory Usage
- In-memory queues per token/type
- LRU-style identity caching
- Minimal object allocation during normal operation

### Network Efficiency
- Batched requests (50 events default)
- Compression support (gzip)
- Intelligent retry with backoff

### Storage I/O
- Write-through cache for all persistent data
- JSON serialization for complex objects
- Graceful fallback to in-memory storage

### CPU Usage
- Lazy initialization of expensive operations
- Efficient queue processing with splice operations
- Minimal validation overhead with helper classes