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>
203 lines
5.2 KiB
TypeScript
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'
|
|
}
|