seo-testing-tool 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 (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +228 -0
  3. package/dist/auth/GoogleOAuthService.d.ts +31 -0
  4. package/dist/auth/GoogleOAuthService.d.ts.map +1 -0
  5. package/dist/auth/GoogleOAuthService.js +69 -0
  6. package/dist/auth/GoogleOAuthService.js.map +1 -0
  7. package/dist/auth/TokenManager.d.ts +56 -0
  8. package/dist/auth/TokenManager.d.ts.map +1 -0
  9. package/dist/auth/TokenManager.js +190 -0
  10. package/dist/auth/TokenManager.js.map +1 -0
  11. package/dist/cli/commands.d.ts +36 -0
  12. package/dist/cli/commands.d.ts.map +1 -0
  13. package/dist/cli/commands.js +471 -0
  14. package/dist/cli/commands.js.map +1 -0
  15. package/dist/cli/formatters.d.ts +24 -0
  16. package/dist/cli/formatters.d.ts.map +1 -0
  17. package/dist/cli/formatters.js +175 -0
  18. package/dist/cli/formatters.js.map +1 -0
  19. package/dist/cli.d.ts +15 -0
  20. package/dist/cli.d.ts.map +1 -0
  21. package/dist/cli.js +62 -0
  22. package/dist/cli.js.map +1 -0
  23. package/dist/config/AnalysisConfig.d.ts +13 -0
  24. package/dist/config/AnalysisConfig.d.ts.map +1 -0
  25. package/dist/config/AnalysisConfig.js +10 -0
  26. package/dist/config/AnalysisConfig.js.map +1 -0
  27. package/dist/config/env.d.ts +30 -0
  28. package/dist/config/env.d.ts.map +1 -0
  29. package/dist/config/env.js +77 -0
  30. package/dist/config/env.js.map +1 -0
  31. package/dist/database/DatabaseService.d.ts +106 -0
  32. package/dist/database/DatabaseService.d.ts.map +1 -0
  33. package/dist/database/DatabaseService.js +180 -0
  34. package/dist/database/DatabaseService.js.map +1 -0
  35. package/dist/database/TimeSeriesService.d.ts +53 -0
  36. package/dist/database/TimeSeriesService.d.ts.map +1 -0
  37. package/dist/database/TimeSeriesService.js +122 -0
  38. package/dist/database/TimeSeriesService.js.map +1 -0
  39. package/dist/database/db.d.ts +20 -0
  40. package/dist/database/db.d.ts.map +1 -0
  41. package/dist/database/db.js +60 -0
  42. package/dist/database/db.js.map +1 -0
  43. package/dist/database/schema.d.ts +687 -0
  44. package/dist/database/schema.d.ts.map +1 -0
  45. package/dist/database/schema.js +62 -0
  46. package/dist/database/schema.js.map +1 -0
  47. package/dist/demo.d.ts +13 -0
  48. package/dist/demo.d.ts.map +1 -0
  49. package/dist/demo.js +149 -0
  50. package/dist/demo.js.map +1 -0
  51. package/dist/gsc/GSCDataFetcher.d.ts +100 -0
  52. package/dist/gsc/GSCDataFetcher.d.ts.map +1 -0
  53. package/dist/gsc/GSCDataFetcher.js +398 -0
  54. package/dist/gsc/GSCDataFetcher.js.map +1 -0
  55. package/dist/gsc/GSCPermissionService.d.ts +20 -0
  56. package/dist/gsc/GSCPermissionService.d.ts.map +1 -0
  57. package/dist/gsc/GSCPermissionService.js +84 -0
  58. package/dist/gsc/GSCPermissionService.js.map +1 -0
  59. package/dist/index.d.ts +12 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +41 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/notifications/NotificationService.d.ts +64 -0
  64. package/dist/notifications/NotificationService.d.ts.map +1 -0
  65. package/dist/notifications/NotificationService.js +115 -0
  66. package/dist/notifications/NotificationService.js.map +1 -0
  67. package/dist/orchestrator/SEOExperimentOrchestrator.d.ts +69 -0
  68. package/dist/orchestrator/SEOExperimentOrchestrator.d.ts.map +1 -0
  69. package/dist/orchestrator/SEOExperimentOrchestrator.js +199 -0
  70. package/dist/orchestrator/SEOExperimentOrchestrator.js.map +1 -0
  71. package/dist/services/ExportService.d.ts +52 -0
  72. package/dist/services/ExportService.d.ts.map +1 -0
  73. package/dist/services/ExportService.js +238 -0
  74. package/dist/services/ExportService.js.map +1 -0
  75. package/dist/smoke-test.d.ts +10 -0
  76. package/dist/smoke-test.d.ts.map +1 -0
  77. package/dist/smoke-test.js +73 -0
  78. package/dist/smoke-test.js.map +1 -0
  79. package/dist/stats/StatisticalEngine.d.ts +48 -0
  80. package/dist/stats/StatisticalEngine.d.ts.map +1 -0
  81. package/dist/stats/StatisticalEngine.js +205 -0
  82. package/dist/stats/StatisticalEngine.js.map +1 -0
  83. package/dist/stats/TDistribution.d.ts +28 -0
  84. package/dist/stats/TDistribution.d.ts.map +1 -0
  85. package/dist/stats/TDistribution.js +120 -0
  86. package/dist/stats/TDistribution.js.map +1 -0
  87. package/drizzle/0000_hot_whiplash.sql +51 -0
  88. package/drizzle/0001_open_photon.sql +9 -0
  89. package/drizzle/0002_faulty_the_watchers.sql +1 -0
  90. package/drizzle/meta/0000_snapshot.json +360 -0
  91. package/drizzle/meta/0001_snapshot.json +428 -0
  92. package/drizzle/meta/0002_snapshot.json +420 -0
  93. package/drizzle/meta/_journal.json +27 -0
  94. package/package.json +89 -0
@@ -0,0 +1,238 @@
1
+ /**
2
+ * ExportService
3
+ *
4
+ * Genera report professionali in formato Excel (.xlsx) e CSV
5
+ * a partire dai dati di un test SEO (metadata + metriche giornaliere).
6
+ */
7
+ import ExcelJS from 'exceljs';
8
+ // ── Costanti stile ────────────────────────────────────────────────────────────
9
+ const COLORS = {
10
+ primary: '1B4F72',
11
+ headerBg: '2C3E50',
12
+ headerFont: 'FFFFFF',
13
+ labelBg: 'EBF5FB',
14
+ greenBg: 'E8F8F5',
15
+ greenFont: '1E8449',
16
+ redBg: 'FDEDEC',
17
+ redFont: 'C0392B',
18
+ zebraBg: 'F8F9F9',
19
+ borderColor: 'D5D8DC',
20
+ };
21
+ // ── Service ───────────────────────────────────────────────────────────────────
22
+ export class ReportExportService {
23
+ /**
24
+ * Genera un file Excel professionale con due fogli:
25
+ * - Riepilogo (metadata + analisi)
26
+ * - Dati Giornalieri (tabella metriche)
27
+ */
28
+ async exportToExcel(input) {
29
+ const { test, metrics } = input;
30
+ const workbook = new ExcelJS.Workbook();
31
+ workbook.creator = 'SEO Testing Tool';
32
+ workbook.created = new Date();
33
+ this.buildRiepilogoSheet(workbook, test, metrics);
34
+ this.buildDatiSheet(workbook, metrics);
35
+ const arrayBuffer = await workbook.xlsx.writeBuffer();
36
+ const buffer = Buffer.from(arrayBuffer);
37
+ return {
38
+ buffer,
39
+ fileName: this.buildFileName(test.name, 'xlsx'),
40
+ format: 'xlsx',
41
+ rowCount: metrics.length,
42
+ };
43
+ }
44
+ /**
45
+ * Genera un file CSV piatto con le metriche giornaliere.
46
+ */
47
+ async exportToCSV(input) {
48
+ const { test, metrics } = input;
49
+ const lines = [];
50
+ // Header
51
+ lines.push('Data,Clicks,Impressions,Gap Filled');
52
+ // Righe
53
+ for (const m of metrics) {
54
+ const date = m.date.includes('T') ? m.date.split('T')[0] : m.date;
55
+ lines.push(`${date},${m.clicks},${m.impressions},${m.gapFilled ? 'sì' : 'no'}`);
56
+ }
57
+ const csv = lines.join('\n') + '\n';
58
+ const buffer = Buffer.from(csv, 'utf-8');
59
+ return {
60
+ buffer,
61
+ fileName: this.buildFileName(test.name, 'csv'),
62
+ format: 'csv',
63
+ rowCount: metrics.length,
64
+ };
65
+ }
66
+ // ── Foglio 1: Riepilogo ───────────────────────────────────────────────────
67
+ buildRiepilogoSheet(workbook, test, metrics) {
68
+ const ws = workbook.addWorksheet('Riepilogo', {
69
+ properties: { defaultColWidth: 30 },
70
+ });
71
+ // Larghezze colonne
72
+ ws.getColumn(1).width = 24;
73
+ ws.getColumn(2).width = 50;
74
+ let row = 1;
75
+ // ── Titolo ──────────────────────────────────────────────────────────────
76
+ const titleCell = ws.getCell(row, 1);
77
+ titleCell.value = 'SEO Testing Tool — Report';
78
+ titleCell.font = { size: 16, bold: true, color: { argb: COLORS.primary } };
79
+ ws.mergeCells(row, 1, row, 2);
80
+ row += 2;
81
+ // ── Sezione: Informazioni Test ──────────────────────────────────────────
82
+ row = this.addSectionHeader(ws, row, 'Informazioni Test');
83
+ const startDateFormatted = this.formatDate(test.startDate);
84
+ const splitDateFormatted = this.formatDate(test.splitDate);
85
+ const infoRows = [
86
+ ['Nome Test', test.name],
87
+ ['ID', test.id],
88
+ ['Proprietà GSC', test.siteUrl],
89
+ ['URL monitorati', test.urls.join(', ') || '—'],
90
+ ['Data Inizio', startDateFormatted],
91
+ ['Split Date', splitDateFormatted],
92
+ ['Stato', test.status.toUpperCase()],
93
+ ['Metriche raccolte', `${metrics.length} giorni`],
94
+ ];
95
+ for (const [label, value] of infoRows) {
96
+ row = this.addLabelValueRow(ws, row, label, value);
97
+ }
98
+ row += 1;
99
+ // ── Sezione: Risultati Analisi ──────────────────────────────────────────
100
+ row = this.addSectionHeader(ws, row, 'Risultati Analisi');
101
+ // P-Value
102
+ const pValueStr = test.lastPValue !== null
103
+ ? test.lastPValue.toFixed(4)
104
+ : 'Non disponibile';
105
+ const pRow = this.addLabelValueRow(ws, row, 'P-Value', pValueStr);
106
+ if (test.lastPValue !== null) {
107
+ const pCell = ws.getCell(row, 2);
108
+ if (test.lastPValue < 0.05) {
109
+ pCell.font = { bold: true, color: { argb: COLORS.greenFont } };
110
+ pCell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: COLORS.greenBg } };
111
+ }
112
+ else {
113
+ pCell.font = { color: { argb: COLORS.redFont } };
114
+ }
115
+ }
116
+ row = pRow;
117
+ // Significatività
118
+ const sigStr = test.lastPValue !== null
119
+ ? (test.lastPValue < 0.05 ? 'SIGNIFICATIVO' : 'Non significativo')
120
+ : '—';
121
+ row = this.addLabelValueRow(ws, row, 'Significatività', sigStr);
122
+ // Miglioramento %
123
+ const improvStr = test.lastImprovement !== null
124
+ ? `${test.lastImprovement >= 0 ? '+' : ''}${test.lastImprovement.toFixed(1)}%`
125
+ : 'Non disponibile';
126
+ const improvRowNum = row;
127
+ row = this.addLabelValueRow(ws, row, 'Miglioramento', improvStr);
128
+ if (test.lastImprovement !== null) {
129
+ const improvCell = ws.getCell(improvRowNum, 2);
130
+ if (test.lastImprovement >= 0) {
131
+ improvCell.font = { bold: true, color: { argb: COLORS.greenFont } };
132
+ improvCell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: COLORS.greenBg } };
133
+ }
134
+ else {
135
+ improvCell.font = { bold: true, color: { argb: COLORS.redFont } };
136
+ improvCell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: COLORS.redBg } };
137
+ }
138
+ }
139
+ row += 1;
140
+ // ── Footer ──────────────────────────────────────────────────────────────
141
+ const footerCell = ws.getCell(row, 1);
142
+ footerCell.value = `Report generato il ${new Date().toLocaleDateString('it-IT')} — SEO Testing Tool v1.0.0`;
143
+ footerCell.font = { size: 9, italic: true, color: { argb: '999999' } };
144
+ ws.mergeCells(row, 1, row, 2);
145
+ }
146
+ // ── Foglio 2: Dati Giornalieri ──────────────────────────────────────────
147
+ buildDatiSheet(workbook, metrics) {
148
+ const ws = workbook.addWorksheet('Dati Giornalieri', {
149
+ views: [{ state: 'frozen', ySplit: 1 }],
150
+ });
151
+ // Colonne
152
+ ws.columns = [
153
+ { header: 'Data', key: 'date', width: 14 },
154
+ { header: 'Clicks', key: 'clicks', width: 12 },
155
+ { header: 'Impressions', key: 'impressions', width: 14 },
156
+ { header: 'Gap Filled', key: 'gapFilled', width: 12 },
157
+ ];
158
+ // Stile header
159
+ const headerRow = ws.getRow(1);
160
+ headerRow.eachCell((cell) => {
161
+ cell.font = { bold: true, color: { argb: COLORS.headerFont } };
162
+ cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: COLORS.headerBg } };
163
+ cell.alignment = { horizontal: 'center' };
164
+ cell.border = {
165
+ bottom: { style: 'thin', color: { argb: COLORS.borderColor } },
166
+ };
167
+ });
168
+ // Righe dati
169
+ for (let i = 0; i < metrics.length; i++) {
170
+ const m = metrics[i];
171
+ const date = m.date.includes('T') ? m.date.split('T')[0] : m.date;
172
+ const dataRow = ws.addRow({
173
+ date,
174
+ clicks: m.clicks,
175
+ impressions: m.impressions,
176
+ gapFilled: m.gapFilled ? 'Sì' : 'No',
177
+ });
178
+ // Zebra striping
179
+ if (i % 2 === 1) {
180
+ dataRow.eachCell((cell) => {
181
+ cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: COLORS.zebraBg } };
182
+ });
183
+ }
184
+ // Allineamento numerico
185
+ dataRow.getCell('clicks').alignment = { horizontal: 'right' };
186
+ dataRow.getCell('impressions').alignment = { horizontal: 'right' };
187
+ dataRow.getCell('gapFilled').alignment = { horizontal: 'center' };
188
+ }
189
+ // Auto-filtro
190
+ if (metrics.length > 0) {
191
+ ws.autoFilter = { from: 'A1', to: 'D1' };
192
+ }
193
+ }
194
+ // ── Helpers ─────────────────────────────────────────────────────────────
195
+ addSectionHeader(ws, row, title) {
196
+ const cell = ws.getCell(row, 1);
197
+ cell.value = title;
198
+ cell.font = { size: 12, bold: true, color: { argb: COLORS.headerFont } };
199
+ cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: COLORS.headerBg } };
200
+ const cell2 = ws.getCell(row, 2);
201
+ cell2.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: COLORS.headerBg } };
202
+ ws.mergeCells(row, 1, row, 2);
203
+ return row + 1;
204
+ }
205
+ addLabelValueRow(ws, row, label, value) {
206
+ const labelCell = ws.getCell(row, 1);
207
+ labelCell.value = label;
208
+ labelCell.font = { bold: true, color: { argb: '555555' } };
209
+ labelCell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: COLORS.labelBg } };
210
+ labelCell.border = {
211
+ bottom: { style: 'hair', color: { argb: COLORS.borderColor } },
212
+ };
213
+ const valueCell = ws.getCell(row, 2);
214
+ valueCell.value = value;
215
+ valueCell.border = {
216
+ bottom: { style: 'hair', color: { argb: COLORS.borderColor } },
217
+ };
218
+ return row + 1;
219
+ }
220
+ buildFileName(testName, ext) {
221
+ const safeName = testName.replace(/[^a-zA-Z0-9àèéìòù_-]/gi, '_').replace(/_+/g, '_');
222
+ const date = new Date().toISOString().split('T')[0];
223
+ return `report_${safeName}_${date}.${ext}`;
224
+ }
225
+ formatDate(isoDate) {
226
+ try {
227
+ return new Date(isoDate).toLocaleDateString('it-IT', {
228
+ day: '2-digit',
229
+ month: '2-digit',
230
+ year: 'numeric',
231
+ });
232
+ }
233
+ catch {
234
+ return isoDate;
235
+ }
236
+ }
237
+ }
238
+ //# sourceMappingURL=ExportService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExportService.js","sourceRoot":"","sources":["../../src/services/ExportService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Smoke Test — Verifica connessione DB SQLite (Drizzle + better-sqlite3)
3
+ *
4
+ * Crea le tabelle, inserisce un test di prova, lo recupera, e lo elimina subito.
5
+ * Conferma che la connessione al database è attiva e funzionante.
6
+ *
7
+ * Uso: npx tsx src/smoke-test.ts
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=smoke-test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke-test.d.ts","sourceRoot":"","sources":["../src/smoke-test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Smoke Test — Verifica connessione DB SQLite (Drizzle + better-sqlite3)
3
+ *
4
+ * Crea le tabelle, inserisce un test di prova, lo recupera, e lo elimina subito.
5
+ * Conferma che la connessione al database è attiva e funzionante.
6
+ *
7
+ * Uso: npx tsx src/smoke-test.ts
8
+ */
9
+ import { config } from 'dotenv';
10
+ config();
11
+ import { eq } from 'drizzle-orm';
12
+ import { db, migrateDB, closeDb } from './database/db.js';
13
+ import { users, tests } from './database/schema.js';
14
+ const SMOKE_TEST_NAME = 'SMOKE_TEST';
15
+ async function smokeTest() {
16
+ console.log('--- Smoke Test DB ---');
17
+ console.log(`Database: ${process.env['DATABASE_URL'] ?? '(default: ~/.seo-tool/data.db)'}`);
18
+ console.log('');
19
+ try {
20
+ // 0. Crea tabelle se non esistono
21
+ migrateDB();
22
+ console.log('[OK] Schema migrato');
23
+ // 1. Assicura che esista un utente per il test
24
+ const userId = 'smoke-test-user';
25
+ const existingUser = db.select().from(users).where(eq(users.id, userId)).get();
26
+ if (!existingUser) {
27
+ db.insert(users).values({ id: userId, email: 'smoke@test.local' }).run();
28
+ console.log('[OK] Utente di test creato');
29
+ }
30
+ else {
31
+ console.log('[OK] Utente di test già presente');
32
+ }
33
+ // 2. Crea test di prova
34
+ const test = db.insert(tests).values({
35
+ name: SMOKE_TEST_NAME,
36
+ siteUrl: 'sc-domain:smoke-test.local',
37
+ urls: JSON.stringify(['https://smoke-test.local/']),
38
+ startDate: new Date().toISOString(),
39
+ splitDate: new Date().toISOString(),
40
+ status: 'running',
41
+ userId,
42
+ }).returning().get();
43
+ console.log(`[OK] Test creato: ${test.id}`);
44
+ // 3. Recupera dal DB
45
+ const fetched = db.select().from(tests).where(eq(tests.id, test.id)).get();
46
+ if (!fetched || fetched.name !== SMOKE_TEST_NAME) {
47
+ throw new Error('Test recuperato non corrisponde');
48
+ }
49
+ console.log(`[OK] Test recuperato: "${fetched.name}"`);
50
+ // 4. Elimina il test
51
+ db.delete(tests).where(eq(tests.id, test.id)).run();
52
+ console.log('[OK] Test eliminato');
53
+ // 5. Verifica eliminazione
54
+ const deleted = db.select().from(tests).where(eq(tests.id, test.id)).get();
55
+ if (deleted) {
56
+ throw new Error('Test ancora presente dopo eliminazione');
57
+ }
58
+ console.log('[OK] Eliminazione confermata');
59
+ console.log('');
60
+ console.log('=== SMOKE TEST SUPERATO ===');
61
+ closeDb();
62
+ process.exit(0);
63
+ }
64
+ catch (error) {
65
+ console.error('');
66
+ console.error('[ERRORE] Smoke test fallito:');
67
+ console.error(error instanceof Error ? error.message : error);
68
+ closeDb();
69
+ process.exit(1);
70
+ }
71
+ }
72
+ smokeTest();
73
+ //# sourceMappingURL=smoke-test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smoke-test.js","sourceRoot":"","sources":["../src/smoke-test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,MAAM,EAAE,CAAC;AAET,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAEpD,MAAM,eAAe,GAAG,YAAY,CAAC;AAErC,KAAK,UAAU,SAAS;IACtB,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,aAAa,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,gCAAgC,EAAE,CAAC,CAAC;IAC5F,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,CAAC;QACH,kCAAkC;QAClC,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAEnC,+CAA+C;QAC/C,MAAM,MAAM,GAAG,iBAAiB,CAAC;QACjC,MAAM,YAAY,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/E,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;YACzE,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAClD,CAAC;QAED,wBAAwB;QACxB,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;YACnC,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,4BAA4B;YACrC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,2BAA2B,CAAC,CAAC;YACnD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,MAAM,EAAE,SAAS;YACjB,MAAM;SACP,CAAC,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QAE5C,qBAAqB;QACrB,MAAM,OAAO,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC3E,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,0BAA0B,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;QAEvD,qBAAqB;QACrB,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QAEnC,2BAA2B;QAC3B,MAAM,OAAO,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC3E,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAE5C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO,EAAE,CAAC;QACV,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAC9C,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC9D,OAAO,EAAE,CAAC;QACV,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,SAAS,EAAE,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { AnalysisConfig } from '../config/AnalysisConfig.js';
2
+ export interface AnalysisInput {
3
+ before: number[];
4
+ after: number[];
5
+ seasonalityAware?: boolean;
6
+ startDayOfWeek?: {
7
+ before: number;
8
+ after: number;
9
+ };
10
+ controlGroup?: {
11
+ before: number[];
12
+ after: number[];
13
+ };
14
+ }
15
+ export interface Outlier {
16
+ value: number;
17
+ index: number;
18
+ period: 'before' | 'after';
19
+ }
20
+ export interface AnalysisResult {
21
+ pValue: number;
22
+ isSignificant: boolean;
23
+ message: string;
24
+ percentageChange: number;
25
+ hasInsufficientData: boolean;
26
+ outliersDetected: boolean;
27
+ outliers: Outlier[];
28
+ meanAfterOutlierRemoval: number;
29
+ seasonalityDetected: boolean;
30
+ seasonalityPeriod: number | null;
31
+ relativePerformance?: number;
32
+ controlGroupPerformance?: number;
33
+ tStatistic?: number;
34
+ degreesOfFreedom?: number;
35
+ }
36
+ export declare class StatisticalEngine {
37
+ private readonly config;
38
+ constructor(config?: Partial<AnalysisConfig>);
39
+ analyze(input: AnalysisInput): AnalysisResult;
40
+ private welchTTest;
41
+ private calculateVariance;
42
+ private detectSeasonality;
43
+ private detectOutliers;
44
+ private removeOutliers;
45
+ private percentile;
46
+ private calculateMean;
47
+ }
48
+ //# sourceMappingURL=StatisticalEngine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatisticalEngine.d.ts","sourceRoot":"","sources":["../../src/stats/StatisticalEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA2B,MAAM,6BAA6B,CAAC;AAGtF,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,YAAY,CAAC,EAAE;QACb,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,KAAK,EAAE,MAAM,EAAE,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,uBAAuB,EAAE,MAAM,CAAC;IAChC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;gBAE5B,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC;IAI5C,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,cAAc;IAkH7C,OAAO,CAAC,UAAU;IAyClB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,aAAa;CAKtB"}
@@ -0,0 +1,205 @@
1
+ import { DEFAULT_ANALYSIS_CONFIG } from '../config/AnalysisConfig.js';
2
+ import { twoTailedPValue } from './TDistribution.js';
3
+ export class StatisticalEngine {
4
+ config;
5
+ constructor(config) {
6
+ this.config = { ...DEFAULT_ANALYSIS_CONFIG, ...config };
7
+ }
8
+ analyze(input) {
9
+ const { before, after, seasonalityAware = false, startDayOfWeek, controlGroup } = input;
10
+ // Rileva stagionalità se richiesto
11
+ const seasonalityInfo = seasonalityAware ? this.detectSeasonality(before) : { detected: false, period: null };
12
+ // Allinea i dati se c'è un offset nei giorni della settimana
13
+ let alignedBefore = before;
14
+ let alignedAfter = after;
15
+ if (seasonalityAware && startDayOfWeek) {
16
+ const offset = (startDayOfWeek.after - startDayOfWeek.before + 7) % 7;
17
+ if (offset !== 0 && after.length >= offset) {
18
+ // Allinea "after" a "before" ruotando i dati
19
+ alignedAfter = [...after.slice(offset), ...after.slice(0, offset)];
20
+ }
21
+ }
22
+ // Rileva outlier prima di calcolare le statistiche
23
+ const outliersBefore = this.detectOutliers(alignedBefore, 'before');
24
+ const outliersAfter = this.detectOutliers(alignedAfter, 'after');
25
+ const allOutliers = [...outliersBefore, ...outliersAfter];
26
+ const outliersDetected = allOutliers.length > 0;
27
+ // Rimuovi outlier per calcolare statistiche pulite
28
+ const cleanBefore = this.removeOutliers(alignedBefore, outliersBefore);
29
+ const cleanAfter = this.removeOutliers(alignedAfter, outliersAfter);
30
+ // Seleziona dati da usare per il calcolo
31
+ const dataBefore = cleanBefore.length > 0 ? cleanBefore : alignedBefore;
32
+ const dataAfter = cleanAfter.length > 0 ? cleanAfter : alignedAfter;
33
+ // Calcola medie
34
+ const meanBefore = this.calculateMean(dataBefore);
35
+ const meanAfter = this.calculateMean(dataAfter);
36
+ const meanAfterOutlierRemoval = meanAfter;
37
+ // Calcola variazione percentuale
38
+ const percentageChange = meanBefore !== 0 ? ((meanAfter - meanBefore) / meanBefore) * 100 : 0;
39
+ // Calcola performance relativa se c'è un gruppo di controllo
40
+ let relativePerformance;
41
+ let controlGroupPerformance;
42
+ if (controlGroup) {
43
+ const controlMeanBefore = this.calculateMean(controlGroup.before);
44
+ const controlMeanAfter = this.calculateMean(controlGroup.after);
45
+ controlGroupPerformance = ((controlMeanAfter - controlMeanBefore) / controlMeanBefore) * 100;
46
+ // Performance relativa = differenza tra test e controllo
47
+ relativePerformance = percentageChange - controlGroupPerformance;
48
+ }
49
+ // Verifica dati insufficienti: volume troppo basso o campione troppo piccolo
50
+ const hasInsufficientData = meanBefore < this.config.minimumDataThreshold ||
51
+ meanAfter < this.config.minimumDataThreshold ||
52
+ dataBefore.length < this.config.minimumSampleSize ||
53
+ dataAfter.length < this.config.minimumSampleSize;
54
+ // Determina significatività e messaggio
55
+ let isSignificant = false;
56
+ let pValue = 1.0;
57
+ let tStatistic;
58
+ let degreesOfFreedom;
59
+ let message = 'Nessun cambiamento significativo rilevato.';
60
+ if (hasInsufficientData) {
61
+ message = 'Dati insufficienti per determinare significatività statistica. Continua il test.';
62
+ }
63
+ else {
64
+ // Welch's t-test reale
65
+ const tTestResult = this.welchTTest(dataBefore, dataAfter);
66
+ pValue = tTestResult.pValue;
67
+ tStatistic = tTestResult.tStatistic;
68
+ degreesOfFreedom = tTestResult.degreesOfFreedom;
69
+ isSignificant = pValue < this.config.significanceLevel;
70
+ if (relativePerformance !== undefined) {
71
+ // Messaggio basato su performance relativa
72
+ if (isSignificant) {
73
+ if (relativePerformance > 0) {
74
+ message = 'Le pagine del test hanno performato meglio del resto del sito.';
75
+ }
76
+ else {
77
+ message = 'Le pagine del test hanno performato peggio del resto del sito.';
78
+ }
79
+ }
80
+ else {
81
+ message = 'Nessun cambiamento significativo rilevato.';
82
+ }
83
+ }
84
+ else {
85
+ // Messaggio classico
86
+ message = isSignificant
87
+ ? 'Cambiamento significativo rilevato.'
88
+ : 'Nessun cambiamento significativo rilevato.';
89
+ }
90
+ }
91
+ return {
92
+ pValue,
93
+ isSignificant,
94
+ message,
95
+ percentageChange,
96
+ hasInsufficientData,
97
+ outliersDetected,
98
+ outliers: allOutliers,
99
+ meanAfterOutlierRemoval,
100
+ seasonalityDetected: seasonalityInfo.detected,
101
+ seasonalityPeriod: seasonalityInfo.period,
102
+ relativePerformance,
103
+ controlGroupPerformance,
104
+ tStatistic,
105
+ degreesOfFreedom,
106
+ };
107
+ }
108
+ welchTTest(sample1, sample2) {
109
+ const n1 = sample1.length;
110
+ const n2 = sample2.length;
111
+ const mean1 = this.calculateMean(sample1);
112
+ const mean2 = this.calculateMean(sample2);
113
+ const var1 = this.calculateVariance(sample1, mean1);
114
+ const var2 = this.calculateVariance(sample2, mean2);
115
+ // Edge case: entrambe le varianze sono zero
116
+ if (var1 === 0 && var2 === 0) {
117
+ if (mean1 === mean2) {
118
+ return { tStatistic: 0, degreesOfFreedom: n1 + n2 - 2, pValue: 1.0 };
119
+ }
120
+ // Medie diverse con varianza zero = separazione perfetta
121
+ return { tStatistic: mean2 > mean1 ? Infinity : -Infinity, degreesOfFreedom: n1 + n2 - 2, pValue: 0.0 };
122
+ }
123
+ const se1 = var1 / n1;
124
+ const se2 = var2 / n2;
125
+ const seSum = se1 + se2;
126
+ const tStat = (mean2 - mean1) / Math.sqrt(seSum);
127
+ // Gradi di libertà Welch-Satterthwaite
128
+ let df;
129
+ if (se1 === 0 || se2 === 0) {
130
+ // Una varianza è zero: usa l'altro campione per i df
131
+ df = (se1 === 0 ? n2 : n1) - 1;
132
+ }
133
+ else {
134
+ df = (seSum * seSum) / ((se1 * se1) / (n1 - 1) + (se2 * se2) / (n2 - 1));
135
+ }
136
+ const effectiveDf = Math.max(df, 1);
137
+ const pVal = twoTailedPValue(tStat, effectiveDf);
138
+ return { tStatistic: tStat, degreesOfFreedom: effectiveDf, pValue: pVal };
139
+ }
140
+ calculateVariance(values, mean) {
141
+ if (values.length < 2)
142
+ return 0;
143
+ const m = mean ?? this.calculateMean(values);
144
+ const sumSquaredDiffs = values.reduce((acc, val) => acc + (val - m) ** 2, 0);
145
+ return sumSquaredDiffs / (values.length - 1); // Correzione di Bessel
146
+ }
147
+ detectSeasonality(values) {
148
+ // Rileva pattern settimanale (periodo 7)
149
+ if (values.length < 14) {
150
+ return { detected: false, period: null };
151
+ }
152
+ // Calcola autocorrelazione per periodo 7
153
+ const period = 7;
154
+ let correlation = 0;
155
+ let count = 0;
156
+ for (let i = 0; i < values.length - period; i++) {
157
+ correlation += Math.abs(values[i] - values[i + period]);
158
+ count++;
159
+ }
160
+ const avgDiff = correlation / count;
161
+ const overallMean = this.calculateMean(values);
162
+ // Se la differenza media tra giorni distanti 7 è piccola rispetto alla media,
163
+ // c'è un pattern settimanale
164
+ const threshold = overallMean * 0.3;
165
+ if (avgDiff < threshold) {
166
+ return { detected: true, period: 7 };
167
+ }
168
+ return { detected: false, period: null };
169
+ }
170
+ detectOutliers(values, period) {
171
+ const outliers = [];
172
+ // Usa metodo IQR (Interquartile Range)
173
+ const sorted = [...values].sort((a, b) => a - b);
174
+ const q1 = this.percentile(sorted, 25);
175
+ const q3 = this.percentile(sorted, 75);
176
+ const iqr = q3 - q1;
177
+ // Soglie per outlier configurabili
178
+ const lowerBound = q1 - this.config.outlierIqrMultiplier * iqr;
179
+ const upperBound = q3 + this.config.outlierIqrMultiplier * iqr;
180
+ values.forEach((value, index) => {
181
+ if (value < lowerBound || value > upperBound) {
182
+ outliers.push({ value, index, period });
183
+ }
184
+ });
185
+ return outliers;
186
+ }
187
+ removeOutliers(values, outliers) {
188
+ const outlierIndices = new Set(outliers.map(o => o.index));
189
+ return values.filter((_, index) => !outlierIndices.has(index));
190
+ }
191
+ percentile(sortedValues, percentile) {
192
+ const index = (percentile / 100) * (sortedValues.length - 1);
193
+ const lower = Math.floor(index);
194
+ const upper = Math.ceil(index);
195
+ const weight = index - lower;
196
+ return sortedValues[lower] * (1 - weight) + sortedValues[upper] * weight;
197
+ }
198
+ calculateMean(values) {
199
+ if (values.length === 0)
200
+ return 0;
201
+ const sum = values.reduce((acc, val) => acc + val, 0);
202
+ return sum / values.length;
203
+ }
204
+ }
205
+ //# sourceMappingURL=StatisticalEngine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StatisticalEngine.js","sourceRoot":"","sources":["../../src/stats/StatisticalEngine.ts"],"names":[],"mappings":"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"}