From fd34553ab0e63b4d3bc22532b61f4fef32846f34 Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Sat, 25 Apr 2026 00:03:59 -0500 Subject: DomainDig v3.9.0 — Portfolio Dashboard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Portfolio summary cards * Recent activity feed across tracked domains * Attention-required queue prioritized by severity * Certificate expiry visibility and expiring-soon section * Quick portfolio filters for triage * Deterministic per-domain health scoring * Local portfolio search * Apex-domain grouping for tracked assets --- DomainReportBuilder.swift | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'DomainReportBuilder.swift') diff --git a/DomainReportBuilder.swift b/DomainReportBuilder.swift index e48b673..afed9db 100644 --- a/DomainReportBuilder.swift +++ b/DomainReportBuilder.swift @@ -34,6 +34,11 @@ struct DomainReport: Codable { let riskAssessment: DomainRiskAssessment let insights: [String] let changeSummary: DomainChangeSummary? + let lastChangeDate: Date? + let health: DomainHealth + let lastMonitoringFailure: Date? + let instabilityScore: Int + let certificateExpiryState: CertificateWarningLevel let workflowContext: DomainWorkflowContext? let metadata: DomainReportMetadata } @@ -223,7 +228,29 @@ struct DomainReportBuilder { primaryIP: String?, changeSummary: DomainChangeSummary? ) -> DomainReport { - DomainReport( + let certificateExpiryState = DomainDiffService.certificateWarningLevel(for: snapshot) + let recentChangeCount = changeSummary?.hasChanges == true ? 1 : 0 + let instabilityScore = DomainHealth.instabilityScore( + recentChangeCount: recentChangeCount, + recentFailureCount: 0, + pendingAlertCount: 0, + hasRecentDNSChange: changeSummary?.changedSections.contains(where: { $0.localizedCaseInsensitiveContains("dns") }) == true + ) + let hasInvalidTLS = snapshot.sslInfo == nil && snapshot.sslError != nil + let isReachable = !snapshot.reachabilityResults.isEmpty + ? snapshot.reachabilityResults.contains(where: \.reachable) + : snapshot.reachabilityError == nil + let health = DomainHealth.classify( + certificateExpiryState: certificateExpiryState, + isReachable: isReachable, + recentMonitoringFailureCount: 0, + hasRecentDNSChange: changeSummary?.changedSections.contains(where: { $0.localizedCaseInsensitiveContains("dns") }) == true, + instabilityScore: instabilityScore, + hasRecentCriticalChange: changeSummary?.impactClassification == .critical, + hasInvalidTLS: hasInvalidTLS + ) + + return DomainReport( domain: snapshot.domain, timestamp: snapshot.timestamp, provenance: DomainReportProvenance( @@ -309,6 +336,11 @@ struct DomainReportBuilder { riskAssessment: analysis.riskAssessment, insights: analysis.insights, changeSummary: changeSummary, + lastChangeDate: changeSummary?.hasChanges == true ? snapshot.timestamp : nil, + health: health, + lastMonitoringFailure: nil, + instabilityScore: instabilityScore, + certificateExpiryState: certificateExpiryState, workflowContext: workflowContext, metadata: DomainReportMetadata( schemaVersion: "3.7.0", -- cgit v1.2.3