Skip to content

Commit e7708fe

Browse files
committed
Merge branch 'staging'
2 parents 40f19c3 + bec5ee0 commit e7708fe

File tree

16 files changed

+2105
-840
lines changed

16 files changed

+2105
-840
lines changed

.cursor/rules/01-MUST-DO.mdc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use console properly, like console.error, console.time, console.json, console.ta
4040

4141
Use Dayjs NEVER date-fns, and Tanstack query for hooks, NEVER SWR
4242

43-
use Icon at the end of phosphor react icons, like CaretIcon not Caret
43+
use Icon at the end of phosphor react icons, like CaretIcon not Caret AND THATS THE DEFAULT IMPORT, NOT AS
4444

4545
use json.stringify() when adding debugging
4646

apps/api/src/query/builders/performance.ts

Lines changed: 226 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
import { Analytics } from '../../types/tables';
22
import type { SimpleQueryConfig } from '../types';
33

4+
// Performance percentile queries with P50, P75, P90, P95, P99 metrics
5+
// Uses both events table (for load times) and web_vitals table (for Core Web Vitals)
6+
47
export const PerformanceBuilders: Record<string, SimpleQueryConfig> = {
58
slow_pages: {
69
table: Analytics.events,
710
fields: [
811
"trimRight(path, '/') as name",
912
'COUNT(DISTINCT anonymous_id) as visitors',
1013
'AVG(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as avg_load_time',
14+
'quantile(0.50)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p50_load_time',
15+
'quantile(0.75)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p75_load_time',
16+
'quantile(0.90)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p90_load_time',
17+
'quantile(0.95)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p95_load_time',
18+
'quantile(0.99)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p99_load_time',
1119
'AVG(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as avg_ttfb',
20+
'quantile(0.95)(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as p95_ttfb',
21+
'quantile(0.99)(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as p99_ttfb',
1222
'AVG(CASE WHEN dom_ready_time > 0 THEN dom_ready_time ELSE NULL END) as avg_dom_ready_time',
1323
'AVG(CASE WHEN render_time > 0 THEN render_time ELSE NULL END) as avg_render_time',
1424
'COUNT(*) as pageviews',
1525
],
1626
where: ["event_name = 'screen_view'", "path != ''", 'load_time > 0'],
1727
groupBy: ["trimRight(path, '/')"],
18-
orderBy: 'avg_load_time DESC',
28+
orderBy: 'p95_load_time DESC',
1929
limit: 100,
2030
timeField: 'time',
2131
customizable: true,
@@ -26,7 +36,10 @@ export const PerformanceBuilders: Record<string, SimpleQueryConfig> = {
2636
"CONCAT(browser_name, ' ', browser_version) as name",
2737
'COUNT(DISTINCT anonymous_id) as visitors',
2838
'AVG(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as avg_load_time',
39+
'quantile(0.95)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p95_load_time',
40+
'quantile(0.99)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p99_load_time',
2941
'AVG(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as avg_ttfb',
42+
'quantile(0.95)(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as p95_ttfb',
3043
'AVG(CASE WHEN dom_ready_time > 0 THEN dom_ready_time ELSE NULL END) as avg_dom_ready_time',
3144
'AVG(CASE WHEN render_time > 0 THEN render_time ELSE NULL END) as avg_render_time',
3245
'COUNT(*) as pageviews',
@@ -39,7 +52,7 @@ export const PerformanceBuilders: Record<string, SimpleQueryConfig> = {
3952
'load_time > 0',
4053
],
4154
groupBy: ['browser_name', 'browser_version'],
42-
orderBy: 'avg_load_time DESC',
55+
orderBy: 'p95_load_time DESC',
4356
limit: 100,
4457
timeField: 'time',
4558
customizable: true,
@@ -51,14 +64,17 @@ export const PerformanceBuilders: Record<string, SimpleQueryConfig> = {
5164
'country as name',
5265
'COUNT(DISTINCT anonymous_id) as visitors',
5366
'AVG(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as avg_load_time',
67+
'quantile(0.95)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p95_load_time',
68+
'quantile(0.99)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p99_load_time',
5469
'AVG(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as avg_ttfb',
70+
'quantile(0.95)(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as p95_ttfb',
5571
'AVG(CASE WHEN dom_ready_time > 0 THEN dom_ready_time ELSE NULL END) as avg_dom_ready_time',
5672
'AVG(CASE WHEN render_time > 0 THEN render_time ELSE NULL END) as avg_render_time',
5773
'COUNT(*) as pageviews',
5874
],
5975
where: ["event_name = 'screen_view'", "country != ''", 'load_time > 0'],
6076
groupBy: ['country'],
61-
orderBy: 'avg_load_time DESC',
77+
orderBy: 'p95_load_time DESC',
6278
limit: 100,
6379
timeField: 'time',
6480
customizable: true,
@@ -71,14 +87,17 @@ export const PerformanceBuilders: Record<string, SimpleQueryConfig> = {
7187
'os_name as name',
7288
'COUNT(DISTINCT anonymous_id) as visitors',
7389
'AVG(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as avg_load_time',
90+
'quantile(0.95)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p95_load_time',
91+
'quantile(0.99)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p99_load_time',
7492
'AVG(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as avg_ttfb',
93+
'quantile(0.95)(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as p95_ttfb',
7594
'AVG(CASE WHEN dom_ready_time > 0 THEN dom_ready_time ELSE NULL END) as avg_dom_ready_time',
7695
'AVG(CASE WHEN render_time > 0 THEN render_time ELSE NULL END) as avg_render_time',
7796
'COUNT(*) as pageviews',
7897
],
7998
where: ["event_name = 'screen_view'", "os_name != ''", 'load_time > 0'],
8099
groupBy: ['os_name'],
81-
orderBy: 'avg_load_time DESC',
100+
orderBy: 'p95_load_time DESC',
82101
limit: 100,
83102
timeField: 'time',
84103
customizable: true,
@@ -90,14 +109,17 @@ export const PerformanceBuilders: Record<string, SimpleQueryConfig> = {
90109
"CONCAT(region, ', ', country) as name",
91110
'COUNT(DISTINCT anonymous_id) as visitors',
92111
'AVG(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as avg_load_time',
112+
'quantile(0.95)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p95_load_time',
113+
'quantile(0.99)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p99_load_time',
93114
'AVG(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as avg_ttfb',
115+
'quantile(0.95)(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as p95_ttfb',
94116
'AVG(CASE WHEN dom_ready_time > 0 THEN dom_ready_time ELSE NULL END) as avg_dom_ready_time',
95117
'AVG(CASE WHEN render_time > 0 THEN render_time ELSE NULL END) as avg_render_time',
96118
'COUNT(*) as pageviews',
97119
],
98120
where: ["event_name = 'screen_view'", "region != ''", 'load_time > 0'],
99121
groupBy: ['region', 'country'],
100-
orderBy: 'avg_load_time DESC',
122+
orderBy: 'p95_load_time DESC',
101123
limit: 100,
102124
timeField: 'time',
103125
customizable: true,
@@ -108,7 +130,11 @@ export const PerformanceBuilders: Record<string, SimpleQueryConfig> = {
108130
fields: [
109131
'toDate(time) as date',
110132
'AVG(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as avg_load_time',
133+
'quantile(0.50)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p50_load_time',
134+
'quantile(0.95)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p95_load_time',
135+
'quantile(0.99)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p99_load_time',
111136
'AVG(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as avg_ttfb',
137+
'quantile(0.95)(CASE WHEN ttfb > 0 THEN ttfb ELSE NULL END) as p95_ttfb',
112138
'AVG(CASE WHEN dom_ready_time > 0 THEN dom_ready_time ELSE NULL END) as avg_dom_ready_time',
113139
'AVG(CASE WHEN render_time > 0 THEN render_time ELSE NULL END) as avg_render_time',
114140
'COUNT(*) as pageviews',
@@ -119,4 +145,199 @@ export const PerformanceBuilders: Record<string, SimpleQueryConfig> = {
119145
timeField: 'time',
120146
customizable: true,
121147
},
148+
149+
load_time_performance: {
150+
table: Analytics.events,
151+
fields: [
152+
'toDate(time) as date',
153+
'AVG(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as avg_load_time',
154+
'quantile(0.50)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p50_load_time',
155+
'quantile(0.95)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p95_load_time',
156+
'quantile(0.99)(CASE WHEN load_time > 0 THEN load_time ELSE NULL END) as p99_load_time',
157+
'COUNT(*) as pageviews',
158+
],
159+
where: ["event_name = 'screen_view'", 'load_time > 0'],
160+
groupBy: ['toDate(time)'],
161+
orderBy: 'date ASC',
162+
timeField: 'time',
163+
customizable: true,
164+
},
165+
166+
web_vitals_by_page: {
167+
table: Analytics.web_vitals,
168+
fields: [
169+
"trimRight(path, '/') as name",
170+
'COUNT(DISTINCT anonymous_id) as visitors',
171+
'AVG(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as avg_fcp',
172+
'quantile(0.50)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p50_fcp',
173+
'quantile(0.75)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p75_fcp',
174+
'quantile(0.90)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p90_fcp',
175+
'quantile(0.95)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p95_fcp',
176+
'quantile(0.99)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p99_fcp',
177+
'AVG(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as avg_lcp',
178+
'quantile(0.50)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p50_lcp',
179+
'quantile(0.75)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p75_lcp',
180+
'quantile(0.90)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p90_lcp',
181+
'quantile(0.95)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p95_lcp',
182+
'quantile(0.99)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p99_lcp',
183+
'AVG(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as avg_cls',
184+
'quantile(0.50)(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as p50_cls',
185+
'quantile(0.75)(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as p75_cls',
186+
'quantile(0.90)(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as p90_cls',
187+
'quantile(0.95)(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as p95_cls',
188+
'quantile(0.99)(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as p99_cls',
189+
'AVG(CASE WHEN fid > 0 THEN fid ELSE NULL END) as avg_fid',
190+
'quantile(0.95)(CASE WHEN fid > 0 THEN fid ELSE NULL END) as p95_fid',
191+
'quantile(0.99)(CASE WHEN fid > 0 THEN fid ELSE NULL END) as p99_fid',
192+
'AVG(CASE WHEN inp > 0 THEN inp ELSE NULL END) as avg_inp',
193+
'quantile(0.95)(CASE WHEN inp > 0 THEN inp ELSE NULL END) as p95_inp',
194+
'quantile(0.99)(CASE WHEN inp > 0 THEN inp ELSE NULL END) as p99_inp',
195+
'COUNT(*) as measurements',
196+
],
197+
where: ["path != ''"],
198+
groupBy: ["trimRight(path, '/')"],
199+
orderBy: 'p95_lcp DESC',
200+
limit: 100,
201+
timeField: 'timestamp',
202+
customizable: true,
203+
},
204+
205+
web_vitals_by_browser: {
206+
table: Analytics.web_vitals,
207+
fields: [
208+
"CONCAT(browser_name, ' ', browser_version) as name",
209+
'COUNT(DISTINCT anonymous_id) as visitors',
210+
'AVG(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as avg_fcp',
211+
'quantile(0.95)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p95_fcp',
212+
'quantile(0.99)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p99_fcp',
213+
'AVG(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as avg_lcp',
214+
'quantile(0.95)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p95_lcp',
215+
'quantile(0.99)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p99_lcp',
216+
'AVG(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as avg_cls',
217+
'quantile(0.95)(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as p95_cls',
218+
'quantile(0.99)(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as p99_cls',
219+
'AVG(CASE WHEN fid > 0 THEN fid ELSE NULL END) as avg_fid',
220+
'quantile(0.95)(CASE WHEN fid > 0 THEN fid ELSE NULL END) as p95_fid',
221+
'AVG(CASE WHEN inp > 0 THEN inp ELSE NULL END) as avg_inp',
222+
'quantile(0.95)(CASE WHEN inp > 0 THEN inp ELSE NULL END) as p95_inp',
223+
'COUNT(*) as measurements',
224+
],
225+
where: [
226+
"browser_name != ''",
227+
"browser_version != ''",
228+
'browser_version IS NOT NULL',
229+
],
230+
groupBy: ['browser_name', 'browser_version'],
231+
orderBy: 'p95_lcp DESC',
232+
limit: 100,
233+
timeField: 'timestamp',
234+
customizable: true,
235+
},
236+
237+
web_vitals_by_country: {
238+
table: Analytics.web_vitals,
239+
fields: [
240+
'country as name',
241+
'COUNT(DISTINCT anonymous_id) as visitors',
242+
'AVG(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as avg_fcp',
243+
'quantile(0.95)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p95_fcp',
244+
'AVG(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as avg_lcp',
245+
'quantile(0.95)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p95_lcp',
246+
'quantile(0.99)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p99_lcp',
247+
'AVG(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as avg_cls',
248+
'quantile(0.95)(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as p95_cls',
249+
'AVG(CASE WHEN fid > 0 THEN fid ELSE NULL END) as avg_fid',
250+
'quantile(0.95)(CASE WHEN fid > 0 THEN fid ELSE NULL END) as p95_fid',
251+
'AVG(CASE WHEN inp > 0 THEN inp ELSE NULL END) as avg_inp',
252+
'quantile(0.95)(CASE WHEN inp > 0 THEN inp ELSE NULL END) as p95_inp',
253+
'COUNT(*) as measurements',
254+
],
255+
where: ["country != ''"],
256+
groupBy: ['country'],
257+
orderBy: 'p95_lcp DESC',
258+
limit: 100,
259+
timeField: 'timestamp',
260+
customizable: true,
261+
plugins: { normalizeGeo: true, deduplicateGeo: true },
262+
},
263+
264+
web_vitals_by_os: {
265+
table: Analytics.web_vitals,
266+
fields: [
267+
'os_name as name',
268+
'COUNT(DISTINCT anonymous_id) as visitors',
269+
'AVG(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as avg_fcp',
270+
'quantile(0.95)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p95_fcp',
271+
'AVG(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as avg_lcp',
272+
'quantile(0.95)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p95_lcp',
273+
'quantile(0.99)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p99_lcp',
274+
'AVG(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as avg_cls',
275+
'quantile(0.95)(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as p95_cls',
276+
'AVG(CASE WHEN fid > 0 THEN fid ELSE NULL END) as avg_fid',
277+
'quantile(0.95)(CASE WHEN fid > 0 THEN fid ELSE NULL END) as p95_fid',
278+
'AVG(CASE WHEN inp > 0 THEN inp ELSE NULL END) as avg_inp',
279+
'quantile(0.95)(CASE WHEN inp > 0 THEN inp ELSE NULL END) as p95_inp',
280+
'COUNT(*) as measurements',
281+
],
282+
where: ["os_name != ''"],
283+
groupBy: ['os_name'],
284+
orderBy: 'p95_lcp DESC',
285+
limit: 100,
286+
timeField: 'timestamp',
287+
customizable: true,
288+
},
289+
290+
web_vitals_by_region: {
291+
table: Analytics.web_vitals,
292+
fields: [
293+
"CONCAT(region, ', ', country) as name",
294+
'COUNT(DISTINCT anonymous_id) as visitors',
295+
'AVG(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as avg_fcp',
296+
'quantile(0.95)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p95_fcp',
297+
'AVG(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as avg_lcp',
298+
'quantile(0.95)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p95_lcp',
299+
'quantile(0.99)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p99_lcp',
300+
'AVG(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as avg_cls',
301+
'quantile(0.95)(CASE WHEN cls IS NOT NULL THEN cls ELSE NULL END) as p95_cls',
302+
'AVG(CASE WHEN fid > 0 THEN fid ELSE NULL END) as avg_fid',
303+
'quantile(0.95)(CASE WHEN fid > 0 THEN fid ELSE NULL END) as p95_fid',
304+
'AVG(CASE WHEN inp > 0 THEN inp ELSE NULL END) as avg_inp',
305+
'quantile(0.95)(CASE WHEN inp > 0 THEN inp ELSE NULL END) as p95_inp',
306+
'COUNT(*) as measurements',
307+
],
308+
where: ["region != ''"],
309+
groupBy: ['region', 'country'],
310+
orderBy: 'p95_lcp DESC',
311+
limit: 100,
312+
timeField: 'timestamp',
313+
customizable: true,
314+
plugins: { normalizeGeo: true, deduplicateGeo: true },
315+
},
316+
317+
web_vitals_time_series: {
318+
table: Analytics.web_vitals,
319+
fields: [
320+
'toDate(timestamp) as date',
321+
'AVG(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as avg_fcp',
322+
'quantile(0.50)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p50_fcp',
323+
'quantile(0.95)(CASE WHEN fcp > 0 THEN fcp ELSE NULL END) as p95_fcp',
324+
'AVG(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as avg_lcp',
325+
'quantile(0.50)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p50_lcp',
326+
'quantile(0.95)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p95_lcp',
327+
'quantile(0.99)(CASE WHEN lcp > 0 THEN lcp ELSE NULL END) as p99_lcp',
328+
'AVG(CASE WHEN cls > 0 THEN cls ELSE NULL END) as avg_cls',
329+
'quantile(0.50)(CASE WHEN cls > 0 THEN cls ELSE NULL END) as p50_cls',
330+
'quantile(0.95)(CASE WHEN cls > 0 THEN cls ELSE NULL END) as p95_cls',
331+
'AVG(CASE WHEN fid > 0 THEN fid ELSE NULL END) as avg_fid',
332+
'quantile(0.95)(CASE WHEN fid > 0 THEN fid ELSE NULL END) as p95_fid',
333+
'AVG(CASE WHEN inp > 0 THEN inp ELSE NULL END) as avg_inp',
334+
'quantile(0.95)(CASE WHEN inp > 0 THEN inp ELSE NULL END) as p95_inp',
335+
'COUNT(*) as measurements',
336+
],
337+
where: [],
338+
groupBy: ['toDate(timestamp)'],
339+
orderBy: 'date ASC',
340+
timeField: 'timestamp',
341+
customizable: true,
342+
},
122343
};

0 commit comments

Comments
 (0)