Files
goodgo-platform/monitoring/grafana/dashboards/web-vitals.json
Ho Ngoc Hai a59bf8eda2 feat(infra): add web vitals Grafana dashboard and admin audit log migration
- Add Grafana dashboard for web vitals metrics visualization
- Add Prisma migration for admin audit log table

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-11 01:39:37 +07:00

398 lines
12 KiB
JSON

{
"annotations": { "list": [] },
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 1,
"links": [],
"panels": [
{
"title": "Core Web Vitals — Overview",
"type": "row",
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 },
"collapsed": false
},
{
"title": "LCP (Largest Contentful Paint)",
"description": "Target: < 2.5s (good), < 4.0s (needs improvement)",
"type": "gauge",
"gridPos": { "h": 6, "w": 6, "x": 0, "y": 1 },
"targets": [
{
"expr": "histogram_quantile(0.75, sum(rate(goodgo_web_vitals_lcp_seconds_bucket[5m])) by (le))",
"legendFormat": "p75 LCP",
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "s",
"min": 0,
"max": 10,
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 2.5 },
{ "color": "red", "value": 4.0 }
]
}
}
}
},
{
"title": "FCP (First Contentful Paint)",
"description": "Target: < 1.8s (good), < 3.0s (needs improvement)",
"type": "gauge",
"gridPos": { "h": 6, "w": 6, "x": 6, "y": 1 },
"targets": [
{
"expr": "histogram_quantile(0.75, sum(rate(goodgo_web_vitals_fcp_seconds_bucket[5m])) by (le))",
"legendFormat": "p75 FCP",
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "s",
"min": 0,
"max": 5,
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 1.8 },
{ "color": "red", "value": 3.0 }
]
}
}
}
},
{
"title": "CLS (Cumulative Layout Shift)",
"description": "Target: < 0.1 (good), < 0.25 (needs improvement)",
"type": "gauge",
"gridPos": { "h": 6, "w": 6, "x": 12, "y": 1 },
"targets": [
{
"expr": "histogram_quantile(0.75, sum(rate(goodgo_web_vitals_cls_bucket[5m])) by (le))",
"legendFormat": "p75 CLS",
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "none",
"min": 0,
"max": 1,
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 0.1 },
{ "color": "red", "value": 0.25 }
]
}
}
}
},
{
"title": "TTFB (Time to First Byte)",
"description": "Target: < 800ms (good)",
"type": "gauge",
"gridPos": { "h": 6, "w": 6, "x": 18, "y": 1 },
"targets": [
{
"expr": "histogram_quantile(0.75, sum(rate(goodgo_web_vitals_ttfb_seconds_bucket[5m])) by (le))",
"legendFormat": "p75 TTFB",
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "s",
"min": 0,
"max": 5,
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 0.8 },
{ "color": "red", "value": 1.8 }
]
}
}
}
},
{
"title": "Rating Distribution",
"type": "row",
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 7 },
"collapsed": false
},
{
"title": "Web Vital Ratings (Good / Needs Improvement / Poor)",
"type": "piechart",
"gridPos": { "h": 8, "w": 8, "x": 0, "y": 8 },
"targets": [
{
"expr": "sum(goodgo_web_vitals_total) by (rating)",
"legendFormat": "{{rating}}",
"refId": "A"
}
],
"fieldConfig": {
"defaults": {},
"overrides": [
{ "matcher": { "id": "byName", "options": "good" }, "properties": [{ "id": "color", "value": { "fixedColor": "green", "mode": "fixed" } }] },
{ "matcher": { "id": "byName", "options": "needs-improvement" }, "properties": [{ "id": "color", "value": { "fixedColor": "yellow", "mode": "fixed" } }] },
{ "matcher": { "id": "byName", "options": "poor" }, "properties": [{ "id": "color", "value": { "fixedColor": "red", "mode": "fixed" } }] }
]
}
},
{
"title": "Events by Vital Type",
"type": "barchart",
"gridPos": { "h": 8, "w": 8, "x": 8, "y": 8 },
"targets": [
{
"expr": "sum(goodgo_web_vitals_total) by (name)",
"legendFormat": "{{name}}",
"refId": "A"
}
],
"fieldConfig": {
"defaults": { "unit": "short" }
}
},
{
"title": "INP (Interaction to Next Paint)",
"description": "Target: < 200ms (good), < 500ms (needs improvement)",
"type": "gauge",
"gridPos": { "h": 8, "w": 8, "x": 16, "y": 8 },
"targets": [
{
"expr": "histogram_quantile(0.75, sum(rate(goodgo_web_vitals_inp_seconds_bucket[5m])) by (le))",
"legendFormat": "p75 INP",
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "s",
"min": 0,
"max": 1,
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 0.2 },
{ "color": "red", "value": 0.5 }
]
}
}
}
},
{
"title": "Trends Over Time",
"type": "row",
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 16 },
"collapsed": false
},
{
"title": "LCP Trend (p50 / p75 / p95)",
"type": "timeseries",
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 17 },
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(goodgo_web_vitals_lcp_seconds_bucket[15m])) by (le))",
"legendFormat": "p50",
"refId": "A"
},
{
"expr": "histogram_quantile(0.75, sum(rate(goodgo_web_vitals_lcp_seconds_bucket[15m])) by (le))",
"legendFormat": "p75",
"refId": "B"
},
{
"expr": "histogram_quantile(0.95, sum(rate(goodgo_web_vitals_lcp_seconds_bucket[15m])) by (le))",
"legendFormat": "p95",
"refId": "C"
}
],
"fieldConfig": {
"defaults": {
"unit": "s",
"custom": { "drawStyle": "line", "fillOpacity": 10, "pointSize": 5 },
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 2.5 },
{ "color": "red", "value": 4.0 }
]
}
}
}
},
{
"title": "CLS Trend (p50 / p75 / p95)",
"type": "timeseries",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 17 },
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(goodgo_web_vitals_cls_bucket[15m])) by (le))",
"legendFormat": "p50",
"refId": "A"
},
{
"expr": "histogram_quantile(0.75, sum(rate(goodgo_web_vitals_cls_bucket[15m])) by (le))",
"legendFormat": "p75",
"refId": "B"
},
{
"expr": "histogram_quantile(0.95, sum(rate(goodgo_web_vitals_cls_bucket[15m])) by (le))",
"legendFormat": "p95",
"refId": "C"
}
],
"fieldConfig": {
"defaults": {
"unit": "none",
"custom": { "drawStyle": "line", "fillOpacity": 10, "pointSize": 5 },
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 0.1 },
{ "color": "red", "value": 0.25 }
]
}
}
}
},
{
"title": "TTFB Trend (p50 / p75 / p95)",
"type": "timeseries",
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 25 },
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(goodgo_web_vitals_ttfb_seconds_bucket[15m])) by (le))",
"legendFormat": "p50",
"refId": "A"
},
{
"expr": "histogram_quantile(0.75, sum(rate(goodgo_web_vitals_ttfb_seconds_bucket[15m])) by (le))",
"legendFormat": "p75",
"refId": "B"
},
{
"expr": "histogram_quantile(0.95, sum(rate(goodgo_web_vitals_ttfb_seconds_bucket[15m])) by (le))",
"legendFormat": "p95",
"refId": "C"
}
],
"fieldConfig": {
"defaults": {
"unit": "s",
"custom": { "drawStyle": "line", "fillOpacity": 10, "pointSize": 5 },
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 0.8 },
{ "color": "red", "value": 1.8 }
]
}
}
}
},
{
"title": "INP Trend (p50 / p75 / p95)",
"type": "timeseries",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 25 },
"targets": [
{
"expr": "histogram_quantile(0.50, sum(rate(goodgo_web_vitals_inp_seconds_bucket[15m])) by (le))",
"legendFormat": "p50",
"refId": "A"
},
{
"expr": "histogram_quantile(0.75, sum(rate(goodgo_web_vitals_inp_seconds_bucket[15m])) by (le))",
"legendFormat": "p75",
"refId": "B"
},
{
"expr": "histogram_quantile(0.95, sum(rate(goodgo_web_vitals_inp_seconds_bucket[15m])) by (le))",
"legendFormat": "p95",
"refId": "C"
}
],
"fieldConfig": {
"defaults": {
"unit": "s",
"custom": { "drawStyle": "line", "fillOpacity": 10, "pointSize": 5 },
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "green", "value": null },
{ "color": "yellow", "value": 0.2 },
{ "color": "red", "value": 0.5 }
]
}
}
}
},
{
"title": "Page Breakdown",
"type": "row",
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 33 },
"collapsed": false
},
{
"title": "LCP by Page (p75)",
"type": "table",
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 34 },
"targets": [
{
"expr": "histogram_quantile(0.75, sum(rate(goodgo_web_vitals_lcp_seconds_bucket[1h])) by (le, page)) > 0",
"legendFormat": "{{page}}",
"refId": "A",
"format": "table",
"instant": true
}
],
"fieldConfig": {
"defaults": { "unit": "s" }
},
"transformations": [
{ "id": "organize", "options": { "excludeByName": { "Time": true, "le": true } } }
]
},
{
"title": "Vitals Event Rate",
"type": "timeseries",
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 34 },
"targets": [
{
"expr": "sum(rate(goodgo_web_vitals_total[5m])) by (name)",
"legendFormat": "{{name}}",
"refId": "A"
}
],
"fieldConfig": {
"defaults": {
"unit": "ops",
"custom": { "drawStyle": "line", "fillOpacity": 10 }
}
}
}
],
"schemaVersion": 39,
"tags": ["web-vitals", "rum", "frontend"],
"templating": { "list": [] },
"time": { "from": "now-6h", "to": "now" },
"title": "Frontend Performance — Core Web Vitals",
"uid": "goodgo-web-vitals",
"version": 1
}