feat: add domain daily rollups

This commit is contained in:
Christian Krakau-Louis
2026-05-22 21:12:43 +02:00
parent b1ff08590f
commit ccc634a10b
6 changed files with 102 additions and 11 deletions
+57 -3
View File
@@ -116,7 +116,7 @@
{% call card_header() %}
{% call card_title() %}Compliance Over Time{% endcall %}
{% call card_description() %}
DMARC pass rate for the past 30 days
Daily DMARC volume, pass rate, and failure rate
{% endcall %}
{% endcall %}
{% call card_content() %}
@@ -636,7 +636,7 @@ function domainDetailsApp(domainId) {
},
initComplianceChart(timelineData) {
if (!timelineData) return;
if (!timelineData || !timelineData.length) return;
const ctx = document.getElementById('compliance-chart').getContext('2d');
@@ -646,6 +646,8 @@ function domainDetailsApp(domainId) {
const labels = timelineData.map(item => item.date);
const complianceData = timelineData.map(item => item.compliance_rate);
const failureData = timelineData.map(item => item.failure_rate || 0);
const volumeData = timelineData.map(item => item.volume || item.total || 0);
// Calculate the threshold line data (recommended 98% for policy advancement)
const thresholdData = Array(labels.length).fill(98);
@@ -658,6 +660,7 @@ function domainDetailsApp(domainId) {
{
label: 'Compliance Rate',
data: complianceData,
yAxisID: 'yRate',
borderColor: 'rgb(59, 130, 246)', // blue-500
backgroundColor: 'rgba(59, 130, 246, 0.1)',
tension: 0.4,
@@ -666,9 +669,33 @@ function domainDetailsApp(domainId) {
pointRadius: 3,
pointHoverRadius: 5
},
{
label: 'Failure Rate',
data: failureData,
yAxisID: 'yRate',
borderColor: 'rgb(220, 38, 38)',
backgroundColor: 'rgba(220, 38, 38, 0.08)',
tension: 0.4,
fill: false,
pointBackgroundColor: 'rgb(220, 38, 38)',
pointRadius: 3,
pointHoverRadius: 5
},
{
label: 'Message Volume',
type: 'bar',
data: volumeData,
yAxisID: 'yVolume',
backgroundColor: 'rgba(107, 114, 128, 0.22)',
borderColor: 'rgba(107, 114, 128, 0.5)',
borderWidth: 1,
borderRadius: 4,
maxBarThickness: 28
},
{
label: 'Recommended Threshold (98%)',
data: thresholdData,
yAxisID: 'yRate',
borderColor: 'rgba(220, 38, 38, 0.6)', // red-600 with opacity
borderDash: [5, 5],
pointRadius: 0,
@@ -682,7 +709,9 @@ function domainDetailsApp(domainId) {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
yRate: {
type: 'linear',
position: 'left',
beginAtZero: false,
min: Math.max(0, Math.min(...complianceData) - 10), // Dynamic min value
max: 100,
@@ -700,6 +729,24 @@ function domainDetailsApp(domainId) {
color: 'rgba(0, 0, 0, 0.05)'
}
},
yVolume: {
type: 'linear',
position: 'right',
beginAtZero: true,
ticks: {
precision: 0
},
title: {
display: true,
text: 'Messages',
font: {
weight: 'bold'
}
},
grid: {
drawOnChartArea: false
}
},
x: {
title: {
display: true,
@@ -728,6 +775,12 @@ function domainDetailsApp(domainId) {
if (context.dataset.label === 'Compliance Rate') {
return `Compliance: ${context.parsed.y}%`;
}
if (context.dataset.label === 'Failure Rate') {
return `Failures: ${context.parsed.y}%`;
}
if (context.dataset.label === 'Message Volume') {
return `Messages: ${context.parsed.y}`;
}
return context.dataset.label;
},
title: function(context) {
@@ -747,6 +800,7 @@ function domainDetailsApp(domainId) {
annotations: {
box1: {
type: 'box',
yScaleID: 'yRate',
yMin: 90,
yMax: 100,
backgroundColor: 'rgba(34, 197, 94, 0.05)',