Files
breakpilot-compliance/admin-compliance/lib/sdk/vendor-compliance/contract-review/findings.ts
Sharang Parnerkar 91063f09b8 refactor(admin): split lib document generators and data catalogs into domain barrels
obligations-document, tom-document, loeschfristen-document, compliance-scope-triggers,
sdk-flow/flow-data, processing-activities, loeschfristen-baseline-catalog,
catalog-registry, dsfa mitigation-library + risk-catalog, vvt-baseline-catalog,
vendor contract-review checklists + findings, demo-data, tom-compliance.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 00:07:03 +02:00

203 lines
5.2 KiB
TypeScript

/**
* Finding Types and Templates
*
* Pre-defined finding templates for contract reviews.
* Barrel re-export — FINDING_TEMPLATES lives in findings-templates.ts.
*/
import {
FindingType,
FindingCategory,
FindingSeverity,
LocalizedText,
} from '../types'
// ==========================================
// FINDING SEVERITY DEFINITIONS
// ==========================================
export const SEVERITY_DEFINITIONS: Record<FindingSeverity, {
label: LocalizedText
description: LocalizedText
responseTime: LocalizedText
color: string
}> = {
LOW: {
label: { de: 'Niedrig', en: 'Low' },
description: {
de: 'Geringfügige Abweichung ohne wesentliche Auswirkungen',
en: 'Minor deviation without significant impact',
},
responseTime: {
de: 'Bei nächster Vertragserneuerung',
en: 'At next contract renewal',
},
color: 'blue',
},
MEDIUM: {
label: { de: 'Mittel', en: 'Medium' },
description: {
de: 'Abweichung mit potenziellen Auswirkungen auf Compliance',
en: 'Deviation with potential impact on compliance',
},
responseTime: {
de: 'Innerhalb von 90 Tagen',
en: 'Within 90 days',
},
color: 'yellow',
},
HIGH: {
label: { de: 'Hoch', en: 'High' },
description: {
de: 'Erhebliche Abweichung mit Auswirkungen auf Datenschutz-Compliance',
en: 'Significant deviation with impact on data protection compliance',
},
responseTime: {
de: 'Innerhalb von 30 Tagen',
en: 'Within 30 days',
},
color: 'orange',
},
CRITICAL: {
label: { de: 'Kritisch', en: 'Critical' },
description: {
de: 'Schwerwiegende Abweichung - unmittelbarer Handlungsbedarf',
en: 'Serious deviation - immediate action required',
},
responseTime: {
de: 'Sofort / vor Vertragsabschluss',
en: 'Immediately / before contract signing',
},
color: 'red',
},
}
// ==========================================
// FINDING TYPE DEFINITIONS
// ==========================================
export const FINDING_TYPE_DEFINITIONS: Record<FindingType, {
label: LocalizedText
description: LocalizedText
icon: string
}> = {
OK: {
label: { de: 'Erfüllt', en: 'Fulfilled' },
description: {
de: 'Anforderung ist vollständig erfüllt',
en: 'Requirement is fully met',
},
icon: 'check-circle',
},
GAP: {
label: { de: 'Lücke', en: 'Gap' },
description: {
de: 'Anforderung fehlt oder ist unvollständig',
en: 'Requirement is missing or incomplete',
},
icon: 'alert-circle',
},
RISK: {
label: { de: 'Risiko', en: 'Risk' },
description: {
de: 'Potenzielles Risiko identifiziert',
en: 'Potential risk identified',
},
icon: 'alert-triangle',
},
UNKNOWN: {
label: { de: 'Unklar', en: 'Unknown' },
description: {
de: 'Nicht eindeutig bestimmbar',
en: 'Cannot be clearly determined',
},
icon: 'help-circle',
},
}
import { FINDING_TEMPLATES } from './findings-templates'
import type { FindingTemplate } from './findings-templates'
export type { FindingTemplate }
export { FINDING_TEMPLATES }
// ==========================================
// HELPER FUNCTIONS
// ==========================================
/**
* Get finding template by ID
*/
export function getFindingTemplateById(id: string): FindingTemplate | undefined {
return FINDING_TEMPLATES.find((t) => t.id === id)
}
/**
* Get finding templates by category
*/
export function getFindingTemplatesByCategory(category: FindingCategory): FindingTemplate[] {
return FINDING_TEMPLATES.filter((t) => t.category === category)
}
/**
* Get finding templates by type
*/
export function getFindingTemplatesByType(type: FindingType): FindingTemplate[] {
return FINDING_TEMPLATES.filter((t) => t.type === type)
}
/**
* Get finding templates by severity
*/
export function getFindingTemplatesBySeverity(severity: FindingSeverity): FindingTemplate[] {
return FINDING_TEMPLATES.filter((t) => t.severity === severity)
}
/**
* Get severity color class
*/
export function getSeverityColorClass(severity: FindingSeverity): string {
return SEVERITY_DEFINITIONS[severity].color
}
/**
* Sort findings by severity (critical first)
*/
export function sortFindingsBySeverity<T extends { severity: FindingSeverity }>(
findings: T[]
): T[] {
const order: Record<FindingSeverity, number> = {
CRITICAL: 0,
HIGH: 1,
MEDIUM: 2,
LOW: 3,
}
return [...findings].sort((a, b) => order[a.severity] - order[b.severity])
}
/**
* Count findings by severity
*/
export function countFindingsBySeverity<T extends { severity: FindingSeverity }>(
findings: T[]
): Record<FindingSeverity, number> {
return findings.reduce(
(acc, f) => {
acc[f.severity] = (acc[f.severity] || 0) + 1
return acc
},
{ LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0 } as Record<FindingSeverity, number>
)
}
/**
* Get overall severity from list of findings
*/
export function getOverallSeverity(findings: { severity: FindingSeverity }[]): FindingSeverity {
if (findings.some((f) => f.severity === 'CRITICAL')) return 'CRITICAL'
if (findings.some((f) => f.severity === 'HIGH')) return 'HIGH'
if (findings.some((f) => f.severity === 'MEDIUM')) return 'MEDIUM'
return 'LOW'
}