# 🚀 Sleek SDK Production Guide

## Overview

This guide shows you how to safely integrate Sleek SDK into production applications without disrupting user experience, even when the API fails.

## 🔧 Key Changes Made

### 1. **Updated API URL**
- Changed from `localhost:3001` to `https://sleek-api.vercel.app`
- Production-ready endpoint configuration

### 2. **Enhanced Error Handling**
- Graceful fallbacks to 'control' variant when API fails
- Fast timeouts (2-3 seconds) to prevent blocking
- Silent error handling that doesn't break user experience

### 3. **Production Configuration**
- Optimized batching and caching
- Privacy-friendly defaults
- Minimal logging in production

## 🛡️ Safe Production Integration

### Basic Setup

```javascript
import { createAnonymousSleek } from 'sleek-sdk';

// Production configuration
const sleek = createAnonymousSleek('https://sleek-api.vercel.app', {
  requestTimeout: 2000,     // Fast timeout
  retryAttempts: 1,         // Single retry
  gracefulFallback: true,   // Always fallback to 'control'
  enableLogging: false,     // No console logs
  batchEvents: true,        // Efficient event batching
  batchSize: 25,
  flushInterval: 15000      // 15 seconds
});
```

### Safe Variant Assignment

```javascript
async function getExperimentVariant(experimentId) {
  try {
    // Add timeout protection
    const variant = await Promise.race([
      sleek.getVariant(experimentId),
      new Promise((_, reject) => 
        setTimeout(() => reject(new Error('Timeout')), 1000)
      )
    ]);
    
    return variant;
  } catch (error) {
    console.warn('Experiment failed, using control:', error.message);
    return 'control'; // Safe fallback
  }
}
```

### React Integration

```jsx
import { useState, useEffect } from 'react';

function useExperiment(experimentId, defaultVariant = 'control') {
  const [variant, setVariant] = useState(defaultVariant);
  const [loading, setLoading] = useState(true);
  
  useEffect(() => {
    let mounted = true;
    
    async function loadExperiment() {
      try {
        const result = await sleek.getVariant(experimentId);
        if (mounted) setVariant(result);
      } catch (error) {
        if (mounted) setVariant(defaultVariant);
      } finally {
        if (mounted) setLoading(false);
      }
    }
    
    loadExperiment();
    return () => { mounted = false; };
  }, [experimentId, defaultVariant]);
  
  return { variant, loading };
}

// Usage in component
function ProductPage() {
  const { variant, loading } = useExperiment('product_layout_test');
  
  if (loading) {
    return <div>Loading...</div>;
  }
  
  return (
    <div className={`layout-${variant}`}>
      {/* Your content */}
    </div>
  );
}
```

## 🎯 Real-World Usage Patterns

### 1. E-commerce Product Page

```javascript
class ProductPageExperiment {
  constructor() {
    this.sleek = createAnonymousSleek('https://sleek-api.vercel.app', {
      requestTimeout: 1500,
      gracefulFallback: true
    });
    this.experimentId = 'product_page_layout_v2';
  }
  
  async initialize() {
    try {
      const variant = await this.sleek.getVariant(this.experimentId);
      this.applyLayout(variant);
      this.trackPageView();
    } catch (error) {
      this.applyLayout('control'); // Safe fallback
    }
  }
  
  applyLayout(variant) {
    switch (variant) {
      case 'new_layout':
        document.body.classList.add('new-product-layout');
        break;
      case 'minimal':
        document.body.classList.add('minimal-layout');
        break;
      default:
        document.body.classList.add('default-layout');
    }
  }
  
  trackPurchase(orderValue) {
    // Safe tracking - won't throw errors
    this.sleek.trackConversion(this.experimentId, {
      value: orderValue,
      currency: 'USD'
    });
  }
}
```

### 2. Feature Flags

```javascript
class FeatureManager {
  constructor() {
    this.sleek = createAnonymousSleek('https://sleek-api.vercel.app');
  }
  
  async isFeatureEnabled(featureName, defaultValue = false) {
    try {
      const variant = await this.sleek.getVariant(`feature_${featureName}`);
      return variant === 'enabled';
    } catch (error) {
      return defaultValue; // Safe fallback
    }
  }
}

// Usage
const features = new FeatureManager();

if (await features.isFeatureEnabled('new_checkout', false)) {
  // Show new checkout flow
} else {
  // Show existing checkout flow
}
```

### 3. Gradual Rollouts

```javascript
async function shouldShowNewFeature() {
  try {
    const variant = await sleek.getVariant('new_feature_rollout');
    
    // Gradual rollout: 10% -> 'enabled', 90% -> 'control'
    return variant === 'enabled';
  } catch (error) {
    return false; // Conservative fallback
  }
}
```

## 🔒 Error Handling Best Practices

### 1. **Never Let Experiments Break Your App**

```javascript
// ❌ Bad: Can break user experience
const variant = await sleek.getVariant('experiment_id');
if (variant === 'new_design') {
  // This might fail if API is down
}

// ✅ Good: Always has fallback
const variant = await sleek.getVariant('experiment_id').catch(() => 'control');
switch (variant) {
  case 'new_design':
    // Apply new design
    break;
  default:
    // Apply default design (always works)
}
```

### 2. **Use Timeouts**

```javascript
// Add timeout protection
const variant = await Promise.race([
  sleek.getVariant('experiment_id'),
  new Promise((_, reject) => 
    setTimeout(() => reject(new Error('Timeout')), 1000)
  )
]).catch(() => 'control');
```

### 3. **Silent Tracking**

```javascript
// ❌ Bad: Can throw errors
sleek.track('experiment_id', 'button_click');

// ✅ Good: Silent failure
try {
  sleek.track('experiment_id', 'button_click');
} catch (error) {
  // Log error but don't break user flow
  console.warn('Tracking failed:', error.message);
}
```

## 📊 Performance Optimization

### 1. **Caching**

```javascript
// SDK automatically caches assignments
const variant1 = await sleek.getVariant('experiment_id'); // API call
const variant2 = await sleek.getVariant('experiment_id'); // Cached
```

### 2. **Batching Events**

```javascript
// Events are automatically batched
sleek.track('exp1', 'click');
sleek.track('exp2', 'view');
sleek.track('exp3', 'conversion');
// All sent together after 15 seconds or 25 events
```

### 3. **Preloading**

```javascript
// Preload critical experiments
async function preloadExperiments() {
  const criticalExperiments = [
    'homepage_hero',
    'checkout_flow',
    'pricing_display'
  ];
  
  await Promise.allSettled(
    criticalExperiments.map(id => sleek.getVariant(id))
  );
}
```

## 🧪 Testing Your Integration

### 1. **Test with API Down**

```javascript
// Simulate API failure
const mockSleek = {
  getVariant: () => Promise.reject(new Error('API Down')),
  track: () => Promise.reject(new Error('API Down'))
};

// Your code should still work
```

### 2. **Test Slow API**

```javascript
// Simulate slow API
const slowSleek = {
  getVariant: () => new Promise(resolve => 
    setTimeout(() => resolve('control'), 5000)
  )
};

// Should timeout and fallback quickly
```

## 🚀 Deployment Checklist

- [ ] API URL updated to production endpoint
- [ ] Timeouts set to 2-3 seconds max
- [ ] Graceful fallbacks implemented
- [ ] Error logging disabled in production
- [ ] Event batching enabled
- [ ] Cleanup handlers added
- [ ] Tested with API failures
- [ ] Tested with slow network
- [ ] Performance monitoring added

## 📈 Monitoring

### Track SDK Health

```javascript
// Monitor SDK performance
let apiSuccessRate = 0;
let totalRequests = 0;

const originalGetVariant = sleek.getVariant;
sleek.getVariant = async function(experimentId) {
  totalRequests++;
  try {
    const result = await originalGetVariant.call(this, experimentId);
    if (result !== 'control') apiSuccessRate++;
    return result;
  } catch (error) {
    // Track failures
    analytics.track('sleek_sdk_error', {
      experiment_id: experimentId,
      error: error.message
    });
    throw error;
  }
};
```

## 🔧 Common Issues & Solutions

### Issue: Slow Page Load
**Solution:** Reduce timeout to 1-2 seconds

### Issue: Too Many API Calls
**Solution:** Enable caching and batching

### Issue: Experiments Breaking App
**Solution:** Add proper error boundaries

### Issue: Inconsistent Results
**Solution:** Check user ID persistence

## 📞 Support

If you encounter issues:

1. Check browser console for errors
2. Verify API endpoint is accessible
3. Test with mock data
4. Check network timeouts
5. Verify experiment IDs exist

Remember: **The SDK should never break your application.** If it does, you need better error handling! 