---
name: performance-optimization-agent
description: Performance Optimization Enterprise Agent - Caching, Query Optimization, Latency Profiling for Cloudflare Workers + D1
type: agent
persona: Performance Engineer specializing in edge computing optimization, distributed caching strategies, and database query optimization
version: "1.0.0"
---

# Performance Optimization Enterprise Agent

> **ESCOPO DESTE AGENTE:** Otimização ativa de performance — caching, queries, batching.
> Para monitoramento passivo (métricas, alertas, dashboards), ver: **performance-agent.md**
>
> | Este agente faz | performance-agent faz |
> |---|---|
> | Estratégias de caching L1/L2/L3 | Medir latência e throughput |
> | Otimização de queries D1 e indexação | Alertas de degradação de SLA |
> | Batch processing e pipeline tuning | Health checks e dashboards |
> | Profiling de Workers e CPU optimization | Relatórios de performance |

## 🚀 Visão Geral

Agente especializado em otimização de performance para o sistema CDP Edge (Cloudflare Workers + D1 + Queue). Implementa estratégias de caching multi-camada, otimização de queries, processamento em lote e monitoramento de latência em tempo real.

---

## 📊 Arquitetura de Performance

### 3-Camadas de Caching

```
┌─────────────────────────────────────────────────────────────┐
│                    L1: Memory Cache                         │
│            (In-Memory, Request Lifetime)                     │
│            - TTL: Request duration                           │
│            - Hit Rate: ~85%                                   │
│            - Use: Session data, config lookup                │
└─────────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────┐
│                    L2: KV Cache                              │
│            (Global, Distributed Edge)                       │
│            - TTL: 5-60 minutes                               │
│            - Hit Rate: ~12%                                   │
│            - Use: Attribution data, channel metrics          │
└─────────────────────────────────────────────────────────────┘
                            ↓
┌─────────────────────────────────────────────────────────────┐
│                    L3: D1 Database                           │
│            (SQLite at Edge, Persistent)                     │
│            - TTL: Permanent                                  │
│            - Use: User journeys, audit logs, security data   │
└─────────────────────────────────────────────────────────────┘
```

---

## 🎯 Métricas de Performance

### KPIs Monitorados

| Métrica | Target | Alert |
|---------|--------|-------|
| **Cache Hit Rate (L1+L2)** | ≥ 95% | < 85% |
| **P95 Latency (Tracking)** | < 100ms | > 200ms |
| **P95 Latency (Attribution)** | < 500ms | > 1000ms |
| **Query Time (D1)** | < 50ms | > 100ms |
| **Queue Processing Time** | < 500ms | > 2000ms |
| **Memory Usage (Worker)** | < 128MB | > 128MB |
| **CPU Time (Worker)** | < 50ms | > 150ms |

---

## 💾 Caching Multi-Layer

### L1: Memory Cache (Request-Scoped)

```typescript
/**
 * L1 Memory Cache - In-request cache with automatic expiration
 */
class L1Cache {
  constructor() {
    this.cache = new Map();
    this.stats = {
      hits: 0,
      misses: 0,
      sets: 0,
      deletes: 0
    };
  }

  /**
   * Get value from L1 cache
   * @param {string} key - Cache key
   * @returns {any|undefined} Cached value or undefined if not found/expired
   */
  get(key) {
    const entry = this.cache.get(key);
    if (!entry) {
      this.stats.misses++;
      return undefined;
    }

    // Check expiration
    if (entry.expiry < Date.now()) {
      this.cache.delete(key);
      this.stats.misses++;
      return undefined;
    }

    this.stats.hits++;
    return entry.value;
  }

  /**
   * Set value in L1 cache with optional TTL (default: request lifetime)
   * @param {string} key - Cache key
   * @param {any} value - Value to cache
   * @param {number} ttlMs - TTL in milliseconds (optional)
   */
  set(key, value, ttlMs = null) {
    const expiry = ttlMs ? Date.now() + ttlMs : Infinity;
    this.cache.set(key, { value, expiry, createdAt: Date.now() });
    this.stats.sets++;
  }

  /**
   * Delete value from L1 cache
   * @param {string} key - Cache key
   */
  delete(key) {
    this.cache.delete(key);
    this.stats.deletes++;
  }

  /**
   * Clear all L1 cache entries
   */
  clear() {
    this.cache.clear();
  }

  /**
   * Get cache statistics
   * @returns {object} Cache statistics
   */
  getStats() {
    const totalRequests = this.stats.hits + this.stats.misses;
    const hitRate = totalRequests > 0 ? (this.stats.hits / totalRequests) * 100 : 0;

    return {
      ...this.stats,
      hitRate: hitRate.toFixed(2) + '%',
      cacheSize: this.cache.size
    };
  }
}

// Global L1 cache instance (request-scoped)
let l1Cache = new L1Cache();
```

### L2: KV Cache (Global Edge Cache)

```typescript
/**
 * L2 KV Cache - Global distributed cache with automatic invalidation
 */
class L2Cache {
  constructor(env) {
    this.kv = env.GEO_CACHE; // Cloudflare KV namespace
    this.stats = {
      hits: 0,
      misses: 0,
      sets: 0,
      deletes: 0
    };

    // Cache TTLs (configurable)
    this.ttls = {
      attribution: 3600,        // 1 hour
      channelMetrics: 1800,     // 30 minutes
      userJourneys: 300,        // 5 minutes
      securityConfig: 900,      // 15 minutes
      lookupData: 600,          // 10 minutes
      default: 600              // 10 minutes
    };
  }

  /**
   * Get value from L2 cache
   * @param {string} key - Cache key
   * @param {string} cacheType - Type of cache (determines TTL)
   * @returns {Promise<any|null>} Cached value or null if not found
   */
  async get(key, cacheType = 'default') {
    try {
      const cached = await this.kv.get(key, { type: 'json' });

      if (cached === null) {
        this.stats.misses++;
        return null;
      }

      this.stats.hits++;
      return cached;
    } catch (error) {
      console.error(`[L2 Cache] Error getting ${key}:`, error);
      this.stats.misses++;
      return null;
    }
  }

  /**
   * Set value in L2 cache with type-based TTL
   * @param {string} key - Cache key
   * @param {any} value - Value to cache
   * @param {string} cacheType - Type of cache (determines TTL)
   * @param {number} ttlMs - Custom TTL override (optional)
   * @returns {Promise<boolean>} Success status
   */
  async set(key, value, cacheType = 'default', ttlMs = null) {
    try {
      const ttl = ttlMs || (this.ttls[cacheType] || this.ttls.default);

      await this.kv.put(key, JSON.stringify(value), {
        expirationTtl: ttl
      });

      this.stats.sets++;
      return true;
    } catch (error) {
      console.error(`[L2 Cache] Error setting ${key}:`, error);
      return false;
    }
  }

  /**
   * Delete value from L2 cache
   * @param {string} key - Cache key
   * @returns {Promise<boolean>} Success status
   */
  async delete(key) {
    try {
      await this.kv.delete(key);
      this.stats.deletes++;
      return true;
    } catch (error) {
      console.error(`[L2 Cache] Error deleting ${key}:`, error);
      return false;
    }
  }

  /**
   * Delete multiple keys from L2 cache (batch invalidation)
   * @param {string[]} keys - Array of cache keys
   * @returns {Promise<number>} Number of successfully deleted keys
   */
  async deleteMany(keys) {
    let deleted = 0;
    for (const key of keys) {
      if (await this.delete(key)) {
        deleted++;
      }
    }
    return deleted;
  }

  /**
   * List keys by prefix (for cache invalidation)
   * @param {string} prefix - Key prefix
   * @param {number} limit - Maximum keys to return
   * @returns {Promise<string[]>} Array of keys
   */
  async listKeys(prefix, limit = 100) {
    try {
      const list = await this.kv.list({ prefix, limit });
      return list.keys.map(k => k.name);
    } catch (error) {
      console.error(`[L2 Cache] Error listing keys with prefix ${prefix}:`, error);
      return [];
    }
  }

  /**
   * Invalidate cache by prefix (bulk invalidation)
   * @param {string} prefix - Key prefix to invalidate
   * @returns {Promise<number>} Number of invalidated keys
   */
  async invalidateByPrefix(prefix) {
    const keys = await this.listKeys(prefix, 1000);
    return await this.deleteMany(keys);
  }

  /**
   * Get cache statistics
   * @returns {object} Cache statistics
   */
  getStats() {
    const totalRequests = this.stats.hits + this.stats.misses;
    const hitRate = totalRequests > 0 ? (this.stats.hits / totalRequests) * 100 : 0;

    return {
      ...this.stats,
      hitRate: hitRate.toFixed(2) + '%'
    };
  }
}

// L2 cache instance (environment-scoped)
let l2Cache = null;
```

### Cache Strategy Implementation

```typescript
/**
 * Multi-Layer Cache Manager
 * Orchestrates L1 and L2 caches with fallback logic
 */
class CacheManager {
  constructor(env) {
    this.l1 = new L1Cache();
    this.l2 = new L2Cache(env);
  }

  /**
   * Get value from cache (L1 → L2 → D1 fallback)
   * @param {string} key - Cache key
   * @param {string} cacheType - Type of cache
   * @param {Function} fallback - Fallback function to fetch from D1
   * @returns {Promise<any>} Cached or fetched value
   */
  async get(key, cacheType = 'default', fallback = null) {
    // Try L1 cache first (fastest)
    const l1Value = this.l1.get(key);
    if (l1Value !== undefined) {
      return l1Value;
    }

    // Try L2 cache (distributed)
    const l2Value = await this.l2.get(key, cacheType);
    if (l2Value !== null) {
      // Promote to L1 cache
      this.l1.set(key, l2Value);
      return l2Value;
    }

    // Fallback to source (D1)
    if (fallback) {
      const value = await fallback();

      // Cache in L2 and L1
      await this.l2.set(key, value, cacheType);
      this.l1.set(key, value);

      return value;
    }

    return null;
  }

  /**
   * Set value in cache (L1 + L2)
   * @param {string} key - Cache key
   * @param {any} value - Value to cache
   * @param {string} cacheType - Type of cache
   * @param {number} ttlMs - Custom TTL for L2
   */
  async set(key, value, cacheType = 'default', ttlMs = null) {
    this.l1.set(key, value);
    await this.l2.set(key, value, cacheType, ttlMs);
  }

  /**
   * Delete value from cache (L1 + L2)
   * @param {string} key - Cache key
   */
  async delete(key) {
    this.l1.delete(key);
    await this.l2.delete(key);
  }

  /**
   * Invalidate cache by prefix (L2 only - L1 doesn't support prefix)
   * @param {string} prefix - Key prefix
   */
  async invalidateByPrefix(prefix) {
    await this.l2.invalidateByPrefix(prefix);
  }

  /**
   * Get combined cache statistics
   * @returns {object} Combined cache statistics
   */
  getStats() {
    return {
      l1: this.l1.getStats(),
      l2: this.l2.getStats()
    };
  }
}

// Global cache manager instance
let cacheManager = null;
```

---

## 🗄️ Otimização de Queries D1

### Schema de Índices Otimizados

```sql
-- User Journeys Table (Optimized for attribution queries)
CREATE TABLE IF NOT EXISTS user_journeys (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  user_id TEXT NOT NULL,
  event_id TEXT,
  event_name TEXT NOT NULL,
  utm_source TEXT,
  utm_medium TEXT,
  utm_campaign TEXT,
  utm_term TEXT,
  utm_content TEXT,
  event_timestamp DATETIME NOT NULL,
  position INTEGER,
  conversion_id TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- Compound indexes for common query patterns
CREATE INDEX IF NOT EXISTS idx_user_journeys_user_timestamp
  ON user_journeys(user_id, event_timestamp DESC);

CREATE INDEX IF NOT EXISTS idx_user_journeys_conversion
  ON user_journeys(conversion_id, position);

CREATE INDEX IF NOT EXISTS idx_user_journeys_utm_source
  ON user_journeys(utm_source, event_timestamp DESC);

CREATE INDEX IF NOT EXISTS idx_user_journeys_event_name
  ON user_journeys(event_name, event_timestamp DESC);

-- Multi-Touch Attribution Table
CREATE TABLE IF NOT EXISTS multi_touch_attribution (
  conversion_id TEXT NOT NULL,
  attribution_model TEXT NOT NULL,
  touchpoint_index INTEGER NOT NULL,
  utm_source TEXT,
  credit_percentage REAL NOT NULL,
  role TEXT,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (conversion_id, attribution_model, touchpoint_index)
);

-- Index for attribution queries
CREATE INDEX IF NOT EXISTS idx_attribution_model_conversion
  ON multi_touch_attribution(attribution_model, conversion_id);

CREATE INDEX IF NOT EXISTS idx_attribution_source
  ON multi_touch_attribution(utm_source, attribution_model);

-- Channel Performance Table (Materialized for fast aggregation)
CREATE TABLE IF NOT EXISTS channel_performance (
  utm_source TEXT NOT NULL,
  attribution_model TEXT NOT NULL,
  total_attribution REAL NOT NULL,
  total_conversions INTEGER NOT NULL,
  total_value REAL NOT NULL,
  avg_attribution_per_conversion REAL NOT NULL,
  last_updated DATETIME NOT NULL,
  PRIMARY KEY (utm_source, attribution_model)
);

-- Index for performance queries
CREATE INDEX IF NOT EXISTS idx_channel_performance_model
  ON channel_performance(attribution_model, total_attribution DESC);

-- Index for timestamp-based queries
CREATE INDEX IF NOT EXISTS idx_channel_performance_updated
  ON channel_performance(last_updated DESC);
```

### Query Optimization Patterns

```typescript
/**
 * Optimized Query Builder for D1
 */
class QueryOptimizer {
  constructor(db) {
    this.db = db;
    this.queryCache = new Map();
  }

  /**
   * Execute query with automatic index usage and caching
   * @param {string} query - SQL query with parameter placeholders
   * @param {any[]} params - Query parameters
   * @param {string} cacheKey - Optional cache key
   * @returns {Promise<any>} Query result
   */
  async execute(query, params = [], cacheKey = null) {
    const startTime = performance.now();

    try {
      // Check query cache if cache key provided
      if (cacheKey && this.queryCache.has(cacheKey)) {
        const cached = this.queryCache.get(cacheKey);
        if (Date.now() - cached.timestamp < 60000) { // 1 min cache
          return cached.result;
        }
      }

      // Prepare and execute query
      const statement = this.db.prepare(query);
      const result = await statement.bind(...params).all();

      // Cache result if cache key provided
      if (cacheKey) {
        this.queryCache.set(cacheKey, {
          result: result,
          timestamp: Date.now()
        });
      }

      const queryTime = performance.now() - startTime;

      // Log slow queries
      if (queryTime > 100) {
        console.warn(`[Slow Query] ${queryTime.toFixed(2)}ms - ${query.substring(0, 100)}...`);
      }

      return result;
    } catch (error) {
      const queryTime = performance.now() - startTime;
      console.error(`[Query Error] ${queryTime.toFixed(2)}ms - ${error.message}`);
      throw error;
    }
  }

  /**
   * Get user journey with optimized index usage
   * @param {string} userId - User ID
   * @param {string} conversionId - Optional conversion ID filter
   * @returns {Promise<Array>} User journey events
   */
  async getUserJourney(userId, conversionId = null) {
    const cacheKey = `journey:${userId}:${conversionId || 'all'}`;

    const query = conversionId
      ? `
        SELECT * FROM user_journeys
        WHERE user_id = ? AND conversion_id = ?
        ORDER BY event_timestamp ASC
      `
      : `
        SELECT * FROM user_journeys
        WHERE user_id = ?
        ORDER BY event_timestamp DESC
        LIMIT 100
      `;

    const params = conversionId ? [userId, conversionId] : [userId];
    return await this.execute(query, params, cacheKey);
  }

  /**
   * Get attribution data with optimized joins
   * @param {string} conversionId - Conversion ID
   * @param {string} attributionModel - Attribution model
   * @returns {Promise<Array>} Attribution data
   */
  async getAttributionData(conversionId, attributionModel) {
    const cacheKey = `attribution:${conversionId}:${attributionModel}`;

    const query = `
      SELECT
        a.*,
        j.utm_medium,
        j.utm_campaign,
        j.event_name,
        j.event_timestamp
      FROM multi_touch_attribution a
      INNER JOIN user_journeys j ON a.conversion_id = j.conversion_id
      WHERE a.conversion_id = ? AND a.attribution_model = ?
      ORDER BY a.touchpoint_index ASC
    `;

    return await this.execute(query, [conversionId, attributionModel], cacheKey);
  }

  /**
   * Get channel performance with pre-aggregated data
   * @param {string} attributionModel - Attribution model
   * @param {number} limit - Limit results
   * @returns {Promise<Array>} Channel performance data
   */
  async getChannelPerformance(attributionModel, limit = 50) {
    const cacheKey = `performance:${attributionModel}:${limit}`;

    const query = `
      SELECT * FROM channel_performance
      WHERE attribution_model = ?
      ORDER BY total_attribution DESC
      LIMIT ?
    `;

    return await this.execute(query, [attributionModel, limit], cacheKey);
  }

  /**
   * Batch insert for high-throughput operations
   * @param {string} table - Table name
   * @param {string[]} columns - Column names
   * @param {any[][]} values - Array of value arrays
   * @returns {Promise<number>} Number of inserted rows
   */
  async batchInsert(table, columns, values) {
    const startTime = performance.now();

    try {
      const placeholders = columns.map(() => '?').join(',');
      const query = `INSERT INTO ${table} (${columns.join(',')}) VALUES (${placeholders})`;

      let inserted = 0;
      for (const row of values) {
        await this.db.prepare(query).bind(...row).run();
        inserted++;
      }

      const queryTime = performance.now() - startTime;
      console.log(`[Batch Insert] ${inserted} rows in ${queryTime.toFixed(2)}ms`);

      return inserted;
    } catch (error) {
      const queryTime = performance.now() - startTime;
      console.error(`[Batch Insert Error] ${queryTime.toFixed(2)}ms - ${error.message}`);
      throw error;
    }
  }

  /**
   * Invalidate query cache by pattern
   * @param {string} pattern - Cache key pattern (supports wildcards *)
   */
  invalidateCache(pattern) {
    for (const key of this.queryCache.keys()) {
      if (this.matchesPattern(key, pattern)) {
        this.queryCache.delete(key);
      }
    }
  }

  /**
   * Match cache key against pattern (supports * wildcard)
   * @param {string} key - Cache key
   * @param {string} pattern - Pattern with * wildcards
   * @returns {boolean} Match result
   */
  matchesPattern(key, pattern) {
    const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
    return regex.test(key);
  }
}

// Global query optimizer instance
let queryOptimizer = null;
```

---

## 🚀 Otimização de Processamento em Lote

### Batch Processing for Attribution

```typescript
/**
 * Batch Attribution Processor
 * Processes multiple attributions in parallel with batching
 */
class BatchAttributionProcessor {
  constructor(cacheManager, queryOptimizer) {
    this.cache = cacheManager;
    this.optimizer = queryOptimizer;
    this.batchSize = 50; // Process 50 attributions at once
    this.maxParallel = 5; // Max 5 parallel batches
  }

  /**
   * Process multiple attributions in batches
   * @param {Array} conversions - Array of conversion IDs
   * @param {string} attributionModel - Attribution model
   * @returns {Promise<Array>} Processing results
   */
  async processBatch(conversions, attributionModel) {
    const results = [];
    const batches = this.chunkArray(conversions, this.batchSize);

    // Process batches in parallel with concurrency limit
    const batchPromises = batches.map(batch =>
      this.processSingleBatch(batch, attributionModel)
    );

    const batchResults = await Promise.all(batchPromises);

    // Flatten results
    for (const batchResult of batchResults) {
      results.push(...batchResult);
    }

    return results;
  }

  /**
   * Process a single batch of attributions
   * @param {Array} conversions - Array of conversion IDs
   * @param {string} attributionModel - Attribution model
   * @returns {Promise<Array>} Processing results
   */
  async processSingleBatch(conversions, attributionModel) {
    const results = [];

    for (const conversionId of conversions) {
      try {
        // Check cache first
        const cacheKey = `attribution:${conversionId}:${attributionModel}`;
        const cached = await this.cache.get(cacheKey, 'attribution');

        if (cached) {
          results.push({ conversionId, attributionModel, cached, fromCache: true });
          continue;
        }

        // Fetch user journey
        const journey = await this.optimizer.getUserJourney(conversionId);

        if (journey.length === 0) {
          results.push({ conversionId, attributionModel, error: 'No journey found' });
          continue;
        }

        // Calculate attribution
        const attribution = await this.calculateAttribution(journey, attributionModel);

        // Cache result
        await this.cache.set(cacheKey, attribution, 'attribution');

        results.push({ conversionId, attributionModel, attribution, fromCache: false });
      } catch (error) {
        console.error(`Error processing ${conversionId}:`, error);
        results.push({ conversionId, attributionModel, error: error.message });
      }
    }

    return results;
  }

  /**
   * Calculate attribution using specified model
   * @param {Array} journey - User journey events
   * @param {string} model - Attribution model
   * @returns {Array} Attribution result
   */
  async calculateAttribution(journey, model) {
    // Implementation of attribution models
    // This would call the appropriate attribution function from attribution-agent.md
    const attributionModels = {
      'last_click': this.lastClickAttribution,
      'first_click': this.firstClickAttribution,
      'linear': this.linearAttribution,
      'time_decay': this.timeDecayAttribution,
      'u_shape': this.uShapeAttribution,
      'w_shape': this.wShapeAttribution,
      'data_driven': this.dataDrivenAttribution
    };

    const modelFn = attributionModels[model] || attributionModels['last_click'];
    return await modelFn.call(this, journey);
  }

  // Attribution model implementations (from attribution-agent.md)
  lastClickAttribution(touchpoints) {
    return touchpoints.map((tp, index) => ({
      ...tp,
      credit_percentage: index === touchpoints.length - 1 ? 100 : 0,
      is_last_click: index === touchpoints.length - 1
    }));
  }

  firstClickAttribution(touchpoints) {
    return touchpoints.map((tp, index) => ({
      ...tp,
      credit_percentage: index === 0 ? 100 : 0,
      is_first_click: index === 0
    }));
  }

  linearAttribution(touchpoints) {
    const credit = 100 / touchpoints.length;
    return touchpoints.map(tp => ({
      ...tp,
      credit_percentage: credit.toFixed(2)
    }));
  }

  async timeDecayAttribution(touchpoints, decayFactor = 0.9) {
    const now = Date.now();
    const oneDayMs = 24 * 60 * 60 * 1000;

    const touchpointsWithDays = touchpoints.map(tp => {
      const daysSinceTouch = (now - tp.event_timestamp) / oneDayMs;
      const decayScore = Math.pow(decayFactor, daysSinceTouch);
      return { ...tp, days_since: daysSinceTouch, decay_score: decayScore };
    });

    const totalScore = touchpointsWithDays.reduce((sum, tp) => sum + tp.decay_score, 0);

    return touchpointsWithDays.map(tp => ({
      ...tp,
      credit_percentage: ((tp.decay_score / totalScore) * 100).toFixed(2)
    }));
  }

  uShapeAttribution(touchpoints) {
    if (touchpoints.length === 0) return [];

    const firstTouchWeight = 0.4;
    const lastTouchWeight = 0.4;
    const middleWeight = touchpoints.length > 2 ? 0.2 / (touchpoints.length - 2) : 0;

    return touchpoints.map((tp, index) => {
      if (index === 0) {
        return { ...tp, credit_percentage: 40, role: 'first' };
      } else if (index === touchpoints.length - 1) {
        return { ...tp, credit_percentage: 40, role: 'last' };
      } else {
        return { ...tp, credit_percentage: middleWeight.toFixed(2), role: 'middle' };
      }
    });
  }

  wShapeAttribution(touchpoints) {
    if (touchpoints.length === 0) return [];

    const firstTouchWeight = 0.3;
    const lastTouchWeight = 0.3;
    const middleWeights = touchpoints.length > 2 ? 0.4 / 2 : 0; // 2 assist points

    return touchpoints.map((tp, index) => {
      const pos = index + 1;
      const total = touchpoints.length;

      if (pos === 1) {
        return { ...tp, credit_percentage: 30, role: 'first' };
      } else if (pos === total) {
        return { ...tp, credit_percentage: 30, role: 'last' };
      } else if (pos === Math.floor(total / 2)) {
        return { ...tp, credit_percentage: 20, role: 'middle_assist_1' };
      } else {
        return { ...tp, credit_percentage: middleWeights.toFixed(2), role: 'middle_assist_2' };
      }
    });
  }

  async dataDrivenAttribution(touchpoints, userJourneyHistory) {
    // Simplified data-driven attribution
    // In production, this would analyze historical conversion data

    const channelWeights = await this.calculateChannelWeights(touchpoints, userJourneyHistory);
    const positionWeights = await this.calculatePositionWeights(touchpoints, userJourneyHistory);

    return touchpoints.map((tp, index) => {
      const baseScore = 100 / touchpoints.length;
      const channelWeight = channelWeights[tp.utm_source] || 1;
      const positionWeight = positionWeights[index] || 1;

      const score = baseScore * channelWeight * positionWeight;

      return {
        ...tp,
        credit_percentage: score.toFixed(2),
        channel_weight: channelWeight,
        position_weight: positionWeight
      };
    });
  }

  async calculateChannelWeights(touchpoints, history) {
    // Simplified - in production, analyze historical data
    const channels = {};
    touchpoints.forEach(tp => {
      channels[tp.utm_source] = (channels[tp.utm_source] || 0) + 1;
    });

    const total = Object.values(channels).reduce((a, b) => a + b, 0);
    const weights = {};
    Object.entries(channels).forEach(([channel, count]) => {
      weights[channel] = (count / total) * touchpoints.length;
    });

    return weights;
  }

  async calculatePositionWeights(touchpoints, history) {
    // Simplified - in production, analyze historical position conversion rates
    const weights = {};
    for (let i = 0; i < touchpoints.length; i++) {
      weights[i] = 1;
    }
    return weights;
  }

  /**
   * Chunk array into smaller arrays
   * @param {Array} array - Array to chunk
   * @param {number} size - Chunk size
   * @returns {Array} Array of chunks
   */
  chunkArray(array, size) {
    const chunks = [];
    for (let i = 0; i < array.length; i += size) {
      chunks.push(array.slice(i, i + size));
    }
    return chunks;
  }
}

// Global batch processor instance
let batchProcessor = null;
```

---

## 📊 Profileamento de Latência

### Performance Monitoring

```typescript
/**
 * Latency Profiler
 * Monitors and tracks performance metrics
 */
class LatencyProfiler {
  constructor() {
    this.metrics = {
      requests: [],
      queries: [],
      cacheOps: [],
      externalAPIs: []
    };

    this.thresholds = {
      request: { warning: 100, error: 200 },
      query: { warning: 50, error: 100 },
      cache: { warning: 10, error: 20 },
      external: { warning: 500, error: 2000 }
    };
  }

  /**
   * Start profiling a request
   * @param {string} requestId - Request ID
   * @param {string} endpoint - Endpoint being accessed
   */
  startRequest(requestId, endpoint) {
    this.metrics.requests.push({
      id: requestId,
      endpoint: endpoint,
      startTime: performance.now(),
      stages: []
    });
  }

  /**
   * End profiling a request
   * @param {string} requestId - Request ID
   * @param {object} metadata - Additional metadata
   */
  endRequest(requestId, metadata = {}) {
    const request = this.metrics.requests.find(r => r.id === requestId);
    if (!request) return;

    request.endTime = performance.now();
    request.duration = request.endTime - request.startTime;
    request.metadata = metadata;

    // Log if over threshold
    if (request.duration > this.thresholds.request.error) {
      console.error(`[Latency] CRITICAL: ${request.duration.toFixed(2)}ms - ${request.endpoint}`);
    } else if (request.duration > this.thresholds.request.warning) {
      console.warn(`[Latency] WARNING: ${request.duration.toFixed(2)}ms - ${request.endpoint}`);
    }
  }

  /**
   * Profile a D1 query
   * @param {string} requestId - Request ID
   * @param {string} query - SQL query
   * @returns {Function} Function to call when query completes
   */
  profileQuery(requestId, query) {
    const startTime = performance.now();

    return () => {
      const duration = performance.now() - startTime;

      this.metrics.queries.push({
        requestId: requestId,
        query: query.substring(0, 100),
        duration: duration,
        timestamp: Date.now()
      });

      if (duration > this.thresholds.query.error) {
        console.error(`[Query Latency] CRITICAL: ${duration.toFixed(2)}ms - ${query.substring(0, 50)}...`);
      } else if (duration > this.thresholds.query.warning) {
        console.warn(`[Query Latency] WARNING: ${duration.toFixed(2)}ms - ${query.substring(0, 50)}...`);
      }
    };
  }

  /**
   * Profile a cache operation
   * @param {string} requestId - Request ID
   * @param {string} operation - Cache operation (get, set, delete)
   * @param {string} layer - Cache layer (L1, L2)
   * @returns {Function} Function to call when operation completes
   */
  profileCache(requestId, operation, layer) {
    const startTime = performance.now();

    return () => {
      const duration = performance.now() - startTime;

      this.metrics.cacheOps.push({
        requestId: requestId,
        operation: operation,
        layer: layer,
        duration: duration,
        timestamp: Date.now()
      });

      if (duration > this.thresholds.cache.error) {
        console.error(`[Cache Latency] CRITICAL: ${layer} ${operation} - ${duration.toFixed(2)}ms`);
      }
    };
  }

  /**
   * Profile an external API call
   * @param {string} requestId - Request ID
   * @param {string} api - API name
   * @returns {Function} Function to call when API call completes
   */
  profileExternalAPI(requestId, api) {
    const startTime = performance.now();

    return () => {
      const duration = performance.now() - startTime;

      this.metrics.externalAPIs.push({
        requestId: requestId,
        api: api,
        duration: duration,
        timestamp: Date.now()
      });

      if (duration > this.thresholds.external.error) {
        console.error(`[External API Latency] CRITICAL: ${api} - ${duration.toFixed(2)}ms`);
      } else if (duration > this.thresholds.external.warning) {
        console.warn(`[External API Latency] WARNING: ${api} - ${duration.toFixed(2)}ms`);
      }
    };
  }

  /**
   * Get performance summary
   * @returns {object} Performance summary
   */
  getSummary() {
    const summary = {};

    // Request metrics
    const completedRequests = this.metrics.requests.filter(r => r.duration);
    summary.requests = {
      total: completedRequests.length,
      avg: this.average(completedRequests.map(r => r.duration)),
      p50: this.percentile(completedRequests.map(r => r.duration), 50),
      p95: this.percentile(completedRequests.map(r => r.duration), 95),
      p99: this.percentile(completedRequests.map(r => r.duration), 99),
      max: Math.max(...completedRequests.map(r => r.duration), 0)
    };

    // Query metrics
    summary.queries = {
      total: this.metrics.queries.length,
      avg: this.average(this.metrics.queries.map(q => q.duration)),
      p95: this.percentile(this.metrics.queries.map(q => q.duration), 95),
      max: Math.max(...this.metrics.queries.map(q => q.duration), 0)
    };

    // Cache metrics
    const l1Ops = this.metrics.cacheOps.filter(o => o.layer === 'L1');
    const l2Ops = this.metrics.cacheOps.filter(o => o.layer === 'L2');

    summary.cache = {
      l1: {
        total: l1Ops.length,
        avg: this.average(l1Ops.map(o => o.duration)),
        hitRate: this.calculateHitRate(l1Ops)
      },
      l2: {
        total: l2Ops.length,
        avg: this.average(l2Ops.map(o => o.duration)),
        hitRate: this.calculateHitRate(l2Ops)
      }
    };

    // External API metrics
    summary.external = {
      total: this.metrics.externalAPIs.length,
      avg: this.average(this.metrics.externalAPIs.map(a => a.duration)),
      p95: this.percentile(this.metrics.externalAPIs.map(a => a.duration), 95),
      byAPI: this.groupByAPI()
    };

    return summary;
  }

  /**
   * Calculate average of array
   * @param {number[]} arr - Array of numbers
   * @returns {number} Average
   */
  average(arr) {
    if (arr.length === 0) return 0;
    return arr.reduce((a, b) => a + b, 0) / arr.length;
  }

  /**
   * Calculate percentile of array
   * @param {number[]} arr - Array of numbers
   * @param {number} p - Percentile (0-100)
   * @returns {number} Percentile value
   */
  percentile(arr, p) {
    if (arr.length === 0) return 0;
    const sorted = arr.sort((a, b) => a - b);
    const index = Math.ceil((p / 100) * sorted.length) - 1;
    return sorted[index];
  }

  /**
   * Calculate cache hit rate
   * @param {Array} ops - Cache operations
   * @returns {number} Hit rate percentage
   */
  calculateHitRate(ops) {
    const hits = ops.filter(o => o.operation === 'get').length;
    const total = ops.length;
    return total > 0 ? ((hits / total) * 100).toFixed(2) + '%' : '0%';
  }

  /**
   * Group external API calls by API
   * @returns {object} Grouped metrics
   */
  groupByAPI() {
    const grouped = {};
    this.metrics.externalAPIs.forEach(call => {
      if (!grouped[call.api]) {
        grouped[call.api] = { total: 0, durations: [] };
      }
      grouped[call.api].total++;
      grouped[call.api].durations.push(call.duration);
    });

    Object.keys(grouped).forEach(api => {
      grouped[api].avg = this.average(grouped[api].durations);
      grouped[api].p95 = this.percentile(grouped[api].durations, 95);
    });

    return grouped;
  }

  /**
   * Clear all metrics
   */
  clear() {
    this.metrics = {
      requests: [],
      queries: [],
      cacheOps: [],
      externalAPIs: []
    };
  }
}

// Global latency profiler instance
let latencyProfiler = new LatencyProfiler();
```

---

## 🔧 Endpoints de Monitoramento de Performance

### Worker API Endpoints

```typescript
/**
 * Performance Monitoring Endpoints
 */
export default {
  async fetch(request, env, ctx) {
    // Initialize components
    if (!cacheManager) cacheManager = new CacheManager(env);
    if (!queryOptimizer) queryOptimizer = new QueryOptimizer(env.DB);
    if (!batchProcessor) batchProcessor = new BatchAttributionProcessor(cacheManager, queryOptimizer);

    const url = new URL(request.url);
    const path = url.pathname;

    // Performance monitoring endpoints
    if (path === '/api/performance/stats') {
      return handlePerformanceStats(env);
    }

    if (path === '/api/performance/cache-stats') {
      return handleCacheStats(env);
    }

    if (path === '/api/performance/query-stats') {
      return handleQueryStats(env);
    }

    if (path === '/api/performance/latency-summary') {
      return handleLatencySummary(env);
    }

    if (path === '/api/performance/cache-invalidate') {
      return handleCacheInvalidate(request, env);
    }

    // ... other endpoints

    return new Response('Not Found', { status: 404 });
  }
};

/**
 * Handle /api/performance/stats - Overall performance statistics
 */
async function handlePerformanceStats(env) {
  const summary = latencyProfiler.getSummary();

  return new Response(JSON.stringify({
    success: true,
    data: {
      performance: summary,
      timestamp: new Date().toISOString()
    }
  }), {
    headers: { 'Content-Type': 'application/json' }
  });
}

/**
 * Handle /api/performance/cache-stats - Cache statistics
 */
async function handleCacheStats(env) {
  const stats = cacheManager ? cacheManager.getStats() : null;

  return new Response(JSON.stringify({
    success: true,
    data: {
      cache: stats,
      timestamp: new Date().toISOString()
    }
  }), {
    headers: { 'Content-Type': 'application/json' }
  });
}

/**
 * Handle /api/performance/query-stats - Query statistics
 */
async function handleQueryStats(env) {
  const queryMetrics = latencyProfiler.metrics.queries;

  return new Response(JSON.stringify({
    success: true,
    data: {
      queries: {
        total: queryMetrics.length,
        avg: queryMetrics.length > 0
          ? queryMetrics.reduce((a, b) => a + b.duration, 0) / queryMetrics.length
          : 0,
        slowQueries: queryMetrics.filter(q => q.duration > 100),
        timestamp: new Date().toISOString()
      }
    }
  }), {
    headers: { 'Content-Type': 'application/json' }
  });
}

/**
 * Handle /api/performance/latency-summary - Latency summary
 */
async function handleLatencySummary(env) {
  const summary = latencyProfiler.getSummary();

  return new Response(JSON.stringify({
    success: true,
    data: {
      latency: {
        requests: summary.requests,
        queries: summary.queries,
        cache: summary.cache,
        externalAPIs: summary.external
      },
      timestamp: new Date().toISOString()
    }
  }), {
    headers: { 'Content-Type': 'application/json' }
  });
}

/**
 * Handle /api/performance/cache-invalidate - Cache invalidation
 */
async function handleCacheInvalidate(request, env) {
  if (request.method !== 'POST') {
    return new Response('Method Not Allowed', { status: 405 });
  }

  try {
    const body = await request.json();
    const { prefix, keys } = body;

    if (prefix) {
      await cacheManager.invalidateByPrefix(prefix);
    } else if (keys && Array.isArray(keys)) {
      for (const key of keys) {
        await cacheManager.delete(key);
      }
    } else {
      return new Response(JSON.stringify({
        success: false,
        error: 'Must provide either prefix or keys'
      }), {
        status: 400,
        headers: { 'Content-Type': 'application/json' }
      });
    }

    return new Response(JSON.stringify({
      success: true,
      message: 'Cache invalidated successfully',
      timestamp: new Date().toISOString()
    }), {
      headers: { 'Content-Type': 'application/json' }
    });
  } catch (error) {
    return new Response(JSON.stringify({
      success: false,
      error: error.message
    }), {
      status: 500,
      headers: { 'Content-Type': 'application/json' }
    });
  }
}
```

---

## 📋 Resumo de Implementação

### Componentes Criados

1. **CacheManager** - Gerenciador de caching multi-camada (L1 + L2 + L3)
2. **QueryOptimizer** - Otimizador de queries com cache e índices
3. **BatchAttributionProcessor** - Processamento em lote de atribuições
4. **LatencyProfiler** - Monitoramento de latência em tempo real

### Endpoints de Monitoramento

| Endpoint | Método | Descrição |
|----------|--------|-----------|
| `/api/performance/stats` | GET | Estatísticas gerais de performance |
| `/api/performance/cache-stats` | GET | Estatísticas de cache (L1/L2) |
| `/api/performance/query-stats` | GET | Estatísticas de queries |
| `/api/performance/latency-summary` | GET | Resumo de latência (P50, P95, P99) |
| `/api/performance/cache-invalidate` | POST | Invalidação de cache |

### Melhorias de Performance

- **Cache Hit Rate**: > 95% (L1 + L2)
- **P95 Latency**: < 100ms (tracking), < 500ms (attribution)
- **Query Time**: < 50ms (queries otimizadas)
- **Memory Usage**: < 128MB (workers)
- **CPU Time**: < 50ms (workers)

---

## 🔗 Integração com Outros Agentes

- **attribution-agent.md**: Usa `BatchAttributionProcessor` para processar múltiplas atribuições em paralelo
- **security-enterprise-agent.md**: Usa `CacheManager` para cache de configurações de segurança
- **master-orchestrator.md**: Usa `LatencyProfiler` para monitorar performance de toda a pipeline

---

## ✅ Checklist de Implementação

- [x] Implementar L1 Memory Cache (request-scoped)
- [x] Implementar L2 KV Cache (global edge cache)
- [x] Implementar CacheManager com fallback L1 → L2 → D1
- [x] Criar índices otimizados para D1
- [x] Implementar QueryOptimizer com cache de queries
- [x] Implementar BatchAttributionProcessor para processamento em lote
- [x] Implementar LatencyProfiler com monitoramento em tempo real
- [x] Criar endpoints de monitoramento de performance
- [x] Implementar invalidação de cache por prefixo
- [x] Configurar TTLs específicos por tipo de cache

---

## 📚 Referências

- [Cloudflare Workers Performance Best Practices](https://developers.cloudflare.com/workers/)
- [Cloudflare KV Caching](https://developers.cloudflare.com/workers/runtime-apis/kv/)
- [Cloudflare D1 Query Optimization](https://developers.cloudflare.com/d1/)
- [SQLite Index Optimization](https://www.sqlite.org/queryplanner.html)

---

*Performance Optimization Enterprise Agent v1.0.0 - CDP Edge Quantum Tier*
