cdp-edge 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/README.md +324 -0
  2. package/bin/cdp-edge.js +71 -0
  3. package/contracts/agent-versions.json +679 -0
  4. package/contracts/api-versions.json +372 -0
  5. package/contracts/types.ts +81 -0
  6. package/dist/commands/analyze.js +52 -0
  7. package/dist/commands/infra.js +54 -0
  8. package/dist/commands/install.js +191 -0
  9. package/dist/commands/server.js +174 -0
  10. package/dist/commands/setup.js +355 -0
  11. package/dist/commands/validate.js +248 -0
  12. package/dist/index.js +12 -0
  13. package/dist/sdk/cdpTrack.js +2095 -0
  14. package/dist/sdk/cdpTrack.min.js +64 -0
  15. package/dist/sdk/install-snippet.html +10 -0
  16. package/docs/CI-CD-SETUP.md +217 -0
  17. package/docs/events-reference.md +359 -0
  18. package/docs/installation.md +155 -0
  19. package/docs/quick-start.md +185 -0
  20. package/docs/sdk-reference.md +371 -0
  21. package/docs/whatsapp-ctwa.md +210 -0
  22. package/extracted-skill/tracking-events-generator/INDEX.md +94 -0
  23. package/extracted-skill/tracking-events-generator/INSTALACAO-CDPEDGE.md +58 -0
  24. package/extracted-skill/tracking-events-generator/INTEGRACAO-COMPLETA.md +683 -0
  25. package/extracted-skill/tracking-events-generator/MELHORIAS-IMPLEMENTADAS.md +513 -0
  26. package/extracted-skill/tracking-events-generator/Premium-Tracking-Intelligence-Resumo.md +333 -0
  27. package/extracted-skill/tracking-events-generator/SKILL.md +257 -0
  28. package/extracted-skill/tracking-events-generator/advanced-matching.js +364 -0
  29. package/extracted-skill/tracking-events-generator/agents/ab-ltv-agent.md +196 -0
  30. package/extracted-skill/tracking-events-generator/agents/ab-testing-agent.md +54 -0
  31. package/extracted-skill/tracking-events-generator/agents/attribution-agent.md +1304 -0
  32. package/extracted-skill/tracking-events-generator/agents/bidding-agent.md +347 -0
  33. package/extracted-skill/tracking-events-generator/agents/bing-agent.md +66 -0
  34. package/extracted-skill/tracking-events-generator/agents/browser-tracking.md +364 -0
  35. package/extracted-skill/tracking-events-generator/agents/code-guardian-agent.md +149 -0
  36. package/extracted-skill/tracking-events-generator/agents/compliance-agent.md +2097 -0
  37. package/extracted-skill/tracking-events-generator/agents/crm-integration-agent.md +1459 -0
  38. package/extracted-skill/tracking-events-generator/agents/dashboard-agent.md +456 -0
  39. package/extracted-skill/tracking-events-generator/agents/database-agent.md +668 -0
  40. package/extracted-skill/tracking-events-generator/agents/debug-agent.md +1455 -0
  41. package/extracted-skill/tracking-events-generator/agents/devops-agent.md +232 -0
  42. package/extracted-skill/tracking-events-generator/agents/domain-setup-agent.md +238 -0
  43. package/extracted-skill/tracking-events-generator/agents/email-agent.md +88 -0
  44. package/extracted-skill/tracking-events-generator/agents/fingerprint-agent.md +257 -0
  45. package/extracted-skill/tracking-events-generator/agents/fraud-detection-agent.md +143 -0
  46. package/extracted-skill/tracking-events-generator/agents/google-agent.md +235 -0
  47. package/extracted-skill/tracking-events-generator/agents/intelligence-agent.md +525 -0
  48. package/extracted-skill/tracking-events-generator/agents/lead-scoring-agent.md +282 -0
  49. package/extracted-skill/tracking-events-generator/agents/linkedin-agent.md +173 -0
  50. package/extracted-skill/tracking-events-generator/agents/localization-agent.md +55 -0
  51. package/extracted-skill/tracking-events-generator/agents/ltv-predictor-agent.md +59 -0
  52. package/extracted-skill/tracking-events-generator/agents/master-feedback-loop.md +960 -0
  53. package/extracted-skill/tracking-events-generator/agents/master-orchestrator.md +2154 -0
  54. package/extracted-skill/tracking-events-generator/agents/match-quality-agent.md +304 -0
  55. package/extracted-skill/tracking-events-generator/agents/memory-agent.json +25 -0
  56. package/extracted-skill/tracking-events-generator/agents/memory-agent.md +878 -0
  57. package/extracted-skill/tracking-events-generator/agents/meta-agent.md +118 -0
  58. package/extracted-skill/tracking-events-generator/agents/ml-clustering-agent.md +749 -0
  59. package/extracted-skill/tracking-events-generator/agents/page-analyzer.md +272 -0
  60. package/extracted-skill/tracking-events-generator/agents/performance-agent.md +1167 -0
  61. package/extracted-skill/tracking-events-generator/agents/performance-optimization-agent.md +1442 -0
  62. package/extracted-skill/tracking-events-generator/agents/pinterest-agent.md +318 -0
  63. package/extracted-skill/tracking-events-generator/agents/premium-tracking-intelligence-agent.md +849 -0
  64. package/extracted-skill/tracking-events-generator/agents/r2-setup-agent.md +258 -0
  65. package/extracted-skill/tracking-events-generator/agents/reddit-agent.md +321 -0
  66. package/extracted-skill/tracking-events-generator/agents/security-enterprise-agent.md +1861 -0
  67. package/extracted-skill/tracking-events-generator/agents/server-tracking.md +1188 -0
  68. package/extracted-skill/tracking-events-generator/agents/spotify-agent.md +391 -0
  69. package/extracted-skill/tracking-events-generator/agents/tiktok-agent.md +182 -0
  70. package/extracted-skill/tracking-events-generator/agents/tracking-plan-agent.md +459 -0
  71. package/extracted-skill/tracking-events-generator/agents/utm-agent.md +322 -0
  72. package/extracted-skill/tracking-events-generator/agents/validator-agent.md +271 -0
  73. package/extracted-skill/tracking-events-generator/agents/webhook-agent.md +177 -0
  74. package/extracted-skill/tracking-events-generator/agents/whatsapp-agent.md +129 -0
  75. package/extracted-skill/tracking-events-generator/agents/whatsapp-ctwa-setup-agent.md +707 -0
  76. package/extracted-skill/tracking-events-generator/agents/youtube-agent.md +537 -0
  77. package/extracted-skill/tracking-events-generator/anti-blocking.js +285 -0
  78. package/extracted-skill/tracking-events-generator/cdpTrack.js +640 -0
  79. package/extracted-skill/tracking-events-generator/contracts/api-versions.json +372 -0
  80. package/extracted-skill/tracking-events-generator/docs/guia-cloudflare-iniciante.md +107 -0
  81. package/extracted-skill/tracking-events-generator/engagement-scoring.js +226 -0
  82. package/extracted-skill/tracking-events-generator/evals/evals.json +235 -0
  83. package/extracted-skill/tracking-events-generator/integration-test.js +497 -0
  84. package/extracted-skill/tracking-events-generator/knowledge-base.md +3066 -0
  85. package/extracted-skill/tracking-events-generator/micro-events.js +992 -0
  86. package/extracted-skill/tracking-events-generator/models/captura-de-lead.md +78 -0
  87. package/extracted-skill/tracking-events-generator/models/captura-lead-evento-externo.md +99 -0
  88. package/extracted-skill/tracking-events-generator/models/checkout-proprio.md +111 -0
  89. package/extracted-skill/tracking-events-generator/models/lancamento-imobiliario.md +344 -0
  90. package/extracted-skill/tracking-events-generator/models/multi-step-checkout.md +672 -0
  91. package/extracted-skill/tracking-events-generator/models/pagina-obrigado.md +55 -0
  92. package/extracted-skill/tracking-events-generator/models/pinterest/conversions-api-template.js +144 -0
  93. package/extracted-skill/tracking-events-generator/models/pinterest/event-mappings.json +48 -0
  94. package/extracted-skill/tracking-events-generator/models/pinterest/tag-template.js +28 -0
  95. package/extracted-skill/tracking-events-generator/models/quiz-funnel.md +132 -0
  96. package/extracted-skill/tracking-events-generator/models/reddit/conversions-api-template.js +205 -0
  97. package/extracted-skill/tracking-events-generator/models/reddit/event-mappings.json +56 -0
  98. package/extracted-skill/tracking-events-generator/models/reddit/pixel-template.js +19 -0
  99. package/extracted-skill/tracking-events-generator/models/scenarios/behavior-engine.js +425 -0
  100. package/extracted-skill/tracking-events-generator/models/scenarios/real-estate-logic.md +50 -0
  101. package/extracted-skill/tracking-events-generator/models/scenarios/sales-page-logic.md +50 -0
  102. package/extracted-skill/tracking-events-generator/models/trafego-direto.md +582 -0
  103. package/extracted-skill/tracking-events-generator/models/webinar-registration.md +63 -0
  104. package/extracted-skill/tracking-events-generator/route-intent-capture.js +222 -0
  105. package/extracted-skill/tracking-events-generator/tracking.config.js +46 -0
  106. package/extracted-skill/tracking-events-generator/walkthrough.md +26 -0
  107. package/package.json +89 -0
  108. package/scripts/build-sdk.js +106 -0
  109. package/server-edge-tracker/.client.env.example +14 -0
  110. package/server-edge-tracker/INSTALAR.md +527 -0
  111. package/server-edge-tracker/SEGMENTATION-DOCS.md +513 -0
  112. package/server-edge-tracker/config/utm-mapping.json +64 -0
  113. package/server-edge-tracker/deploy-client.cjs +76 -0
  114. package/server-edge-tracker/index.ts +1164 -0
  115. package/server-edge-tracker/migrate-new-db.sql +137 -0
  116. package/server-edge-tracker/migrate-v2.sql +16 -0
  117. package/server-edge-tracker/migrate-v3.sql +6 -0
  118. package/server-edge-tracker/migrate-v4.sql +18 -0
  119. package/server-edge-tracker/migrate-v5.sql +17 -0
  120. package/server-edge-tracker/migrate-v6.sql +24 -0
  121. package/server-edge-tracker/migrate-v7.sql +64 -0
  122. package/server-edge-tracker/migrate.sql +111 -0
  123. package/server-edge-tracker/modules/db.ts +702 -0
  124. package/server-edge-tracker/modules/dispatch/ga4.ts +72 -0
  125. package/server-edge-tracker/modules/dispatch/meta.ts +143 -0
  126. package/server-edge-tracker/modules/dispatch/platforms.ts +255 -0
  127. package/server-edge-tracker/modules/dispatch/tiktok.ts +107 -0
  128. package/server-edge-tracker/modules/dispatch/whatsapp.ts +279 -0
  129. package/server-edge-tracker/modules/intelligence.ts +589 -0
  130. package/server-edge-tracker/modules/ml/bidding.ts +247 -0
  131. package/server-edge-tracker/modules/ml/fraud.ts +302 -0
  132. package/server-edge-tracker/modules/ml/logistic.ts +226 -0
  133. package/server-edge-tracker/modules/ml/ltv.ts +531 -0
  134. package/server-edge-tracker/modules/ml/matchquality.ts +232 -0
  135. package/server-edge-tracker/modules/ml/quiz.ts +343 -0
  136. package/server-edge-tracker/modules/ml/roas.ts +255 -0
  137. package/server-edge-tracker/modules/ml/segmentation.ts +407 -0
  138. package/server-edge-tracker/modules/nurture.ts +257 -0
  139. package/server-edge-tracker/modules/utils.ts +311 -0
  140. package/server-edge-tracker/modules/utm/utm-enricher.ts +231 -0
  141. package/server-edge-tracker/schema-ab-ltv.sql +97 -0
  142. package/server-edge-tracker/schema-bidding.sql +86 -0
  143. package/server-edge-tracker/schema-fraud.sql +90 -0
  144. package/server-edge-tracker/schema-indexes.sql +67 -0
  145. package/server-edge-tracker/schema-ltv-feedback.sql +11 -0
  146. package/server-edge-tracker/schema-quiz.sql +52 -0
  147. package/server-edge-tracker/schema-sales-engine.sql +113 -0
  148. package/server-edge-tracker/schema-segmentation.sql +219 -0
  149. package/server-edge-tracker/schema-utm.sql +82 -0
  150. package/server-edge-tracker/schema.sql +265 -0
  151. package/server-edge-tracker/types.ts +258 -0
  152. package/server-edge-tracker/wrangler.toml +136 -0
  153. package/templates/afiliado-sem-landing.md +312 -0
  154. package/templates/captura-de-lead.md +78 -0
  155. package/templates/captura-lead-evento-externo.md +99 -0
  156. package/templates/checkout-proprio.md +111 -0
  157. package/templates/install/.claude/commands/cdp.md +1 -0
  158. package/templates/install/CLAUDE.md +65 -0
  159. package/templates/lancamento-imobiliario.md +344 -0
  160. package/templates/linkedin/tag-template.js +46 -0
  161. package/templates/multi-step-checkout.md +672 -0
  162. package/templates/pagina-obrigado.md +55 -0
  163. package/templates/pinterest/conversions-api-template.js +144 -0
  164. package/templates/pinterest/event-mappings.json +48 -0
  165. package/templates/pinterest/tag-template.js +28 -0
  166. package/templates/quiz-funnel.md +132 -0
  167. package/templates/reddit/conversions-api-template.js +205 -0
  168. package/templates/reddit/event-mappings.json +56 -0
  169. package/templates/reddit/pixel-template.js +19 -0
  170. package/templates/scenarios/behavior-engine.js +425 -0
  171. package/templates/scenarios/real-estate-logic.md +50 -0
  172. package/templates/scenarios/sales-page-logic.md +50 -0
  173. package/templates/spotify/pixel-template.js +46 -0
  174. package/templates/trafego-direto.md +582 -0
  175. package/templates/vsl-page.md +292 -0
  176. package/templates/webinar-registration.md +63 -0
@@ -0,0 +1,1442 @@
1
+ ---
2
+ name: performance-optimization-agent
3
+ description: Performance Optimization Enterprise Agent - Caching, Query Optimization, Latency Profiling for Cloudflare Workers + D1
4
+ type: agent
5
+ persona: Performance Engineer specializing in edge computing optimization, distributed caching strategies, and database query optimization
6
+ version: "1.0.0"
7
+ ---
8
+
9
+ # Performance Optimization Enterprise Agent
10
+
11
+ > **ESCOPO DESTE AGENTE:** Otimização ativa de performance — caching, queries, batching.
12
+ > Para monitoramento passivo (métricas, alertas, dashboards), ver: **performance-agent.md**
13
+ >
14
+ > | Este agente faz | performance-agent faz |
15
+ > |---|---|
16
+ > | Estratégias de caching L1/L2/L3 | Medir latência e throughput |
17
+ > | Otimização de queries D1 e indexação | Alertas de degradação de SLA |
18
+ > | Batch processing e pipeline tuning | Health checks e dashboards |
19
+ > | Profiling de Workers e CPU optimization | Relatórios de performance |
20
+
21
+ ## 🚀 Visão Geral
22
+
23
+ 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.
24
+
25
+ ---
26
+
27
+ ## 📊 Arquitetura de Performance
28
+
29
+ ### 3-Camadas de Caching
30
+
31
+ ```
32
+ ┌─────────────────────────────────────────────────────────────┐
33
+ │ L1: Memory Cache │
34
+ │ (In-Memory, Request Lifetime) │
35
+ │ - TTL: Request duration │
36
+ │ - Hit Rate: ~85% │
37
+ │ - Use: Session data, config lookup │
38
+ └─────────────────────────────────────────────────────────────┘
39
+
40
+ ┌─────────────────────────────────────────────────────────────┐
41
+ │ L2: KV Cache │
42
+ │ (Global, Distributed Edge) │
43
+ │ - TTL: 5-60 minutes │
44
+ │ - Hit Rate: ~12% │
45
+ │ - Use: Attribution data, channel metrics │
46
+ └─────────────────────────────────────────────────────────────┘
47
+
48
+ ┌─────────────────────────────────────────────────────────────┐
49
+ │ L3: D1 Database │
50
+ │ (SQLite at Edge, Persistent) │
51
+ │ - TTL: Permanent │
52
+ │ - Use: User journeys, audit logs, security data │
53
+ └─────────────────────────────────────────────────────────────┘
54
+ ```
55
+
56
+ ---
57
+
58
+ ## 🎯 Métricas de Performance
59
+
60
+ ### KPIs Monitorados
61
+
62
+ | Métrica | Target | Alert |
63
+ |---------|--------|-------|
64
+ | **Cache Hit Rate (L1+L2)** | ≥ 95% | < 85% |
65
+ | **P95 Latency (Tracking)** | < 100ms | > 200ms |
66
+ | **P95 Latency (Attribution)** | < 500ms | > 1000ms |
67
+ | **Query Time (D1)** | < 50ms | > 100ms |
68
+ | **Queue Processing Time** | < 500ms | > 2000ms |
69
+ | **Memory Usage (Worker)** | < 128MB | > 128MB |
70
+ | **CPU Time (Worker)** | < 50ms | > 150ms |
71
+
72
+ ---
73
+
74
+ ## 💾 Caching Multi-Layer
75
+
76
+ ### L1: Memory Cache (Request-Scoped)
77
+
78
+ ```typescript
79
+ /**
80
+ * L1 Memory Cache - In-request cache with automatic expiration
81
+ */
82
+ class L1Cache {
83
+ constructor() {
84
+ this.cache = new Map();
85
+ this.stats = {
86
+ hits: 0,
87
+ misses: 0,
88
+ sets: 0,
89
+ deletes: 0
90
+ };
91
+ }
92
+
93
+ /**
94
+ * Get value from L1 cache
95
+ * @param {string} key - Cache key
96
+ * @returns {any|undefined} Cached value or undefined if not found/expired
97
+ */
98
+ get(key) {
99
+ const entry = this.cache.get(key);
100
+ if (!entry) {
101
+ this.stats.misses++;
102
+ return undefined;
103
+ }
104
+
105
+ // Check expiration
106
+ if (entry.expiry < Date.now()) {
107
+ this.cache.delete(key);
108
+ this.stats.misses++;
109
+ return undefined;
110
+ }
111
+
112
+ this.stats.hits++;
113
+ return entry.value;
114
+ }
115
+
116
+ /**
117
+ * Set value in L1 cache with optional TTL (default: request lifetime)
118
+ * @param {string} key - Cache key
119
+ * @param {any} value - Value to cache
120
+ * @param {number} ttlMs - TTL in milliseconds (optional)
121
+ */
122
+ set(key, value, ttlMs = null) {
123
+ const expiry = ttlMs ? Date.now() + ttlMs : Infinity;
124
+ this.cache.set(key, { value, expiry, createdAt: Date.now() });
125
+ this.stats.sets++;
126
+ }
127
+
128
+ /**
129
+ * Delete value from L1 cache
130
+ * @param {string} key - Cache key
131
+ */
132
+ delete(key) {
133
+ this.cache.delete(key);
134
+ this.stats.deletes++;
135
+ }
136
+
137
+ /**
138
+ * Clear all L1 cache entries
139
+ */
140
+ clear() {
141
+ this.cache.clear();
142
+ }
143
+
144
+ /**
145
+ * Get cache statistics
146
+ * @returns {object} Cache statistics
147
+ */
148
+ getStats() {
149
+ const totalRequests = this.stats.hits + this.stats.misses;
150
+ const hitRate = totalRequests > 0 ? (this.stats.hits / totalRequests) * 100 : 0;
151
+
152
+ return {
153
+ ...this.stats,
154
+ hitRate: hitRate.toFixed(2) + '%',
155
+ cacheSize: this.cache.size
156
+ };
157
+ }
158
+ }
159
+
160
+ // Global L1 cache instance (request-scoped)
161
+ let l1Cache = new L1Cache();
162
+ ```
163
+
164
+ ### L2: KV Cache (Global Edge Cache)
165
+
166
+ ```typescript
167
+ /**
168
+ * L2 KV Cache - Global distributed cache with automatic invalidation
169
+ */
170
+ class L2Cache {
171
+ constructor(env) {
172
+ this.kv = env.GEO_CACHE; // Cloudflare KV namespace
173
+ this.stats = {
174
+ hits: 0,
175
+ misses: 0,
176
+ sets: 0,
177
+ deletes: 0
178
+ };
179
+
180
+ // Cache TTLs (configurable)
181
+ this.ttls = {
182
+ attribution: 3600, // 1 hour
183
+ channelMetrics: 1800, // 30 minutes
184
+ userJourneys: 300, // 5 minutes
185
+ securityConfig: 900, // 15 minutes
186
+ lookupData: 600, // 10 minutes
187
+ default: 600 // 10 minutes
188
+ };
189
+ }
190
+
191
+ /**
192
+ * Get value from L2 cache
193
+ * @param {string} key - Cache key
194
+ * @param {string} cacheType - Type of cache (determines TTL)
195
+ * @returns {Promise<any|null>} Cached value or null if not found
196
+ */
197
+ async get(key, cacheType = 'default') {
198
+ try {
199
+ const cached = await this.kv.get(key, { type: 'json' });
200
+
201
+ if (cached === null) {
202
+ this.stats.misses++;
203
+ return null;
204
+ }
205
+
206
+ this.stats.hits++;
207
+ return cached;
208
+ } catch (error) {
209
+ console.error(`[L2 Cache] Error getting ${key}:`, error);
210
+ this.stats.misses++;
211
+ return null;
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Set value in L2 cache with type-based TTL
217
+ * @param {string} key - Cache key
218
+ * @param {any} value - Value to cache
219
+ * @param {string} cacheType - Type of cache (determines TTL)
220
+ * @param {number} ttlMs - Custom TTL override (optional)
221
+ * @returns {Promise<boolean>} Success status
222
+ */
223
+ async set(key, value, cacheType = 'default', ttlMs = null) {
224
+ try {
225
+ const ttl = ttlMs || (this.ttls[cacheType] || this.ttls.default);
226
+
227
+ await this.kv.put(key, JSON.stringify(value), {
228
+ expirationTtl: ttl
229
+ });
230
+
231
+ this.stats.sets++;
232
+ return true;
233
+ } catch (error) {
234
+ console.error(`[L2 Cache] Error setting ${key}:`, error);
235
+ return false;
236
+ }
237
+ }
238
+
239
+ /**
240
+ * Delete value from L2 cache
241
+ * @param {string} key - Cache key
242
+ * @returns {Promise<boolean>} Success status
243
+ */
244
+ async delete(key) {
245
+ try {
246
+ await this.kv.delete(key);
247
+ this.stats.deletes++;
248
+ return true;
249
+ } catch (error) {
250
+ console.error(`[L2 Cache] Error deleting ${key}:`, error);
251
+ return false;
252
+ }
253
+ }
254
+
255
+ /**
256
+ * Delete multiple keys from L2 cache (batch invalidation)
257
+ * @param {string[]} keys - Array of cache keys
258
+ * @returns {Promise<number>} Number of successfully deleted keys
259
+ */
260
+ async deleteMany(keys) {
261
+ let deleted = 0;
262
+ for (const key of keys) {
263
+ if (await this.delete(key)) {
264
+ deleted++;
265
+ }
266
+ }
267
+ return deleted;
268
+ }
269
+
270
+ /**
271
+ * List keys by prefix (for cache invalidation)
272
+ * @param {string} prefix - Key prefix
273
+ * @param {number} limit - Maximum keys to return
274
+ * @returns {Promise<string[]>} Array of keys
275
+ */
276
+ async listKeys(prefix, limit = 100) {
277
+ try {
278
+ const list = await this.kv.list({ prefix, limit });
279
+ return list.keys.map(k => k.name);
280
+ } catch (error) {
281
+ console.error(`[L2 Cache] Error listing keys with prefix ${prefix}:`, error);
282
+ return [];
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Invalidate cache by prefix (bulk invalidation)
288
+ * @param {string} prefix - Key prefix to invalidate
289
+ * @returns {Promise<number>} Number of invalidated keys
290
+ */
291
+ async invalidateByPrefix(prefix) {
292
+ const keys = await this.listKeys(prefix, 1000);
293
+ return await this.deleteMany(keys);
294
+ }
295
+
296
+ /**
297
+ * Get cache statistics
298
+ * @returns {object} Cache statistics
299
+ */
300
+ getStats() {
301
+ const totalRequests = this.stats.hits + this.stats.misses;
302
+ const hitRate = totalRequests > 0 ? (this.stats.hits / totalRequests) * 100 : 0;
303
+
304
+ return {
305
+ ...this.stats,
306
+ hitRate: hitRate.toFixed(2) + '%'
307
+ };
308
+ }
309
+ }
310
+
311
+ // L2 cache instance (environment-scoped)
312
+ let l2Cache = null;
313
+ ```
314
+
315
+ ### Cache Strategy Implementation
316
+
317
+ ```typescript
318
+ /**
319
+ * Multi-Layer Cache Manager
320
+ * Orchestrates L1 and L2 caches with fallback logic
321
+ */
322
+ class CacheManager {
323
+ constructor(env) {
324
+ this.l1 = new L1Cache();
325
+ this.l2 = new L2Cache(env);
326
+ }
327
+
328
+ /**
329
+ * Get value from cache (L1 → L2 → D1 fallback)
330
+ * @param {string} key - Cache key
331
+ * @param {string} cacheType - Type of cache
332
+ * @param {Function} fallback - Fallback function to fetch from D1
333
+ * @returns {Promise<any>} Cached or fetched value
334
+ */
335
+ async get(key, cacheType = 'default', fallback = null) {
336
+ // Try L1 cache first (fastest)
337
+ const l1Value = this.l1.get(key);
338
+ if (l1Value !== undefined) {
339
+ return l1Value;
340
+ }
341
+
342
+ // Try L2 cache (distributed)
343
+ const l2Value = await this.l2.get(key, cacheType);
344
+ if (l2Value !== null) {
345
+ // Promote to L1 cache
346
+ this.l1.set(key, l2Value);
347
+ return l2Value;
348
+ }
349
+
350
+ // Fallback to source (D1)
351
+ if (fallback) {
352
+ const value = await fallback();
353
+
354
+ // Cache in L2 and L1
355
+ await this.l2.set(key, value, cacheType);
356
+ this.l1.set(key, value);
357
+
358
+ return value;
359
+ }
360
+
361
+ return null;
362
+ }
363
+
364
+ /**
365
+ * Set value in cache (L1 + L2)
366
+ * @param {string} key - Cache key
367
+ * @param {any} value - Value to cache
368
+ * @param {string} cacheType - Type of cache
369
+ * @param {number} ttlMs - Custom TTL for L2
370
+ */
371
+ async set(key, value, cacheType = 'default', ttlMs = null) {
372
+ this.l1.set(key, value);
373
+ await this.l2.set(key, value, cacheType, ttlMs);
374
+ }
375
+
376
+ /**
377
+ * Delete value from cache (L1 + L2)
378
+ * @param {string} key - Cache key
379
+ */
380
+ async delete(key) {
381
+ this.l1.delete(key);
382
+ await this.l2.delete(key);
383
+ }
384
+
385
+ /**
386
+ * Invalidate cache by prefix (L2 only - L1 doesn't support prefix)
387
+ * @param {string} prefix - Key prefix
388
+ */
389
+ async invalidateByPrefix(prefix) {
390
+ await this.l2.invalidateByPrefix(prefix);
391
+ }
392
+
393
+ /**
394
+ * Get combined cache statistics
395
+ * @returns {object} Combined cache statistics
396
+ */
397
+ getStats() {
398
+ return {
399
+ l1: this.l1.getStats(),
400
+ l2: this.l2.getStats()
401
+ };
402
+ }
403
+ }
404
+
405
+ // Global cache manager instance
406
+ let cacheManager = null;
407
+ ```
408
+
409
+ ---
410
+
411
+ ## 🗄️ Otimização de Queries D1
412
+
413
+ ### Schema de Índices Otimizados
414
+
415
+ ```sql
416
+ -- User Journeys Table (Optimized for attribution queries)
417
+ CREATE TABLE IF NOT EXISTS user_journeys (
418
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
419
+ user_id TEXT NOT NULL,
420
+ event_id TEXT,
421
+ event_name TEXT NOT NULL,
422
+ utm_source TEXT,
423
+ utm_medium TEXT,
424
+ utm_campaign TEXT,
425
+ utm_term TEXT,
426
+ utm_content TEXT,
427
+ event_timestamp DATETIME NOT NULL,
428
+ position INTEGER,
429
+ conversion_id TEXT,
430
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
431
+ );
432
+
433
+ -- Compound indexes for common query patterns
434
+ CREATE INDEX IF NOT EXISTS idx_user_journeys_user_timestamp
435
+ ON user_journeys(user_id, event_timestamp DESC);
436
+
437
+ CREATE INDEX IF NOT EXISTS idx_user_journeys_conversion
438
+ ON user_journeys(conversion_id, position);
439
+
440
+ CREATE INDEX IF NOT EXISTS idx_user_journeys_utm_source
441
+ ON user_journeys(utm_source, event_timestamp DESC);
442
+
443
+ CREATE INDEX IF NOT EXISTS idx_user_journeys_event_name
444
+ ON user_journeys(event_name, event_timestamp DESC);
445
+
446
+ -- Multi-Touch Attribution Table
447
+ CREATE TABLE IF NOT EXISTS multi_touch_attribution (
448
+ conversion_id TEXT NOT NULL,
449
+ attribution_model TEXT NOT NULL,
450
+ touchpoint_index INTEGER NOT NULL,
451
+ utm_source TEXT,
452
+ credit_percentage REAL NOT NULL,
453
+ role TEXT,
454
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
455
+ PRIMARY KEY (conversion_id, attribution_model, touchpoint_index)
456
+ );
457
+
458
+ -- Index for attribution queries
459
+ CREATE INDEX IF NOT EXISTS idx_attribution_model_conversion
460
+ ON multi_touch_attribution(attribution_model, conversion_id);
461
+
462
+ CREATE INDEX IF NOT EXISTS idx_attribution_source
463
+ ON multi_touch_attribution(utm_source, attribution_model);
464
+
465
+ -- Channel Performance Table (Materialized for fast aggregation)
466
+ CREATE TABLE IF NOT EXISTS channel_performance (
467
+ utm_source TEXT NOT NULL,
468
+ attribution_model TEXT NOT NULL,
469
+ total_attribution REAL NOT NULL,
470
+ total_conversions INTEGER NOT NULL,
471
+ total_value REAL NOT NULL,
472
+ avg_attribution_per_conversion REAL NOT NULL,
473
+ last_updated DATETIME NOT NULL,
474
+ PRIMARY KEY (utm_source, attribution_model)
475
+ );
476
+
477
+ -- Index for performance queries
478
+ CREATE INDEX IF NOT EXISTS idx_channel_performance_model
479
+ ON channel_performance(attribution_model, total_attribution DESC);
480
+
481
+ -- Index for timestamp-based queries
482
+ CREATE INDEX IF NOT EXISTS idx_channel_performance_updated
483
+ ON channel_performance(last_updated DESC);
484
+ ```
485
+
486
+ ### Query Optimization Patterns
487
+
488
+ ```typescript
489
+ /**
490
+ * Optimized Query Builder for D1
491
+ */
492
+ class QueryOptimizer {
493
+ constructor(db) {
494
+ this.db = db;
495
+ this.queryCache = new Map();
496
+ }
497
+
498
+ /**
499
+ * Execute query with automatic index usage and caching
500
+ * @param {string} query - SQL query with parameter placeholders
501
+ * @param {any[]} params - Query parameters
502
+ * @param {string} cacheKey - Optional cache key
503
+ * @returns {Promise<any>} Query result
504
+ */
505
+ async execute(query, params = [], cacheKey = null) {
506
+ const startTime = performance.now();
507
+
508
+ try {
509
+ // Check query cache if cache key provided
510
+ if (cacheKey && this.queryCache.has(cacheKey)) {
511
+ const cached = this.queryCache.get(cacheKey);
512
+ if (Date.now() - cached.timestamp < 60000) { // 1 min cache
513
+ return cached.result;
514
+ }
515
+ }
516
+
517
+ // Prepare and execute query
518
+ const statement = this.db.prepare(query);
519
+ const result = await statement.bind(...params).all();
520
+
521
+ // Cache result if cache key provided
522
+ if (cacheKey) {
523
+ this.queryCache.set(cacheKey, {
524
+ result: result,
525
+ timestamp: Date.now()
526
+ });
527
+ }
528
+
529
+ const queryTime = performance.now() - startTime;
530
+
531
+ // Log slow queries
532
+ if (queryTime > 100) {
533
+ console.warn(`[Slow Query] ${queryTime.toFixed(2)}ms - ${query.substring(0, 100)}...`);
534
+ }
535
+
536
+ return result;
537
+ } catch (error) {
538
+ const queryTime = performance.now() - startTime;
539
+ console.error(`[Query Error] ${queryTime.toFixed(2)}ms - ${error.message}`);
540
+ throw error;
541
+ }
542
+ }
543
+
544
+ /**
545
+ * Get user journey with optimized index usage
546
+ * @param {string} userId - User ID
547
+ * @param {string} conversionId - Optional conversion ID filter
548
+ * @returns {Promise<Array>} User journey events
549
+ */
550
+ async getUserJourney(userId, conversionId = null) {
551
+ const cacheKey = `journey:${userId}:${conversionId || 'all'}`;
552
+
553
+ const query = conversionId
554
+ ? `
555
+ SELECT * FROM user_journeys
556
+ WHERE user_id = ? AND conversion_id = ?
557
+ ORDER BY event_timestamp ASC
558
+ `
559
+ : `
560
+ SELECT * FROM user_journeys
561
+ WHERE user_id = ?
562
+ ORDER BY event_timestamp DESC
563
+ LIMIT 100
564
+ `;
565
+
566
+ const params = conversionId ? [userId, conversionId] : [userId];
567
+ return await this.execute(query, params, cacheKey);
568
+ }
569
+
570
+ /**
571
+ * Get attribution data with optimized joins
572
+ * @param {string} conversionId - Conversion ID
573
+ * @param {string} attributionModel - Attribution model
574
+ * @returns {Promise<Array>} Attribution data
575
+ */
576
+ async getAttributionData(conversionId, attributionModel) {
577
+ const cacheKey = `attribution:${conversionId}:${attributionModel}`;
578
+
579
+ const query = `
580
+ SELECT
581
+ a.*,
582
+ j.utm_medium,
583
+ j.utm_campaign,
584
+ j.event_name,
585
+ j.event_timestamp
586
+ FROM multi_touch_attribution a
587
+ INNER JOIN user_journeys j ON a.conversion_id = j.conversion_id
588
+ WHERE a.conversion_id = ? AND a.attribution_model = ?
589
+ ORDER BY a.touchpoint_index ASC
590
+ `;
591
+
592
+ return await this.execute(query, [conversionId, attributionModel], cacheKey);
593
+ }
594
+
595
+ /**
596
+ * Get channel performance with pre-aggregated data
597
+ * @param {string} attributionModel - Attribution model
598
+ * @param {number} limit - Limit results
599
+ * @returns {Promise<Array>} Channel performance data
600
+ */
601
+ async getChannelPerformance(attributionModel, limit = 50) {
602
+ const cacheKey = `performance:${attributionModel}:${limit}`;
603
+
604
+ const query = `
605
+ SELECT * FROM channel_performance
606
+ WHERE attribution_model = ?
607
+ ORDER BY total_attribution DESC
608
+ LIMIT ?
609
+ `;
610
+
611
+ return await this.execute(query, [attributionModel, limit], cacheKey);
612
+ }
613
+
614
+ /**
615
+ * Batch insert for high-throughput operations
616
+ * @param {string} table - Table name
617
+ * @param {string[]} columns - Column names
618
+ * @param {any[][]} values - Array of value arrays
619
+ * @returns {Promise<number>} Number of inserted rows
620
+ */
621
+ async batchInsert(table, columns, values) {
622
+ const startTime = performance.now();
623
+
624
+ try {
625
+ const placeholders = columns.map(() => '?').join(',');
626
+ const query = `INSERT INTO ${table} (${columns.join(',')}) VALUES (${placeholders})`;
627
+
628
+ let inserted = 0;
629
+ for (const row of values) {
630
+ await this.db.prepare(query).bind(...row).run();
631
+ inserted++;
632
+ }
633
+
634
+ const queryTime = performance.now() - startTime;
635
+ console.log(`[Batch Insert] ${inserted} rows in ${queryTime.toFixed(2)}ms`);
636
+
637
+ return inserted;
638
+ } catch (error) {
639
+ const queryTime = performance.now() - startTime;
640
+ console.error(`[Batch Insert Error] ${queryTime.toFixed(2)}ms - ${error.message}`);
641
+ throw error;
642
+ }
643
+ }
644
+
645
+ /**
646
+ * Invalidate query cache by pattern
647
+ * @param {string} pattern - Cache key pattern (supports wildcards *)
648
+ */
649
+ invalidateCache(pattern) {
650
+ for (const key of this.queryCache.keys()) {
651
+ if (this.matchesPattern(key, pattern)) {
652
+ this.queryCache.delete(key);
653
+ }
654
+ }
655
+ }
656
+
657
+ /**
658
+ * Match cache key against pattern (supports * wildcard)
659
+ * @param {string} key - Cache key
660
+ * @param {string} pattern - Pattern with * wildcards
661
+ * @returns {boolean} Match result
662
+ */
663
+ matchesPattern(key, pattern) {
664
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
665
+ return regex.test(key);
666
+ }
667
+ }
668
+
669
+ // Global query optimizer instance
670
+ let queryOptimizer = null;
671
+ ```
672
+
673
+ ---
674
+
675
+ ## 🚀 Otimização de Processamento em Lote
676
+
677
+ ### Batch Processing for Attribution
678
+
679
+ ```typescript
680
+ /**
681
+ * Batch Attribution Processor
682
+ * Processes multiple attributions in parallel with batching
683
+ */
684
+ class BatchAttributionProcessor {
685
+ constructor(cacheManager, queryOptimizer) {
686
+ this.cache = cacheManager;
687
+ this.optimizer = queryOptimizer;
688
+ this.batchSize = 50; // Process 50 attributions at once
689
+ this.maxParallel = 5; // Max 5 parallel batches
690
+ }
691
+
692
+ /**
693
+ * Process multiple attributions in batches
694
+ * @param {Array} conversions - Array of conversion IDs
695
+ * @param {string} attributionModel - Attribution model
696
+ * @returns {Promise<Array>} Processing results
697
+ */
698
+ async processBatch(conversions, attributionModel) {
699
+ const results = [];
700
+ const batches = this.chunkArray(conversions, this.batchSize);
701
+
702
+ // Process batches in parallel with concurrency limit
703
+ const batchPromises = batches.map(batch =>
704
+ this.processSingleBatch(batch, attributionModel)
705
+ );
706
+
707
+ const batchResults = await Promise.all(batchPromises);
708
+
709
+ // Flatten results
710
+ for (const batchResult of batchResults) {
711
+ results.push(...batchResult);
712
+ }
713
+
714
+ return results;
715
+ }
716
+
717
+ /**
718
+ * Process a single batch of attributions
719
+ * @param {Array} conversions - Array of conversion IDs
720
+ * @param {string} attributionModel - Attribution model
721
+ * @returns {Promise<Array>} Processing results
722
+ */
723
+ async processSingleBatch(conversions, attributionModel) {
724
+ const results = [];
725
+
726
+ for (const conversionId of conversions) {
727
+ try {
728
+ // Check cache first
729
+ const cacheKey = `attribution:${conversionId}:${attributionModel}`;
730
+ const cached = await this.cache.get(cacheKey, 'attribution');
731
+
732
+ if (cached) {
733
+ results.push({ conversionId, attributionModel, cached, fromCache: true });
734
+ continue;
735
+ }
736
+
737
+ // Fetch user journey
738
+ const journey = await this.optimizer.getUserJourney(conversionId);
739
+
740
+ if (journey.length === 0) {
741
+ results.push({ conversionId, attributionModel, error: 'No journey found' });
742
+ continue;
743
+ }
744
+
745
+ // Calculate attribution
746
+ const attribution = await this.calculateAttribution(journey, attributionModel);
747
+
748
+ // Cache result
749
+ await this.cache.set(cacheKey, attribution, 'attribution');
750
+
751
+ results.push({ conversionId, attributionModel, attribution, fromCache: false });
752
+ } catch (error) {
753
+ console.error(`Error processing ${conversionId}:`, error);
754
+ results.push({ conversionId, attributionModel, error: error.message });
755
+ }
756
+ }
757
+
758
+ return results;
759
+ }
760
+
761
+ /**
762
+ * Calculate attribution using specified model
763
+ * @param {Array} journey - User journey events
764
+ * @param {string} model - Attribution model
765
+ * @returns {Array} Attribution result
766
+ */
767
+ async calculateAttribution(journey, model) {
768
+ // Implementation of attribution models
769
+ // This would call the appropriate attribution function from attribution-agent.md
770
+ const attributionModels = {
771
+ 'last_click': this.lastClickAttribution,
772
+ 'first_click': this.firstClickAttribution,
773
+ 'linear': this.linearAttribution,
774
+ 'time_decay': this.timeDecayAttribution,
775
+ 'u_shape': this.uShapeAttribution,
776
+ 'w_shape': this.wShapeAttribution,
777
+ 'data_driven': this.dataDrivenAttribution
778
+ };
779
+
780
+ const modelFn = attributionModels[model] || attributionModels['last_click'];
781
+ return await modelFn.call(this, journey);
782
+ }
783
+
784
+ // Attribution model implementations (from attribution-agent.md)
785
+ lastClickAttribution(touchpoints) {
786
+ return touchpoints.map((tp, index) => ({
787
+ ...tp,
788
+ credit_percentage: index === touchpoints.length - 1 ? 100 : 0,
789
+ is_last_click: index === touchpoints.length - 1
790
+ }));
791
+ }
792
+
793
+ firstClickAttribution(touchpoints) {
794
+ return touchpoints.map((tp, index) => ({
795
+ ...tp,
796
+ credit_percentage: index === 0 ? 100 : 0,
797
+ is_first_click: index === 0
798
+ }));
799
+ }
800
+
801
+ linearAttribution(touchpoints) {
802
+ const credit = 100 / touchpoints.length;
803
+ return touchpoints.map(tp => ({
804
+ ...tp,
805
+ credit_percentage: credit.toFixed(2)
806
+ }));
807
+ }
808
+
809
+ async timeDecayAttribution(touchpoints, decayFactor = 0.9) {
810
+ const now = Date.now();
811
+ const oneDayMs = 24 * 60 * 60 * 1000;
812
+
813
+ const touchpointsWithDays = touchpoints.map(tp => {
814
+ const daysSinceTouch = (now - tp.event_timestamp) / oneDayMs;
815
+ const decayScore = Math.pow(decayFactor, daysSinceTouch);
816
+ return { ...tp, days_since: daysSinceTouch, decay_score: decayScore };
817
+ });
818
+
819
+ const totalScore = touchpointsWithDays.reduce((sum, tp) => sum + tp.decay_score, 0);
820
+
821
+ return touchpointsWithDays.map(tp => ({
822
+ ...tp,
823
+ credit_percentage: ((tp.decay_score / totalScore) * 100).toFixed(2)
824
+ }));
825
+ }
826
+
827
+ uShapeAttribution(touchpoints) {
828
+ if (touchpoints.length === 0) return [];
829
+
830
+ const firstTouchWeight = 0.4;
831
+ const lastTouchWeight = 0.4;
832
+ const middleWeight = touchpoints.length > 2 ? 0.2 / (touchpoints.length - 2) : 0;
833
+
834
+ return touchpoints.map((tp, index) => {
835
+ if (index === 0) {
836
+ return { ...tp, credit_percentage: 40, role: 'first' };
837
+ } else if (index === touchpoints.length - 1) {
838
+ return { ...tp, credit_percentage: 40, role: 'last' };
839
+ } else {
840
+ return { ...tp, credit_percentage: middleWeight.toFixed(2), role: 'middle' };
841
+ }
842
+ });
843
+ }
844
+
845
+ wShapeAttribution(touchpoints) {
846
+ if (touchpoints.length === 0) return [];
847
+
848
+ const firstTouchWeight = 0.3;
849
+ const lastTouchWeight = 0.3;
850
+ const middleWeights = touchpoints.length > 2 ? 0.4 / 2 : 0; // 2 assist points
851
+
852
+ return touchpoints.map((tp, index) => {
853
+ const pos = index + 1;
854
+ const total = touchpoints.length;
855
+
856
+ if (pos === 1) {
857
+ return { ...tp, credit_percentage: 30, role: 'first' };
858
+ } else if (pos === total) {
859
+ return { ...tp, credit_percentage: 30, role: 'last' };
860
+ } else if (pos === Math.floor(total / 2)) {
861
+ return { ...tp, credit_percentage: 20, role: 'middle_assist_1' };
862
+ } else {
863
+ return { ...tp, credit_percentage: middleWeights.toFixed(2), role: 'middle_assist_2' };
864
+ }
865
+ });
866
+ }
867
+
868
+ async dataDrivenAttribution(touchpoints, userJourneyHistory) {
869
+ // Simplified data-driven attribution
870
+ // In production, this would analyze historical conversion data
871
+
872
+ const channelWeights = await this.calculateChannelWeights(touchpoints, userJourneyHistory);
873
+ const positionWeights = await this.calculatePositionWeights(touchpoints, userJourneyHistory);
874
+
875
+ return touchpoints.map((tp, index) => {
876
+ const baseScore = 100 / touchpoints.length;
877
+ const channelWeight = channelWeights[tp.utm_source] || 1;
878
+ const positionWeight = positionWeights[index] || 1;
879
+
880
+ const score = baseScore * channelWeight * positionWeight;
881
+
882
+ return {
883
+ ...tp,
884
+ credit_percentage: score.toFixed(2),
885
+ channel_weight: channelWeight,
886
+ position_weight: positionWeight
887
+ };
888
+ });
889
+ }
890
+
891
+ async calculateChannelWeights(touchpoints, history) {
892
+ // Simplified - in production, analyze historical data
893
+ const channels = {};
894
+ touchpoints.forEach(tp => {
895
+ channels[tp.utm_source] = (channels[tp.utm_source] || 0) + 1;
896
+ });
897
+
898
+ const total = Object.values(channels).reduce((a, b) => a + b, 0);
899
+ const weights = {};
900
+ Object.entries(channels).forEach(([channel, count]) => {
901
+ weights[channel] = (count / total) * touchpoints.length;
902
+ });
903
+
904
+ return weights;
905
+ }
906
+
907
+ async calculatePositionWeights(touchpoints, history) {
908
+ // Simplified - in production, analyze historical position conversion rates
909
+ const weights = {};
910
+ for (let i = 0; i < touchpoints.length; i++) {
911
+ weights[i] = 1;
912
+ }
913
+ return weights;
914
+ }
915
+
916
+ /**
917
+ * Chunk array into smaller arrays
918
+ * @param {Array} array - Array to chunk
919
+ * @param {number} size - Chunk size
920
+ * @returns {Array} Array of chunks
921
+ */
922
+ chunkArray(array, size) {
923
+ const chunks = [];
924
+ for (let i = 0; i < array.length; i += size) {
925
+ chunks.push(array.slice(i, i + size));
926
+ }
927
+ return chunks;
928
+ }
929
+ }
930
+
931
+ // Global batch processor instance
932
+ let batchProcessor = null;
933
+ ```
934
+
935
+ ---
936
+
937
+ ## 📊 Profileamento de Latência
938
+
939
+ ### Performance Monitoring
940
+
941
+ ```typescript
942
+ /**
943
+ * Latency Profiler
944
+ * Monitors and tracks performance metrics
945
+ */
946
+ class LatencyProfiler {
947
+ constructor() {
948
+ this.metrics = {
949
+ requests: [],
950
+ queries: [],
951
+ cacheOps: [],
952
+ externalAPIs: []
953
+ };
954
+
955
+ this.thresholds = {
956
+ request: { warning: 100, error: 200 },
957
+ query: { warning: 50, error: 100 },
958
+ cache: { warning: 10, error: 20 },
959
+ external: { warning: 500, error: 2000 }
960
+ };
961
+ }
962
+
963
+ /**
964
+ * Start profiling a request
965
+ * @param {string} requestId - Request ID
966
+ * @param {string} endpoint - Endpoint being accessed
967
+ */
968
+ startRequest(requestId, endpoint) {
969
+ this.metrics.requests.push({
970
+ id: requestId,
971
+ endpoint: endpoint,
972
+ startTime: performance.now(),
973
+ stages: []
974
+ });
975
+ }
976
+
977
+ /**
978
+ * End profiling a request
979
+ * @param {string} requestId - Request ID
980
+ * @param {object} metadata - Additional metadata
981
+ */
982
+ endRequest(requestId, metadata = {}) {
983
+ const request = this.metrics.requests.find(r => r.id === requestId);
984
+ if (!request) return;
985
+
986
+ request.endTime = performance.now();
987
+ request.duration = request.endTime - request.startTime;
988
+ request.metadata = metadata;
989
+
990
+ // Log if over threshold
991
+ if (request.duration > this.thresholds.request.error) {
992
+ console.error(`[Latency] CRITICAL: ${request.duration.toFixed(2)}ms - ${request.endpoint}`);
993
+ } else if (request.duration > this.thresholds.request.warning) {
994
+ console.warn(`[Latency] WARNING: ${request.duration.toFixed(2)}ms - ${request.endpoint}`);
995
+ }
996
+ }
997
+
998
+ /**
999
+ * Profile a D1 query
1000
+ * @param {string} requestId - Request ID
1001
+ * @param {string} query - SQL query
1002
+ * @returns {Function} Function to call when query completes
1003
+ */
1004
+ profileQuery(requestId, query) {
1005
+ const startTime = performance.now();
1006
+
1007
+ return () => {
1008
+ const duration = performance.now() - startTime;
1009
+
1010
+ this.metrics.queries.push({
1011
+ requestId: requestId,
1012
+ query: query.substring(0, 100),
1013
+ duration: duration,
1014
+ timestamp: Date.now()
1015
+ });
1016
+
1017
+ if (duration > this.thresholds.query.error) {
1018
+ console.error(`[Query Latency] CRITICAL: ${duration.toFixed(2)}ms - ${query.substring(0, 50)}...`);
1019
+ } else if (duration > this.thresholds.query.warning) {
1020
+ console.warn(`[Query Latency] WARNING: ${duration.toFixed(2)}ms - ${query.substring(0, 50)}...`);
1021
+ }
1022
+ };
1023
+ }
1024
+
1025
+ /**
1026
+ * Profile a cache operation
1027
+ * @param {string} requestId - Request ID
1028
+ * @param {string} operation - Cache operation (get, set, delete)
1029
+ * @param {string} layer - Cache layer (L1, L2)
1030
+ * @returns {Function} Function to call when operation completes
1031
+ */
1032
+ profileCache(requestId, operation, layer) {
1033
+ const startTime = performance.now();
1034
+
1035
+ return () => {
1036
+ const duration = performance.now() - startTime;
1037
+
1038
+ this.metrics.cacheOps.push({
1039
+ requestId: requestId,
1040
+ operation: operation,
1041
+ layer: layer,
1042
+ duration: duration,
1043
+ timestamp: Date.now()
1044
+ });
1045
+
1046
+ if (duration > this.thresholds.cache.error) {
1047
+ console.error(`[Cache Latency] CRITICAL: ${layer} ${operation} - ${duration.toFixed(2)}ms`);
1048
+ }
1049
+ };
1050
+ }
1051
+
1052
+ /**
1053
+ * Profile an external API call
1054
+ * @param {string} requestId - Request ID
1055
+ * @param {string} api - API name
1056
+ * @returns {Function} Function to call when API call completes
1057
+ */
1058
+ profileExternalAPI(requestId, api) {
1059
+ const startTime = performance.now();
1060
+
1061
+ return () => {
1062
+ const duration = performance.now() - startTime;
1063
+
1064
+ this.metrics.externalAPIs.push({
1065
+ requestId: requestId,
1066
+ api: api,
1067
+ duration: duration,
1068
+ timestamp: Date.now()
1069
+ });
1070
+
1071
+ if (duration > this.thresholds.external.error) {
1072
+ console.error(`[External API Latency] CRITICAL: ${api} - ${duration.toFixed(2)}ms`);
1073
+ } else if (duration > this.thresholds.external.warning) {
1074
+ console.warn(`[External API Latency] WARNING: ${api} - ${duration.toFixed(2)}ms`);
1075
+ }
1076
+ };
1077
+ }
1078
+
1079
+ /**
1080
+ * Get performance summary
1081
+ * @returns {object} Performance summary
1082
+ */
1083
+ getSummary() {
1084
+ const summary = {};
1085
+
1086
+ // Request metrics
1087
+ const completedRequests = this.metrics.requests.filter(r => r.duration);
1088
+ summary.requests = {
1089
+ total: completedRequests.length,
1090
+ avg: this.average(completedRequests.map(r => r.duration)),
1091
+ p50: this.percentile(completedRequests.map(r => r.duration), 50),
1092
+ p95: this.percentile(completedRequests.map(r => r.duration), 95),
1093
+ p99: this.percentile(completedRequests.map(r => r.duration), 99),
1094
+ max: Math.max(...completedRequests.map(r => r.duration), 0)
1095
+ };
1096
+
1097
+ // Query metrics
1098
+ summary.queries = {
1099
+ total: this.metrics.queries.length,
1100
+ avg: this.average(this.metrics.queries.map(q => q.duration)),
1101
+ p95: this.percentile(this.metrics.queries.map(q => q.duration), 95),
1102
+ max: Math.max(...this.metrics.queries.map(q => q.duration), 0)
1103
+ };
1104
+
1105
+ // Cache metrics
1106
+ const l1Ops = this.metrics.cacheOps.filter(o => o.layer === 'L1');
1107
+ const l2Ops = this.metrics.cacheOps.filter(o => o.layer === 'L2');
1108
+
1109
+ summary.cache = {
1110
+ l1: {
1111
+ total: l1Ops.length,
1112
+ avg: this.average(l1Ops.map(o => o.duration)),
1113
+ hitRate: this.calculateHitRate(l1Ops)
1114
+ },
1115
+ l2: {
1116
+ total: l2Ops.length,
1117
+ avg: this.average(l2Ops.map(o => o.duration)),
1118
+ hitRate: this.calculateHitRate(l2Ops)
1119
+ }
1120
+ };
1121
+
1122
+ // External API metrics
1123
+ summary.external = {
1124
+ total: this.metrics.externalAPIs.length,
1125
+ avg: this.average(this.metrics.externalAPIs.map(a => a.duration)),
1126
+ p95: this.percentile(this.metrics.externalAPIs.map(a => a.duration), 95),
1127
+ byAPI: this.groupByAPI()
1128
+ };
1129
+
1130
+ return summary;
1131
+ }
1132
+
1133
+ /**
1134
+ * Calculate average of array
1135
+ * @param {number[]} arr - Array of numbers
1136
+ * @returns {number} Average
1137
+ */
1138
+ average(arr) {
1139
+ if (arr.length === 0) return 0;
1140
+ return arr.reduce((a, b) => a + b, 0) / arr.length;
1141
+ }
1142
+
1143
+ /**
1144
+ * Calculate percentile of array
1145
+ * @param {number[]} arr - Array of numbers
1146
+ * @param {number} p - Percentile (0-100)
1147
+ * @returns {number} Percentile value
1148
+ */
1149
+ percentile(arr, p) {
1150
+ if (arr.length === 0) return 0;
1151
+ const sorted = arr.sort((a, b) => a - b);
1152
+ const index = Math.ceil((p / 100) * sorted.length) - 1;
1153
+ return sorted[index];
1154
+ }
1155
+
1156
+ /**
1157
+ * Calculate cache hit rate
1158
+ * @param {Array} ops - Cache operations
1159
+ * @returns {number} Hit rate percentage
1160
+ */
1161
+ calculateHitRate(ops) {
1162
+ const hits = ops.filter(o => o.operation === 'get').length;
1163
+ const total = ops.length;
1164
+ return total > 0 ? ((hits / total) * 100).toFixed(2) + '%' : '0%';
1165
+ }
1166
+
1167
+ /**
1168
+ * Group external API calls by API
1169
+ * @returns {object} Grouped metrics
1170
+ */
1171
+ groupByAPI() {
1172
+ const grouped = {};
1173
+ this.metrics.externalAPIs.forEach(call => {
1174
+ if (!grouped[call.api]) {
1175
+ grouped[call.api] = { total: 0, durations: [] };
1176
+ }
1177
+ grouped[call.api].total++;
1178
+ grouped[call.api].durations.push(call.duration);
1179
+ });
1180
+
1181
+ Object.keys(grouped).forEach(api => {
1182
+ grouped[api].avg = this.average(grouped[api].durations);
1183
+ grouped[api].p95 = this.percentile(grouped[api].durations, 95);
1184
+ });
1185
+
1186
+ return grouped;
1187
+ }
1188
+
1189
+ /**
1190
+ * Clear all metrics
1191
+ */
1192
+ clear() {
1193
+ this.metrics = {
1194
+ requests: [],
1195
+ queries: [],
1196
+ cacheOps: [],
1197
+ externalAPIs: []
1198
+ };
1199
+ }
1200
+ }
1201
+
1202
+ // Global latency profiler instance
1203
+ let latencyProfiler = new LatencyProfiler();
1204
+ ```
1205
+
1206
+ ---
1207
+
1208
+ ## 🔧 Endpoints de Monitoramento de Performance
1209
+
1210
+ ### Worker API Endpoints
1211
+
1212
+ ```typescript
1213
+ /**
1214
+ * Performance Monitoring Endpoints
1215
+ */
1216
+ export default {
1217
+ async fetch(request, env, ctx) {
1218
+ // Initialize components
1219
+ if (!cacheManager) cacheManager = new CacheManager(env);
1220
+ if (!queryOptimizer) queryOptimizer = new QueryOptimizer(env.DB);
1221
+ if (!batchProcessor) batchProcessor = new BatchAttributionProcessor(cacheManager, queryOptimizer);
1222
+
1223
+ const url = new URL(request.url);
1224
+ const path = url.pathname;
1225
+
1226
+ // Performance monitoring endpoints
1227
+ if (path === '/api/performance/stats') {
1228
+ return handlePerformanceStats(env);
1229
+ }
1230
+
1231
+ if (path === '/api/performance/cache-stats') {
1232
+ return handleCacheStats(env);
1233
+ }
1234
+
1235
+ if (path === '/api/performance/query-stats') {
1236
+ return handleQueryStats(env);
1237
+ }
1238
+
1239
+ if (path === '/api/performance/latency-summary') {
1240
+ return handleLatencySummary(env);
1241
+ }
1242
+
1243
+ if (path === '/api/performance/cache-invalidate') {
1244
+ return handleCacheInvalidate(request, env);
1245
+ }
1246
+
1247
+ // ... other endpoints
1248
+
1249
+ return new Response('Not Found', { status: 404 });
1250
+ }
1251
+ };
1252
+
1253
+ /**
1254
+ * Handle /api/performance/stats - Overall performance statistics
1255
+ */
1256
+ async function handlePerformanceStats(env) {
1257
+ const summary = latencyProfiler.getSummary();
1258
+
1259
+ return new Response(JSON.stringify({
1260
+ success: true,
1261
+ data: {
1262
+ performance: summary,
1263
+ timestamp: new Date().toISOString()
1264
+ }
1265
+ }), {
1266
+ headers: { 'Content-Type': 'application/json' }
1267
+ });
1268
+ }
1269
+
1270
+ /**
1271
+ * Handle /api/performance/cache-stats - Cache statistics
1272
+ */
1273
+ async function handleCacheStats(env) {
1274
+ const stats = cacheManager ? cacheManager.getStats() : null;
1275
+
1276
+ return new Response(JSON.stringify({
1277
+ success: true,
1278
+ data: {
1279
+ cache: stats,
1280
+ timestamp: new Date().toISOString()
1281
+ }
1282
+ }), {
1283
+ headers: { 'Content-Type': 'application/json' }
1284
+ });
1285
+ }
1286
+
1287
+ /**
1288
+ * Handle /api/performance/query-stats - Query statistics
1289
+ */
1290
+ async function handleQueryStats(env) {
1291
+ const queryMetrics = latencyProfiler.metrics.queries;
1292
+
1293
+ return new Response(JSON.stringify({
1294
+ success: true,
1295
+ data: {
1296
+ queries: {
1297
+ total: queryMetrics.length,
1298
+ avg: queryMetrics.length > 0
1299
+ ? queryMetrics.reduce((a, b) => a + b.duration, 0) / queryMetrics.length
1300
+ : 0,
1301
+ slowQueries: queryMetrics.filter(q => q.duration > 100),
1302
+ timestamp: new Date().toISOString()
1303
+ }
1304
+ }
1305
+ }), {
1306
+ headers: { 'Content-Type': 'application/json' }
1307
+ });
1308
+ }
1309
+
1310
+ /**
1311
+ * Handle /api/performance/latency-summary - Latency summary
1312
+ */
1313
+ async function handleLatencySummary(env) {
1314
+ const summary = latencyProfiler.getSummary();
1315
+
1316
+ return new Response(JSON.stringify({
1317
+ success: true,
1318
+ data: {
1319
+ latency: {
1320
+ requests: summary.requests,
1321
+ queries: summary.queries,
1322
+ cache: summary.cache,
1323
+ externalAPIs: summary.external
1324
+ },
1325
+ timestamp: new Date().toISOString()
1326
+ }
1327
+ }), {
1328
+ headers: { 'Content-Type': 'application/json' }
1329
+ });
1330
+ }
1331
+
1332
+ /**
1333
+ * Handle /api/performance/cache-invalidate - Cache invalidation
1334
+ */
1335
+ async function handleCacheInvalidate(request, env) {
1336
+ if (request.method !== 'POST') {
1337
+ return new Response('Method Not Allowed', { status: 405 });
1338
+ }
1339
+
1340
+ try {
1341
+ const body = await request.json();
1342
+ const { prefix, keys } = body;
1343
+
1344
+ if (prefix) {
1345
+ await cacheManager.invalidateByPrefix(prefix);
1346
+ } else if (keys && Array.isArray(keys)) {
1347
+ for (const key of keys) {
1348
+ await cacheManager.delete(key);
1349
+ }
1350
+ } else {
1351
+ return new Response(JSON.stringify({
1352
+ success: false,
1353
+ error: 'Must provide either prefix or keys'
1354
+ }), {
1355
+ status: 400,
1356
+ headers: { 'Content-Type': 'application/json' }
1357
+ });
1358
+ }
1359
+
1360
+ return new Response(JSON.stringify({
1361
+ success: true,
1362
+ message: 'Cache invalidated successfully',
1363
+ timestamp: new Date().toISOString()
1364
+ }), {
1365
+ headers: { 'Content-Type': 'application/json' }
1366
+ });
1367
+ } catch (error) {
1368
+ return new Response(JSON.stringify({
1369
+ success: false,
1370
+ error: error.message
1371
+ }), {
1372
+ status: 500,
1373
+ headers: { 'Content-Type': 'application/json' }
1374
+ });
1375
+ }
1376
+ }
1377
+ ```
1378
+
1379
+ ---
1380
+
1381
+ ## 📋 Resumo de Implementação
1382
+
1383
+ ### Componentes Criados
1384
+
1385
+ 1. **CacheManager** - Gerenciador de caching multi-camada (L1 + L2 + L3)
1386
+ 2. **QueryOptimizer** - Otimizador de queries com cache e índices
1387
+ 3. **BatchAttributionProcessor** - Processamento em lote de atribuições
1388
+ 4. **LatencyProfiler** - Monitoramento de latência em tempo real
1389
+
1390
+ ### Endpoints de Monitoramento
1391
+
1392
+ | Endpoint | Método | Descrição |
1393
+ |----------|--------|-----------|
1394
+ | `/api/performance/stats` | GET | Estatísticas gerais de performance |
1395
+ | `/api/performance/cache-stats` | GET | Estatísticas de cache (L1/L2) |
1396
+ | `/api/performance/query-stats` | GET | Estatísticas de queries |
1397
+ | `/api/performance/latency-summary` | GET | Resumo de latência (P50, P95, P99) |
1398
+ | `/api/performance/cache-invalidate` | POST | Invalidação de cache |
1399
+
1400
+ ### Melhorias de Performance
1401
+
1402
+ - **Cache Hit Rate**: > 95% (L1 + L2)
1403
+ - **P95 Latency**: < 100ms (tracking), < 500ms (attribution)
1404
+ - **Query Time**: < 50ms (queries otimizadas)
1405
+ - **Memory Usage**: < 128MB (workers)
1406
+ - **CPU Time**: < 50ms (workers)
1407
+
1408
+ ---
1409
+
1410
+ ## 🔗 Integração com Outros Agentes
1411
+
1412
+ - **attribution-agent.md**: Usa `BatchAttributionProcessor` para processar múltiplas atribuições em paralelo
1413
+ - **security-enterprise-agent.md**: Usa `CacheManager` para cache de configurações de segurança
1414
+ - **master-orchestrator.md**: Usa `LatencyProfiler` para monitorar performance de toda a pipeline
1415
+
1416
+ ---
1417
+
1418
+ ## ✅ Checklist de Implementação
1419
+
1420
+ - [x] Implementar L1 Memory Cache (request-scoped)
1421
+ - [x] Implementar L2 KV Cache (global edge cache)
1422
+ - [x] Implementar CacheManager com fallback L1 → L2 → D1
1423
+ - [x] Criar índices otimizados para D1
1424
+ - [x] Implementar QueryOptimizer com cache de queries
1425
+ - [x] Implementar BatchAttributionProcessor para processamento em lote
1426
+ - [x] Implementar LatencyProfiler com monitoramento em tempo real
1427
+ - [x] Criar endpoints de monitoramento de performance
1428
+ - [x] Implementar invalidação de cache por prefixo
1429
+ - [x] Configurar TTLs específicos por tipo de cache
1430
+
1431
+ ---
1432
+
1433
+ ## 📚 Referências
1434
+
1435
+ - [Cloudflare Workers Performance Best Practices](https://developers.cloudflare.com/workers/)
1436
+ - [Cloudflare KV Caching](https://developers.cloudflare.com/workers/runtime-apis/kv/)
1437
+ - [Cloudflare D1 Query Optimization](https://developers.cloudflare.com/d1/)
1438
+ - [SQLite Index Optimization](https://www.sqlite.org/queryplanner.html)
1439
+
1440
+ ---
1441
+
1442
+ *Performance Optimization Enterprise Agent v1.0.0 - CDP Edge Quantum Tier*