feat(admin-v2): Major SDK/Compliance overhaul and new modules
SDK modules added/enhanced: - compliance-hub, compliance-scope, consent-management, notfallplan - audit-report, workflow, source-policy, dsms - advisory-board documentation section - TOM dashboard components, TOM generator SDM mapping - DSFA: mitigation library, risk catalog, threshold analysis, source attribution - VVT: baseline catalog, profiling engine, types - Loeschfristen: baseline catalog, compliance engine, export, profiling, types - Compliance scope: engine, profiling, golden tests, types Existing SDK pages updated: - dsfa/[id], tom, vvt, loeschfristen, advisory-board — expanded functionality - SDKSidebar, StepHeader — new navigation items and layout - SDK layout, context, types — expanded type system Other admin-v2 changes: - AI agents page, RAG pipeline DSFA integration - GridOverlay component updates - Companion feature (development + education) - Compliance advisor SOUL definition Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
492
admin-v2/lib/sdk/vvt-profiling.ts
Normal file
492
admin-v2/lib/sdk/vvt-profiling.ts
Normal file
@@ -0,0 +1,492 @@
|
||||
/**
|
||||
* VVT Profiling — Generator-Fragebogen
|
||||
*
|
||||
* ~25 Fragen in 6 Schritten, die auf Basis der Antworten
|
||||
* Baseline-Verarbeitungstaetigkeiten generieren.
|
||||
*/
|
||||
|
||||
import { VVT_BASELINE_CATALOG, templateToActivity } from './vvt-baseline-catalog'
|
||||
import { generateVVTId } from './vvt-types'
|
||||
import type { VVTActivity, BusinessFunction } from './vvt-types'
|
||||
|
||||
// =============================================================================
|
||||
// TYPES
|
||||
// =============================================================================
|
||||
|
||||
export interface ProfilingQuestion {
|
||||
id: string
|
||||
step: number
|
||||
question: string
|
||||
type: 'single_choice' | 'multi_choice' | 'number' | 'text' | 'boolean'
|
||||
options?: { value: string; label: string }[]
|
||||
helpText?: string
|
||||
triggersTemplates: string[] // Template-IDs that get activated when answered positively
|
||||
}
|
||||
|
||||
export interface ProfilingStep {
|
||||
step: number
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
export interface ProfilingAnswers {
|
||||
[questionId: string]: string | string[] | number | boolean
|
||||
}
|
||||
|
||||
export interface ProfilingResult {
|
||||
answers: ProfilingAnswers
|
||||
generatedActivities: VVTActivity[]
|
||||
coverageScore: number
|
||||
art30Abs5Exempt: boolean
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// STEPS
|
||||
// =============================================================================
|
||||
|
||||
export const PROFILING_STEPS: ProfilingStep[] = [
|
||||
{ step: 1, title: 'Organisation', description: 'Grunddaten zu Ihrem Unternehmen' },
|
||||
{ step: 2, title: 'Geschaeftsbereiche', description: 'Welche Bereiche sind aktiv?' },
|
||||
{ step: 3, title: 'Systeme & Tools', description: 'Welche IT-Systeme nutzen Sie?' },
|
||||
{ step: 4, title: 'Datenkategorien', description: 'Welche besonderen Daten verarbeiten Sie?' },
|
||||
{ step: 5, title: 'Drittlandtransfers', description: 'Transfers ausserhalb der EU/EWR' },
|
||||
{ step: 6, title: 'Besondere Verarbeitungen', description: 'KI, Scoring, Ueberwachung' },
|
||||
]
|
||||
|
||||
// =============================================================================
|
||||
// QUESTIONS
|
||||
// =============================================================================
|
||||
|
||||
export const PROFILING_QUESTIONS: ProfilingQuestion[] = [
|
||||
// === STEP 1: Organisation ===
|
||||
{
|
||||
id: 'org_industry',
|
||||
step: 1,
|
||||
question: 'In welcher Branche ist Ihr Unternehmen taetig?',
|
||||
type: 'single_choice',
|
||||
options: [
|
||||
{ value: 'it_software', label: 'IT & Software' },
|
||||
{ value: 'healthcare', label: 'Gesundheitswesen' },
|
||||
{ value: 'education', label: 'Bildung & Erziehung' },
|
||||
{ value: 'finance', label: 'Finanzdienstleistungen' },
|
||||
{ value: 'retail', label: 'Handel & E-Commerce' },
|
||||
{ value: 'manufacturing', label: 'Produktion & Industrie' },
|
||||
{ value: 'consulting', label: 'Beratung & Dienstleistung' },
|
||||
{ value: 'public', label: 'Oeffentlicher Sektor' },
|
||||
{ value: 'other', label: 'Sonstige' },
|
||||
],
|
||||
triggersTemplates: [],
|
||||
},
|
||||
{
|
||||
id: 'org_employees',
|
||||
step: 1,
|
||||
question: 'Wie viele Mitarbeiter hat Ihr Unternehmen?',
|
||||
type: 'number',
|
||||
helpText: 'Relevant fuer Art. 30 Abs. 5 DSGVO (Ausnahme < 250 Mitarbeiter)',
|
||||
triggersTemplates: [],
|
||||
},
|
||||
{
|
||||
id: 'org_locations',
|
||||
step: 1,
|
||||
question: 'An wie vielen Standorten ist Ihr Unternehmen taetig?',
|
||||
type: 'single_choice',
|
||||
options: [
|
||||
{ value: '1', label: '1 Standort' },
|
||||
{ value: '2-5', label: '2-5 Standorte' },
|
||||
{ value: '6-20', label: '6-20 Standorte' },
|
||||
{ value: '20+', label: 'Mehr als 20 Standorte' },
|
||||
],
|
||||
triggersTemplates: [],
|
||||
},
|
||||
{
|
||||
id: 'org_b2b_b2c',
|
||||
step: 1,
|
||||
question: 'Welches Geschaeftsmodell betreiben Sie?',
|
||||
type: 'single_choice',
|
||||
options: [
|
||||
{ value: 'b2b', label: 'B2B (Geschaeftskunden)' },
|
||||
{ value: 'b2c', label: 'B2C (Endkunden)' },
|
||||
{ value: 'both', label: 'Beides (B2B + B2C)' },
|
||||
{ value: 'b2g', label: 'B2G (Oeffentlicher Sektor)' },
|
||||
],
|
||||
triggersTemplates: [],
|
||||
},
|
||||
|
||||
// === STEP 2: Geschaeftsbereiche ===
|
||||
{
|
||||
id: 'dept_hr',
|
||||
step: 2,
|
||||
question: 'Haben Sie eine Personalabteilung / HR?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: ['hr-mitarbeiterverwaltung', 'hr-gehaltsabrechnung', 'hr-zeiterfassung'],
|
||||
},
|
||||
{
|
||||
id: 'dept_recruiting',
|
||||
step: 2,
|
||||
question: 'Betreiben Sie aktives Recruiting / Bewerbermanagement?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: ['hr-bewerbermanagement'],
|
||||
},
|
||||
{
|
||||
id: 'dept_finance',
|
||||
step: 2,
|
||||
question: 'Haben Sie eine Finanz-/Buchhaltungsabteilung?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: ['finance-buchhaltung', 'finance-zahlungsverkehr'],
|
||||
},
|
||||
{
|
||||
id: 'dept_sales',
|
||||
step: 2,
|
||||
question: 'Haben Sie einen Vertrieb / Kundenverwaltung?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: ['sales-kundenverwaltung', 'sales-vertriebssteuerung'],
|
||||
},
|
||||
{
|
||||
id: 'dept_marketing',
|
||||
step: 2,
|
||||
question: 'Betreiben Sie Marketing-Aktivitaeten?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: ['marketing-social-media'],
|
||||
},
|
||||
{
|
||||
id: 'dept_support',
|
||||
step: 2,
|
||||
question: 'Haben Sie einen Kundenservice / Support?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: ['support-ticketsystem'],
|
||||
},
|
||||
|
||||
// === STEP 3: Systeme & Tools ===
|
||||
{
|
||||
id: 'sys_crm',
|
||||
step: 3,
|
||||
question: 'Nutzen Sie ein CRM-System (z.B. Salesforce, HubSpot, Pipedrive)?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: ['sales-kundenverwaltung'],
|
||||
},
|
||||
{
|
||||
id: 'sys_website_analytics',
|
||||
step: 3,
|
||||
question: 'Nutzen Sie Website-Analytics (z.B. Matomo, Google Analytics)?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: ['marketing-website-analytics'],
|
||||
},
|
||||
{
|
||||
id: 'sys_newsletter',
|
||||
step: 3,
|
||||
question: 'Versenden Sie Newsletter (z.B. Mailchimp, CleverReach)?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: ['marketing-newsletter'],
|
||||
},
|
||||
{
|
||||
id: 'sys_video',
|
||||
step: 3,
|
||||
question: 'Nutzen Sie Videokonferenz-Tools (z.B. Zoom, Teams, Jitsi)?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: ['other-videokonferenz'],
|
||||
},
|
||||
{
|
||||
id: 'sys_erp',
|
||||
step: 3,
|
||||
question: 'Nutzen Sie ein ERP-System?',
|
||||
type: 'boolean',
|
||||
helpText: 'z.B. SAP, ERPNext, Microsoft Dynamics',
|
||||
triggersTemplates: ['finance-buchhaltung'],
|
||||
},
|
||||
{
|
||||
id: 'sys_visitor',
|
||||
step: 3,
|
||||
question: 'Haben Sie ein Besuchermanagement-System?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: ['other-besuchermanagement'],
|
||||
},
|
||||
|
||||
// === STEP 4: Datenkategorien ===
|
||||
{
|
||||
id: 'data_health',
|
||||
step: 4,
|
||||
question: 'Verarbeiten Sie Gesundheitsdaten (Art. 9 DSGVO)?',
|
||||
type: 'boolean',
|
||||
helpText: 'z.B. Krankmeldungen, Arbeitsmedizin, Gesundheitsversorgung',
|
||||
triggersTemplates: [],
|
||||
},
|
||||
{
|
||||
id: 'data_minors',
|
||||
step: 4,
|
||||
question: 'Verarbeiten Sie Daten von Minderjaehrigen?',
|
||||
type: 'boolean',
|
||||
helpText: 'z.B. Schueler, Kinder unter 16 Jahren',
|
||||
triggersTemplates: [],
|
||||
},
|
||||
{
|
||||
id: 'data_biometric',
|
||||
step: 4,
|
||||
question: 'Verarbeiten Sie biometrische Daten zur Identifizierung?',
|
||||
type: 'boolean',
|
||||
helpText: 'z.B. Fingerabdruck, Gesichtserkennung, Stimmerkennung',
|
||||
triggersTemplates: [],
|
||||
},
|
||||
{
|
||||
id: 'data_criminal',
|
||||
step: 4,
|
||||
question: 'Verarbeiten Sie Daten ueber strafrechtliche Verurteilungen (Art. 10 DSGVO)?',
|
||||
type: 'boolean',
|
||||
helpText: 'z.B. Fuehrungszeugnisse',
|
||||
triggersTemplates: [],
|
||||
},
|
||||
|
||||
// === STEP 5: Drittlandtransfers ===
|
||||
{
|
||||
id: 'transfer_cloud_us',
|
||||
step: 5,
|
||||
question: 'Nutzen Sie Cloud-Dienste mit Sitz in den USA?',
|
||||
type: 'boolean',
|
||||
helpText: 'z.B. AWS, Azure, Google Cloud, Microsoft 365',
|
||||
triggersTemplates: [],
|
||||
},
|
||||
{
|
||||
id: 'transfer_support_non_eu',
|
||||
step: 5,
|
||||
question: 'Haben Sie Support-Mitarbeiter oder Dienstleister ausserhalb der EU?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: [],
|
||||
},
|
||||
{
|
||||
id: 'transfer_subprocessor',
|
||||
step: 5,
|
||||
question: 'Nutzen Sie Auftragsverarbeiter mit Unteraufragnehmern in Drittlaendern?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: [],
|
||||
},
|
||||
|
||||
// === STEP 6: Besondere Verarbeitungen ===
|
||||
{
|
||||
id: 'special_ai',
|
||||
step: 6,
|
||||
question: 'Setzen Sie KI oder automatisierte Entscheidungsfindung ein?',
|
||||
type: 'boolean',
|
||||
helpText: 'z.B. Chatbots, Scoring, Profiling, automatische Bewertungen',
|
||||
triggersTemplates: [],
|
||||
},
|
||||
{
|
||||
id: 'special_video_surveillance',
|
||||
step: 6,
|
||||
question: 'Betreiben Sie Videoueberwachung?',
|
||||
type: 'boolean',
|
||||
triggersTemplates: [],
|
||||
},
|
||||
{
|
||||
id: 'special_tracking',
|
||||
step: 6,
|
||||
question: 'Betreiben Sie umfangreiches Nutzer-Tracking oder Profiling?',
|
||||
type: 'boolean',
|
||||
helpText: 'z.B. Verhaltensprofiling, Cross-Device-Tracking',
|
||||
triggersTemplates: [],
|
||||
},
|
||||
]
|
||||
|
||||
// =============================================================================
|
||||
// GENERATOR LOGIC
|
||||
// =============================================================================
|
||||
|
||||
export function generateActivities(answers: ProfilingAnswers): ProfilingResult {
|
||||
// Collect all triggered template IDs
|
||||
const triggeredIds = new Set<string>()
|
||||
|
||||
for (const question of PROFILING_QUESTIONS) {
|
||||
const answer = answers[question.id]
|
||||
if (!answer) continue
|
||||
|
||||
// Boolean questions: if true, trigger templates
|
||||
if (question.type === 'boolean' && answer === true) {
|
||||
question.triggersTemplates.forEach(id => triggeredIds.add(id))
|
||||
}
|
||||
}
|
||||
|
||||
// Always add IT baseline templates (every company needs these)
|
||||
triggeredIds.add('it-systemadministration')
|
||||
triggeredIds.add('it-backup')
|
||||
triggeredIds.add('it-logging')
|
||||
triggeredIds.add('it-iam')
|
||||
|
||||
// Generate activities from triggered templates
|
||||
const existingIds: string[] = []
|
||||
const activities: VVTActivity[] = []
|
||||
|
||||
for (const templateId of triggeredIds) {
|
||||
const template = VVT_BASELINE_CATALOG.find(t => t.templateId === templateId)
|
||||
if (!template) continue
|
||||
|
||||
const vvtId = generateVVTId(existingIds)
|
||||
existingIds.push(vvtId)
|
||||
|
||||
const activity = templateToActivity(template, vvtId)
|
||||
|
||||
// Enrich with profiling answers
|
||||
enrichActivityFromAnswers(activity, answers)
|
||||
|
||||
activities.push(activity)
|
||||
}
|
||||
|
||||
// Calculate coverage score
|
||||
const totalFields = activities.length * 12 // 12 key fields per activity
|
||||
let filledFields = 0
|
||||
for (const a of activities) {
|
||||
if (a.name) filledFields++
|
||||
if (a.description) filledFields++
|
||||
if (a.purposes.length > 0) filledFields++
|
||||
if (a.legalBases.length > 0) filledFields++
|
||||
if (a.dataSubjectCategories.length > 0) filledFields++
|
||||
if (a.personalDataCategories.length > 0) filledFields++
|
||||
if (a.recipientCategories.length > 0) filledFields++
|
||||
if (a.retentionPeriod.description) filledFields++
|
||||
if (a.tomDescription) filledFields++
|
||||
if (a.businessFunction !== 'other') filledFields++
|
||||
if (a.structuredToms.accessControl.length > 0) filledFields++
|
||||
if (a.responsible || a.owner) filledFields++
|
||||
}
|
||||
|
||||
const coverageScore = totalFields > 0 ? Math.round((filledFields / totalFields) * 100) : 0
|
||||
|
||||
// Art. 30 Abs. 5 check
|
||||
const employeeCount = typeof answers.org_employees === 'number' ? answers.org_employees : 0
|
||||
const hasSpecialCategories = answers.data_health === true || answers.data_biometric === true || answers.data_criminal === true
|
||||
const art30Abs5Exempt = employeeCount < 250 && !hasSpecialCategories
|
||||
|
||||
return {
|
||||
answers,
|
||||
generatedActivities: activities,
|
||||
coverageScore,
|
||||
art30Abs5Exempt,
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// ENRICHMENT
|
||||
// =============================================================================
|
||||
|
||||
function enrichActivityFromAnswers(activity: VVTActivity, answers: ProfilingAnswers): void {
|
||||
// Add third-country transfers if US cloud is used
|
||||
if (answers.transfer_cloud_us === true) {
|
||||
activity.thirdCountryTransfers.push({
|
||||
country: 'US',
|
||||
recipient: 'Cloud-Dienstleister (USA)',
|
||||
transferMechanism: 'SCC_PROCESSOR',
|
||||
additionalMeasures: ['Verschluesselung at-rest', 'Transfer Impact Assessment'],
|
||||
})
|
||||
}
|
||||
|
||||
// Add special data categories if applicable
|
||||
if (answers.data_health === true) {
|
||||
if (!activity.personalDataCategories.includes('HEALTH_DATA')) {
|
||||
// Only add to HR activities
|
||||
if (activity.businessFunction === 'hr') {
|
||||
activity.personalDataCategories.push('HEALTH_DATA')
|
||||
// Ensure Art. 9 legal basis
|
||||
if (!activity.legalBases.some(lb => lb.type.startsWith('ART9_'))) {
|
||||
activity.legalBases.push({
|
||||
type: 'ART9_EMPLOYMENT',
|
||||
description: 'Arbeitsrechtliche Verarbeitung',
|
||||
reference: 'Art. 9 Abs. 2 lit. b DSGVO',
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (answers.data_minors === true) {
|
||||
if (!activity.dataSubjectCategories.includes('MINORS')) {
|
||||
// Add to relevant activities (education, app users)
|
||||
if (activity.businessFunction === 'support' || activity.businessFunction === 'product_engineering') {
|
||||
activity.dataSubjectCategories.push('MINORS')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set DPIA required for special processing
|
||||
if (answers.special_ai === true || answers.special_video_surveillance === true || answers.special_tracking === true) {
|
||||
if (answers.special_ai === true && activity.businessFunction === 'product_engineering') {
|
||||
activity.dpiaRequired = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// HELPERS
|
||||
// =============================================================================
|
||||
|
||||
export function getQuestionsForStep(step: number): ProfilingQuestion[] {
|
||||
return PROFILING_QUESTIONS.filter(q => q.step === step)
|
||||
}
|
||||
|
||||
export function getStepProgress(answers: ProfilingAnswers, step: number): number {
|
||||
const questions = getQuestionsForStep(step)
|
||||
if (questions.length === 0) return 100
|
||||
|
||||
const answered = questions.filter(q => {
|
||||
const a = answers[q.id]
|
||||
return a !== undefined && a !== null && a !== ''
|
||||
}).length
|
||||
|
||||
return Math.round((answered / questions.length) * 100)
|
||||
}
|
||||
|
||||
export function getTotalProgress(answers: ProfilingAnswers): number {
|
||||
const total = PROFILING_QUESTIONS.length
|
||||
if (total === 0) return 100
|
||||
|
||||
const answered = PROFILING_QUESTIONS.filter(q => {
|
||||
const a = answers[q.id]
|
||||
return a !== undefined && a !== null && a !== ''
|
||||
}).length
|
||||
|
||||
return Math.round((answered / total) * 100)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// COMPLIANCE SCOPE INTEGRATION
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Prefill VVT profiling answers from Compliance Scope Engine answers.
|
||||
* The Scope Engine acts as the "Single Source of Truth" for organizational questions.
|
||||
* Redundant questions are auto-filled with a "prefilled" marker.
|
||||
*/
|
||||
export function prefillFromScopeAnswers(
|
||||
scopeAnswers: import('./compliance-scope-types').ScopeProfilingAnswer[]
|
||||
): ProfilingAnswers {
|
||||
const { exportToVVTAnswers } = require('./compliance-scope-profiling')
|
||||
const exported = exportToVVTAnswers(scopeAnswers) as Record<string, unknown>
|
||||
const prefilled: ProfilingAnswers = {}
|
||||
|
||||
for (const [key, value] of Object.entries(exported)) {
|
||||
if (value !== undefined && value !== null) {
|
||||
prefilled[key] = value as string | string[] | number | boolean
|
||||
}
|
||||
}
|
||||
|
||||
return prefilled
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of VVT question IDs that are prefilled from Scope answers.
|
||||
* These questions should show "Aus Scope-Analyse uebernommen" hint.
|
||||
*/
|
||||
export const SCOPE_PREFILLED_VVT_QUESTIONS = [
|
||||
'org_industry',
|
||||
'org_employees',
|
||||
'org_b2b_b2c',
|
||||
'dept_hr',
|
||||
'dept_finance',
|
||||
'dept_marketing',
|
||||
'data_health',
|
||||
'data_minors',
|
||||
'data_biometric',
|
||||
'data_criminal',
|
||||
'special_ai',
|
||||
'special_video_surveillance',
|
||||
'special_tracking',
|
||||
'transfer_cloud_us',
|
||||
'transfer_subprocessor',
|
||||
'transfer_support_non_eu',
|
||||
]
|
||||
Reference in New Issue
Block a user