use std::path::PathBuf;
use crate::cli::ReportLevel;
use crate::wcag::Severity;
pub type SignalDetails = Vec<(String, Vec<(String, bool, String)>)>;
pub struct ReportConfig {
pub level: ReportLevel,
pub logo_path: Option<PathBuf>,
pub locale: String,
pub history_preview: Option<ReportHistoryPreview>,
}
impl Default for ReportConfig {
fn default() -> Self {
Self {
level: ReportLevel::Standard,
logo_path: None,
locale: "de".to_string(),
history_preview: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum Priority {
Low,
Medium,
High,
Critical,
}
impl Priority {
pub fn label(&self) -> &'static str {
match self {
Priority::Critical => "Kritisch",
Priority::High => "Hoch",
Priority::Medium => "Mittel",
Priority::Low => "Niedrig",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Role {
Development,
Editorial,
DesignUx,
ProjectManagement,
}
impl Role {
pub fn label(&self) -> &'static str {
match self {
Role::Development => "Entwicklung",
Role::Editorial => "Redaktion",
Role::DesignUx => "Design / UX",
Role::ProjectManagement => "Projektleitung",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Effort {
Quick,
Medium,
Structural,
}
impl Effort {
pub fn label(&self) -> &'static str {
match self {
Effort::Quick => "Quick Win",
Effort::Medium => "Mittelfristig",
Effort::Structural => "Strukturell",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ExecutionPriority {
Optional,
Important,
Immediate,
}
impl ExecutionPriority {
pub fn label(&self) -> &'static str {
match self {
ExecutionPriority::Immediate => "Sofort beheben",
ExecutionPriority::Important => "Wichtig",
ExecutionPriority::Optional => "Optional",
}
}
}
pub struct FindingSummary {
pub total: usize,
pub critical: usize,
pub high: usize,
pub medium: usize,
pub low: usize,
pub verdict: String,
pub dominant_issue_note: Option<String>,
pub cross_impact_notes: Vec<String>,
pub issue_pattern_label: String,
}
pub struct TaskSummary {
pub blocker_count: usize,
pub high_count: usize,
pub medium_count: usize,
pub low_count: usize,
pub total_count: usize,
pub primary_role: String,
}
pub struct FindingCluster {
pub label: String,
pub dimension: String,
pub finding_count: usize,
pub occurrence_total: usize,
pub severity_label: String,
pub finding_titles: Vec<String>,
}
pub struct DiagnosisBlock {
pub section_title: String,
pub pattern_label: String,
pub pattern_description: String,
pub is_systematic: bool,
pub category_breakdown: Vec<(String, usize, String)>,
pub dominant_issue: Option<String>,
pub verdict_intro: String,
pub clusters: Vec<FindingCluster>,
}
pub struct ReportViewModel {
pub meta: MetaBlock,
pub cover: CoverBlock,
pub summary: SummaryBlock,
pub executive: ExecutiveNarrativeBlock,
pub history: Option<HistoryTrendBlock>,
pub methodology: MethodologyBlock,
pub modules: ModulesBlock,
pub severity: SeverityBlock,
pub findings: FindingsBlock,
pub diagnosis: DiagnosisBlock,
pub module_details: ModuleDetailsBlock,
pub actions: ActionsBlock,
pub appendix: AppendixBlock,
pub positive_signals: PositiveSignalsBlock,
}
pub struct PositiveSignalsBlock {
pub items: Vec<PositiveSignal>,
}
pub struct PositiveSignal {
pub title: String,
pub description: String,
pub strong: bool,
}
impl PositiveSignalsBlock {
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
}
pub struct MetaBlock {
pub title: String,
pub subtitle: String,
pub date: String,
pub version: String,
pub author: String,
pub report_level: ReportLevel,
pub score_label: String,
}
pub struct CoverBlock {
pub brand: String,
pub title: String,
pub domain: String,
pub subtitle: String,
pub date: String,
pub score: u32,
pub grade: String,
pub certificate: String,
pub maturity_label: String,
pub total_issues: u32,
pub critical_issues: u32,
pub modules: Vec<String>,
pub desktop_score: Option<u32>,
pub mobile_score: Option<u32>,
}
pub struct SummaryBlock {
pub score: u32,
pub overall_score: u32,
pub grade: String,
pub certificate: String,
pub maturity_label: String,
pub problem_type: String,
pub domain: String,
pub date: String,
pub executive_lead: String,
pub dominant_issue_note: Option<String>,
pub verdict: String,
pub score_note: Option<String>,
pub metrics: Vec<MetricItem>,
pub top_actions: Vec<String>,
pub positive_aspects: Vec<String>,
pub overall_impact: Vec<(String, String)>,
pub technical_overview: Vec<String>,
pub benchmark_context: String,
pub business_consequence: String,
pub consequence: String,
pub risk_level: String,
pub risk_summary: String,
}
pub struct ExecutiveNarrativeBlock {
pub cover_eyebrow: String,
pub cover_kicker: String,
pub status_title: String,
pub risk_title: String,
pub metrics_title: String,
pub key_points_title: String,
pub key_points: Vec<String>,
pub impact_title: String,
pub impact_rows: Vec<(String, String)>,
pub quick_actions_title: String,
pub quick_actions: Vec<String>,
pub spotlight_eyebrow: String,
pub spotlight_body: String,
pub spotlight_impact: String,
pub spotlight_recommendation: String,
pub leverage_title: String,
pub leverage_text: Option<String>,
pub findings_title: String,
pub findings_intro: String,
pub action_plan_title: String,
pub action_plan_intro: String,
pub action_plan_callout_title: String,
pub action_plan_callout_body: String,
pub technical_title: String,
pub technical_intro: String,
pub next_steps_title: String,
pub next_steps_intro: String,
pub next_steps_callout_title: String,
pub next_steps_callout_body: String,
}
pub struct MetricItem {
pub title: String,
pub value: String,
pub accent_color: Option<String>,
}
pub struct ReportHistoryPreview {
pub previous_date: String,
pub timeline_entries: usize,
pub previous_accessibility_score: u32,
pub previous_overall_score: u32,
pub delta_accessibility: i32,
pub delta_overall: i32,
pub delta_total_issues: i32,
pub delta_critical_issues: i32,
pub recent_entries: Vec<(String, u32, u32, String, u32)>,
pub new_findings: Vec<String>,
pub resolved_findings: Vec<String>,
}
pub struct HistoryTrendBlock {
pub previous_date: String,
pub timeline_entries: usize,
pub summary: String,
pub trend_label: String,
pub metrics: Vec<(String, String)>,
pub timeline_rows: Vec<(String, String, String, String, String)>,
pub new_findings: Vec<String>,
pub resolved_findings: Vec<String>,
}
pub struct MethodologyBlock {
pub scope: String,
pub method: String,
pub limitations: String,
pub disclaimer: String,
pub audit_facts: Vec<(String, String)>,
pub confidence_summary: Vec<(String, String)>,
pub capabilities: Vec<CapabilitySignal>,
}
pub struct ModulesBlock {
pub dashboard: Vec<ModuleScore>,
pub overall_score: Option<u32>,
pub overall_interpretation: Option<String>,
}
pub struct ModuleScore {
pub name: String,
pub score: u32,
pub measurement_type: String,
pub interpretation: String,
pub card_context: String,
pub score_context: String,
pub key_lever: String,
pub good_threshold: u32,
pub warn_threshold: u32,
}
pub struct SeverityBlock {
pub critical: u32,
pub high: u32,
pub medium: u32,
pub low: u32,
pub total: u32,
pub has_issues: bool,
pub component_issues: u32,
pub component_occurrences: u32,
}
pub struct FindingSeverityTier {
pub severity: Severity,
pub label: String,
pub findings: Vec<FindingGroup>,
pub total_occurrences: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum CriticalityTier {
Mandatory,
Optimization,
}
pub fn classify_criticality_tier(category: &str, wcag_level: &str) -> CriticalityTier {
if category == "wcag" && matches!(wcag_level, "A" | "AA") {
CriticalityTier::Mandatory
} else {
CriticalityTier::Optimization
}
}
pub struct FindingCriticalityGroup {
pub tier: CriticalityTier,
pub label: String,
pub eyebrow: String,
pub intro: String,
pub by_severity: Vec<FindingSeverityTier>,
pub total_findings: usize,
pub total_occurrences: usize,
}
pub struct FindingsBlock {
pub summary: FindingSummary,
pub clusters: Vec<FindingCluster>,
pub top_findings: Vec<FindingGroup>,
pub all_findings: Vec<FindingGroup>,
pub by_severity: Vec<FindingSeverityTier>,
pub by_tier: Vec<FindingCriticalityGroup>,
}
pub struct ModuleDetailsBlock {
pub performance: Option<PerformancePresentation>,
pub seo: Option<SeoPresentation>,
pub security: Option<SecurityPresentation>,
pub mobile: Option<MobilePresentation>,
pub ux: Option<UxPresentation>,
pub journey: Option<JourneyPresentation>,
pub dark_mode: Option<DarkModePresentation>,
pub source_quality: Option<crate::source_quality::SourceQualityAnalysis>,
pub ai_visibility: Option<crate::ai_visibility::AiVisibilityAnalysis>,
pub tech_stack: Option<crate::tech_stack::TechStackAnalysis>,
pub content_visibility: Option<crate::content_visibility::ContentVisibilityAnalysis>,
pub best_practices: Option<crate::best_practices::BestPracticesAnalysis>,
pub has_any: bool,
}
pub struct DarkModePresentation {
pub supported: bool,
pub score: u32,
pub detection_methods: Vec<String>,
pub color_scheme_css: bool,
pub meta_color_scheme: Option<String>,
pub css_custom_properties: u32,
pub dark_contrast_violations: u32,
pub dark_only_violations: u32,
pub light_only_violations: u32,
pub issues: Vec<(String, String)>,
}
pub struct ActionsBlock {
pub roadmap_columns: Vec<RoadmapColumnData>,
pub role_assignments: Vec<RoleAssignment>,
pub intro_text: String,
pub phase_preview: Vec<PhasePreview>,
pub block_title: String,
pub task_summary: TaskSummary,
}
pub struct RoadmapColumnData {
pub title: String,
pub accent_color: String,
pub items: Vec<RoadmapItemData>,
}
pub struct RoadmapItemData {
pub action: String,
pub role: String,
pub priority: String,
pub execution_priority: String,
pub effort: String,
pub benefit: String,
pub user_effect: String,
pub risk_effect: String,
pub conversion_effect: String,
}
pub struct PhasePreview {
pub phase_label: String,
pub accent_color: String,
pub description: String,
pub item_count: usize,
pub top_items: Vec<String>,
}
pub struct AppendixBlock {
pub violations: Vec<AppendixViolation>,
pub score_methodology: String,
pub has_violations: bool,
}
pub struct NarrativeArc {
pub diagnose: String,
pub ursache: String,
pub wirkung: String,
pub umsetzung: String,
}
pub struct FindingGroup {
pub title: String,
pub rule_id: String,
pub wcag_criterion: String,
pub wcag_level: String,
pub help_url: Option<String>,
pub dimension: Option<String>,
pub subcategory: Option<String>,
pub issue_class: Option<String>,
pub severity: Severity,
pub priority: Priority,
pub customer_description: String,
pub user_impact: String,
pub business_impact: String,
pub typical_cause: String,
pub recommendation: String,
pub technical_note: String,
pub occurrence_count: usize,
pub affected_urls: Vec<String>,
pub affected_elements: usize,
pub additional_occurrences: usize,
pub pattern_clusters: Vec<FindingPatternCluster>,
pub location_hints: Vec<String>,
pub representative_occurrences: Vec<RepresentativeOccurrence>,
pub responsible_role: Role,
pub effort: Effort,
pub execution_priority: ExecutionPriority,
pub examples: Vec<ExampleBlock>,
pub structural_cause: Option<String>,
pub is_component_issue: bool,
pub criticality_tier: CriticalityTier,
pub narrative: NarrativeArc,
}
pub struct RepresentativeOccurrence {
pub selector: String,
pub node_id: String,
pub message: String,
pub html_snippet: Option<String>,
pub suggested_code: Option<String>,
}
pub struct FindingPatternCluster {
pub label: String,
pub occurrences: usize,
}
pub struct CapabilitySignal {
pub signal: String,
pub source: String,
pub confidence: String,
pub surfaces: Vec<String>,
pub note: String,
}
pub struct ExampleBlock {
pub bad: String,
pub good: String,
pub decorative: Option<String>,
}
pub struct PositiveAspect {
pub area: String,
pub description: String,
}
#[derive(Debug, Clone)]
pub struct PerformanceViewport {
pub score: u32,
pub grade: String,
pub vitals: Vec<(String, String, String)>,
}
pub struct ThrottledPerfEntry {
pub profile_name: String,
pub lcp: String,
pub tbt: String,
pub cls: String,
pub score: u32,
}
pub struct ThirdPartyOriginRow {
pub origin: String,
pub request_count: u32,
pub transfer_kb: f64,
pub resource_kinds: String,
}
pub struct ThirdPartyPresentation {
pub origins: Vec<ThirdPartyOriginRow>,
pub total_origins: u32,
pub total_kb: f64,
pub total_requests: u32,
pub is_significant: bool,
}
pub struct CriticalChainPresentation {
pub max_depth: usize,
pub critical_path_ms: String,
pub critical_path_kb: String,
pub total_requests: usize,
}
pub struct MinificationPresentation {
pub total_count: usize,
pub total_savings_kb: f64,
pub top_assets: Vec<(String, String, String)>, }
pub struct CoveragePresentation {
pub js_used_pct: Option<f64>,
pub js_unused_kb: Option<f64>,
pub css_used_pct: Option<f64>,
pub css_total_rules: Option<u32>,
pub css_used_rules: Option<u32>,
}
pub struct AnimationPresentation {
pub total_count: usize,
pub affected_properties: Vec<String>,
pub findings: Vec<(String, String, String)>, }
pub struct OversizedImageRow {
pub src: String,
pub natural: String,
pub display: String,
}
pub struct ImageEfficiencyPresentation {
pub total_images: usize,
pub modern_format_pct: f64,
pub legacy_count: usize,
pub oversized: Vec<OversizedImageRow>,
}
pub struct PerformancePresentation {
pub score: u32,
pub grade: String,
pub interpretation: String,
pub vitals: Vec<(String, String, String)>,
pub desktop: Option<PerformanceViewport>,
pub mobile: Option<PerformanceViewport>,
pub additional_metrics: Vec<(String, String)>,
pub recommendations: Vec<String>,
pub render_blocking_metrics: Vec<(String, String)>,
pub render_blocking_suggestions: Vec<String>,
pub has_render_blocking: bool,
pub throttled_profiles: Vec<ThrottledPerfEntry>,
pub cls_attribution: Vec<(String, String, String)>,
pub third_party: Option<ThirdPartyPresentation>,
pub critical_chain: Option<CriticalChainPresentation>,
pub minification: Option<MinificationPresentation>,
pub coverage: Option<CoveragePresentation>,
pub animations: Option<AnimationPresentation>,
}
pub struct SeoPresentation {
pub score: u32,
pub interpretation: String,
pub meta_tags: Vec<(String, String)>,
pub meta_issues: Vec<(String, Severity, String)>,
pub heading_summary: String,
pub social_summary: String,
pub technical_summary: Vec<(String, String)>,
pub tracking_summary: Vec<(String, String)>,
pub tracking_summary_text: String,
pub profile: Option<SeoProfilePresentation>,
pub robots: Option<RobotsPresentation>,
pub page_health: Option<PageHealthPresentation>,
pub serp: Option<SerpPresentation>,
pub image_efficiency: Option<ImageEfficiencyPresentation>,
}
pub struct SerpPresentation {
pub score: u32,
pub pass_count: u32,
pub warning_count: u32,
pub fail_count: u32,
pub signals: Vec<(String, String, String, String)>,
pub rich_result_types: Vec<String>,
}
pub struct PageHealthPresentation {
pub issues: Vec<(String, String, String)>,
pub url_info: Vec<(String, String)>,
pub html_issues: Vec<(String, u32, String, String)>,
pub html_validator: Option<(String, String)>,
pub www_status: Option<(String, String, bool)>,
pub soft_404: Option<(u16, bool)>,
pub has_any_issue: bool,
}
pub struct RobotsPresentation {
pub error: Option<String>,
pub has_wildcard_disallow_all: bool,
pub blocks_ai_crawlers: bool,
pub blocks_ai_citation: bool,
pub inferred_policy: String,
pub sitemaps: Vec<String>,
pub crawl_delays: Vec<(String, u32)>,
pub bot_rows: Vec<(String, String, usize, usize, bool)>,
pub blocked_ai_bots: Vec<String>,
}
pub struct SeoProfilePresentation {
pub identity_summary: String,
pub site_name: String,
pub content_type: String,
pub language: String,
pub category_hints: Vec<String>,
pub identity_facts: Vec<(String, String)>,
pub page_type: String,
pub page_attributes: Vec<String>,
pub content_depth_score: u32,
pub structural_richness_score: u32,
pub media_text_balance_score: u32,
pub intent_fit_score: u32,
pub page_profile_summary: String,
pub optimization_note: String,
pub page_profile_facts: Vec<(String, String)>,
pub schema_rows: Vec<(String, String, String)>,
pub schema_count: usize,
pub signal_rows: Vec<(String, String, String)>,
pub signal_overall_pct: u32,
pub signal_details: SignalDetails,
pub maturity_level: String,
pub maturity_description: String,
pub maturity_techniques_used: u32,
pub maturity_techniques_total: u32,
}
pub struct SecurityPresentation {
pub score: u32,
pub grade: String,
pub interpretation: String,
pub headers: Vec<(String, String, String)>,
pub ssl_info: Vec<(String, String)>,
pub issues: Vec<(String, Severity, String)>,
pub recommendations: Vec<String>,
pub protection: Vec<(String, String)>,
pub has_waf: bool,
pub has_cdn: bool,
}
pub struct MobilePresentation {
pub score: u32,
pub interpretation: String,
pub viewport: Vec<(String, String)>,
pub touch_targets: Vec<(String, String)>,
pub font_analysis: Vec<(String, String)>,
pub content_sizing: Vec<(String, String)>,
pub issues: Vec<(String, Severity, String)>,
}
pub struct UxPresentation {
pub score: u32,
pub grade: String,
pub interpretation: String,
pub dimensions: Vec<UxDimensionPresentation>,
pub issues: Vec<UxIssuePresentation>,
}
pub struct UxDimensionPresentation {
pub name: String,
pub score: u32,
pub summary: String,
}
pub struct UxIssuePresentation {
pub dimension: String,
pub severity: String,
pub problem: String,
pub impact: String,
pub recommendation: String,
}
pub struct JourneyPresentation {
pub score: u32,
pub grade: String,
pub page_intent: String,
pub interpretation: String,
pub dimensions: Vec<JourneyDimensionPresentation>,
pub friction_points: Vec<FrictionPointPresentation>,
}
pub struct JourneyDimensionPresentation {
pub name: String,
pub score: u32,
pub weight_pct: u32,
pub summary: String,
}
pub struct FrictionPointPresentation {
pub step: String,
pub severity: String,
pub problem: String,
pub impact: String,
pub recommendation: String,
}
#[derive(Clone)]
pub struct ActionItem {
pub action: String,
pub benefit: String,
pub role: Role,
pub priority: Priority,
pub execution_priority: ExecutionPriority,
pub effort: Effort,
}
pub struct RoleAssignment {
pub role: Role,
pub responsibilities: Vec<String>,
}
pub struct AppendixViolation {
pub rule: String,
pub rule_name: String,
pub severity: Severity,
pub message: String,
pub fix_suggestion: Option<String>,
pub affected_elements: Vec<AffectedElement>,
}
pub struct AffectedElement {
pub selector: String,
pub node_id: String,
}
pub struct CoverData {
pub title: String,
pub url: String,
pub date: String,
pub version: String,
}
pub struct BatchPresentation {
pub cover: CoverData,
pub portfolio_summary: PortfolioSummary,
pub top_issues: Vec<FindingGroup>,
pub issue_frequency: Vec<IssueFrequency>,
pub action_plan: ActionPlan,
pub url_ranking: Vec<UrlSummary>,
pub url_details: Vec<CompactUrlSummary>,
pub url_matrix: Vec<UrlMatrixRow>,
pub appendix: BatchAppendixData,
}
pub struct ActionPlan {
pub quick_wins: Vec<ActionItem>,
pub medium_term: Vec<ActionItem>,
pub structural: Vec<ActionItem>,
pub role_assignments: Vec<RoleAssignment>,
}
pub struct PortfolioSummary {
pub total_urls: usize,
pub passed: usize,
pub failed: usize,
pub average_score: f64,
pub average_overall_score: u32,
pub total_violations: usize,
pub duration_ms: u64,
pub verdict_text: String,
pub worst_urls: Vec<(String, f32)>,
pub best_urls: Vec<(String, f32)>,
pub severity_distribution: SeverityDistribution,
pub risk_level: String,
pub risk_summary: String,
pub module_averages: Vec<(String, u32)>,
pub active_modules: Vec<String>,
pub domain: String,
pub certificate: String,
pub grade: String,
pub page_type_distribution: Vec<(String, usize, u32)>,
pub distribution_insights: Vec<String>,
pub strongest_content_pages: Vec<(String, String, u32)>,
pub weakest_content_pages: Vec<(String, String, u32)>,
pub top_topics: Vec<(String, usize)>,
pub overlap_pairs: Vec<(String, String, u32)>,
pub near_duplicates: Vec<(String, String, u8)>,
pub crawl_links: Option<CrawlLinkSummary>,
pub budget_summary: Vec<(String, String, usize, String)>,
pub render_blocking_summary: Vec<(String, String)>,
pub schema_distribution: Vec<(String, usize)>,
pub pages_without_schema: usize,
}
pub struct CrawlLinkSummary {
pub seed_url: String,
pub checked_internal_links: usize,
pub broken_internal_links: Vec<BrokenLinkRow>,
pub checked_external_links: usize,
pub broken_external_links: Vec<BrokenLinkRow>,
pub redirect_chains: Vec<RedirectChainRow>,
}
pub struct BrokenLinkRow {
pub source_url: String,
pub target_url: String,
pub status: String,
pub is_external: bool,
pub severity: String,
pub redirect_hops: u8,
}
pub struct RedirectChainRow {
pub source_url: String,
pub target_url: String,
pub final_url: String,
pub hops: u8,
pub is_external: bool,
}
pub struct SeverityDistribution {
pub critical: usize,
pub high: usize,
pub medium: usize,
pub low: usize,
}
pub struct IssueFrequency {
pub problem: String,
pub wcag: String,
pub occurrences: usize,
pub affected_urls: usize,
pub priority: Priority,
}
pub struct UrlSummary {
pub url: String,
pub score: f32,
pub overall_score: u32,
pub grade: String,
pub critical_violations: usize,
pub total_violations: usize,
pub passed: bool,
pub priority: Priority,
}
pub struct CompactUrlSummary {
pub url: String,
pub score: f32,
pub grade: String,
pub critical_violations: usize,
pub total_violations: usize,
pub page_type: Option<String>,
pub page_attributes: Vec<String>,
pub page_semantic_score: Option<u32>,
pub biggest_lever: String,
pub topic_terms: Vec<String>,
pub top_issues: Vec<String>,
pub module_scores: Vec<(String, u32)>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct UrlMatrixRow {
pub rank: usize,
pub url: String,
pub title: Option<String>,
pub inbound_links: usize,
pub outbound_links: u32,
pub word_count: u32,
}
pub struct BatchAppendixData {
pub per_url: Vec<UrlAppendix>,
}
pub struct UrlAppendix {
pub url: String,
pub violations: Vec<AppendixViolation>,
}