feat(sdk): Add Drafting Engine with 4-mode agent system (Explain/Ask/Draft/Validate)

Extends the Compliance Advisor from a Q&A chatbot into a full drafting engine
that can generate, validate, and refine compliance documents within Scope Engine
constraints. Includes intent classifier, state projector, constraint enforcer,
SOUL templates, Go backend endpoints, and React UI components.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
BreakPilot Dev
2026-02-11 12:37:18 +01:00
parent f927c0c205
commit 206183670d
26 changed files with 4639 additions and 1 deletions

View File

@@ -0,0 +1,49 @@
/**
* Gap Analysis Prompt - Lueckenanalyse und gezielte Fragen
*/
import type { GapContext } from '../types'
export interface GapAnalysisInput {
context: GapContext
instructions?: string
}
export function buildGapAnalysisPrompt(input: GapAnalysisInput): string {
const { context, instructions } = input
return `## Aufgabe: Compliance-Lueckenanalyse
### Identifizierte Luecken:
${context.gaps.length > 0
? context.gaps.map(g => `- [${g.severity}] ${g.title}: ${g.description}`).join('\n')
: '- Keine Luecken identifiziert'}
### Fehlende Pflichtdokumente:
${context.missingDocuments.length > 0
? context.missingDocuments.map(d => `- ${d.label} (Tiefe: ${d.depth}, Aufwand: ${d.estimatedEffort})`).join('\n')
: '- Alle Pflichtdokumente vorhanden'}
### Unbeantwortete Fragen:
${context.unansweredQuestions.length > 0
? context.unansweredQuestions.map(q => `- [${q.blockId}] ${q.question}`).join('\n')
: '- Alle Fragen beantwortet'}
${instructions ? `### Zusaetzliche Anweisungen: ${instructions}` : ''}
### Aufgabe:
Analysiere den Stand und stelle EINE gezielte Frage, die die wichtigste Luecke adressiert.
Priorisiere nach:
1. Fehlende Pflichtdokumente
2. Kritische Luecken (HIGH/CRITICAL severity)
3. Unbeantwortete Pflichtfragen
4. Mittlere Luecken
### Antwort-Format:
Antworte in dieser Struktur:
1. **Statusuebersicht**: Kurze Zusammenfassung des Compliance-Stands (2-3 Saetze)
2. **Wichtigste Luecke**: Was fehlt am dringendsten?
3. **Gezielte Frage**: Eine konkrete Frage an den Nutzer
4. **Warum wichtig**: Warum muss diese Luecke geschlossen werden?
5. **Empfohlener naechster Schritt**: Link/Verweis zum SDK-Modul`
}

View File

@@ -0,0 +1,91 @@
/**
* DSFA Draft Prompt - Datenschutz-Folgenabschaetzung (Art. 35 DSGVO)
*/
import type { DraftContext } from '../types'
export interface DSFADraftInput {
context: DraftContext
processingDescription?: string
instructions?: string
}
export function buildDSFADraftPrompt(input: DSFADraftInput): string {
const { context, processingDescription, instructions } = input
const level = context.decisions.level
const depthItems = context.constraints.depthRequirements.detailItems
const hardTriggers = context.decisions.hardTriggers
return `## Aufgabe: DSFA entwerfen (Art. 35 DSGVO)
### Unternehmensprofil
- Name: ${context.companyProfile.name}
- Branche: ${context.companyProfile.industry}
- Mitarbeiter: ${context.companyProfile.employeeCount}
### Compliance-Level: ${level}
Tiefe: ${context.constraints.depthRequirements.depth}
### Hard Triggers (Gruende fuer DSFA-Pflicht):
${hardTriggers.length > 0
? hardTriggers.map(t => `- ${t.id}: ${t.label} (${t.legalReference})`).join('\n')
: '- Keine Hard Triggers (DSFA auf Wunsch)'}
### Erforderliche Inhalte:
${depthItems.map((item, i) => `${i + 1}. ${item}`).join('\n')}
${processingDescription ? `### Beschreibung der Verarbeitung: ${processingDescription}` : ''}
${instructions ? `### Zusaetzliche Anweisungen: ${instructions}` : ''}
### Antwort-Format
Antworte als JSON:
{
"sections": [
{
"id": "beschreibung",
"title": "Systematische Beschreibung der Verarbeitung",
"content": "...",
"schemaField": "processingDescription"
},
{
"id": "notwendigkeit",
"title": "Notwendigkeit und Verhaeltnismaessigkeit",
"content": "...",
"schemaField": "necessityAssessment"
},
{
"id": "risikobewertung",
"title": "Bewertung der Risiken fuer die Rechte und Freiheiten",
"content": "...",
"schemaField": "riskAssessment"
},
{
"id": "massnahmen",
"title": "Massnahmen zur Eindaemmung der Risiken",
"content": "...",
"schemaField": "mitigationMeasures"
},
{
"id": "stellungnahme_dsb",
"title": "Stellungnahme des Datenschutzbeauftragten",
"content": "...",
"schemaField": "dpoOpinion"
},
{
"id": "standpunkt_betroffene",
"title": "Standpunkt der betroffenen Personen",
"content": "...",
"schemaField": "dataSubjectView"
},
{
"id": "ergebnis",
"title": "Ergebnis und Empfehlung",
"content": "...",
"schemaField": "conclusion"
}
]
}
Halte die Tiefe exakt auf Level ${level}.
Nutze WP248-Kriterien als Leitfaden fuer die Risikobewertung.`
}

View File

@@ -0,0 +1,78 @@
/**
* Loeschfristen Draft Prompt - Loeschkonzept
*/
import type { DraftContext } from '../types'
export interface LoeschfristenDraftInput {
context: DraftContext
instructions?: string
}
export function buildLoeschfristenDraftPrompt(input: LoeschfristenDraftInput): string {
const { context, instructions } = input
const level = context.decisions.level
const depthItems = context.constraints.depthRequirements.detailItems
return `## Aufgabe: Loeschkonzept / Loeschfristen entwerfen
### Unternehmensprofil
- Name: ${context.companyProfile.name}
- Branche: ${context.companyProfile.industry}
- Mitarbeiter: ${context.companyProfile.employeeCount}
### Compliance-Level: ${level}
Tiefe: ${context.constraints.depthRequirements.depth}
### Erforderliche Inhalte:
${depthItems.map((item, i) => `${i + 1}. ${item}`).join('\n')}
${context.existingDocumentData ? `### Bestehende Loeschfristen: ${JSON.stringify(context.existingDocumentData).slice(0, 500)}` : ''}
${instructions ? `### Zusaetzliche Anweisungen: ${instructions}` : ''}
### Antwort-Format
Antworte als JSON:
{
"sections": [
{
"id": "grundsaetze",
"title": "Grundsaetze der Datenlöschung",
"content": "...",
"schemaField": "principles"
},
{
"id": "kategorien",
"title": "Datenkategorien und Loeschfristen",
"content": "Tabellarische Uebersicht...",
"schemaField": "retentionSchedule"
},
{
"id": "gesetzliche_fristen",
"title": "Gesetzliche Aufbewahrungsfristen",
"content": "HGB, AO, weitere...",
"schemaField": "legalRetention"
},
{
"id": "loeschprozess",
"title": "Technischer Loeschprozess",
"content": "...",
"schemaField": "deletionProcess"
},
{
"id": "verantwortlichkeiten",
"title": "Verantwortlichkeiten",
"content": "...",
"schemaField": "responsibilities"
},
{
"id": "ausnahmen",
"title": "Ausnahmen und Sonderfaelle",
"content": "...",
"schemaField": "exceptions"
}
]
}
Halte die Tiefe exakt auf Level ${level}.
Beruecksichtige branchenspezifische Aufbewahrungsfristen fuer ${context.companyProfile.industry}.`
}

View File

@@ -0,0 +1,102 @@
/**
* Privacy Policy Draft Prompt - Datenschutzerklaerung (Art. 13/14 DSGVO)
*/
import type { DraftContext } from '../types'
export interface PrivacyPolicyDraftInput {
context: DraftContext
websiteUrl?: string
instructions?: string
}
export function buildPrivacyPolicyDraftPrompt(input: PrivacyPolicyDraftInput): string {
const { context, websiteUrl, instructions } = input
const level = context.decisions.level
const depthItems = context.constraints.depthRequirements.detailItems
return `## Aufgabe: Datenschutzerklaerung entwerfen (Art. 13/14 DSGVO)
### Unternehmensprofil
- Name: ${context.companyProfile.name}
- Branche: ${context.companyProfile.industry}
${context.companyProfile.dataProtectionOfficer ? `- DSB: ${context.companyProfile.dataProtectionOfficer.name} (${context.companyProfile.dataProtectionOfficer.email})` : ''}
${websiteUrl ? `- Website: ${websiteUrl}` : ''}
### Compliance-Level: ${level}
Tiefe: ${context.constraints.depthRequirements.depth}
### Erforderliche Inhalte:
${depthItems.map((item, i) => `${i + 1}. ${item}`).join('\n')}
${instructions ? `### Zusaetzliche Anweisungen: ${instructions}` : ''}
### Antwort-Format
Antworte als JSON:
{
"sections": [
{
"id": "verantwortlicher",
"title": "Verantwortlicher",
"content": "...",
"schemaField": "controller"
},
{
"id": "dsb",
"title": "Datenschutzbeauftragter",
"content": "...",
"schemaField": "dpo"
},
{
"id": "verarbeitungen",
"title": "Verarbeitungstaetigkeiten und Zwecke",
"content": "...",
"schemaField": "processingPurposes"
},
{
"id": "rechtsgrundlagen",
"title": "Rechtsgrundlagen der Verarbeitung",
"content": "...",
"schemaField": "legalBases"
},
{
"id": "empfaenger",
"title": "Empfaenger und Datenweitergabe",
"content": "...",
"schemaField": "recipients"
},
{
"id": "drittland",
"title": "Uebermittlung in Drittlaender",
"content": "...",
"schemaField": "thirdCountryTransfers"
},
{
"id": "speicherdauer",
"title": "Speicherdauer",
"content": "...",
"schemaField": "retentionPeriods"
},
{
"id": "betroffenenrechte",
"title": "Ihre Rechte als betroffene Person",
"content": "...",
"schemaField": "dataSubjectRights"
},
{
"id": "cookies",
"title": "Cookies und Tracking",
"content": "...",
"schemaField": "cookies"
},
{
"id": "aenderungen",
"title": "Aenderungen dieser Datenschutzerklaerung",
"content": "...",
"schemaField": "changes"
}
]
}
Halte die Tiefe exakt auf Level ${level}.`
}

View File

@@ -0,0 +1,99 @@
/**
* TOM Draft Prompt - Technische und Organisatorische Massnahmen (Art. 32 DSGVO)
*/
import type { DraftContext } from '../types'
export interface TOMDraftInput {
context: DraftContext
focusArea?: string
instructions?: string
}
export function buildTOMDraftPrompt(input: TOMDraftInput): string {
const { context, focusArea, instructions } = input
const level = context.decisions.level
const depthItems = context.constraints.depthRequirements.detailItems
return `## Aufgabe: TOM-Dokument entwerfen (Art. 32 DSGVO)
### Unternehmensprofil
- Name: ${context.companyProfile.name}
- Branche: ${context.companyProfile.industry}
- Mitarbeiter: ${context.companyProfile.employeeCount}
### Compliance-Level: ${level}
Tiefe: ${context.constraints.depthRequirements.depth}
### Erforderliche Inhalte fuer Level ${level}:
${depthItems.map((item, i) => `${i + 1}. ${item}`).join('\n')}
### Constraints
${context.constraints.boundaries.map(b => `- ${b}`).join('\n')}
${context.constraints.riskFlags.length > 0 ? `### Risiko-Flags
${context.constraints.riskFlags.map(f => `- [${f.severity}] ${f.title}`).join('\n')}` : ''}
${focusArea ? `### Fokusbereich: ${focusArea}` : ''}
${instructions ? `### Zusaetzliche Anweisungen: ${instructions}` : ''}
${context.existingDocumentData ? `### Bestehende TOM: ${JSON.stringify(context.existingDocumentData).slice(0, 500)}` : ''}
### Antwort-Format
Antworte als JSON:
{
"sections": [
{
"id": "zutrittskontrolle",
"title": "Zutrittskontrolle",
"content": "Massnahmen die unbefugten Zutritt zu Datenverarbeitungsanlagen verhindern...",
"schemaField": "accessControl"
},
{
"id": "zugangskontrolle",
"title": "Zugangskontrolle",
"content": "Massnahmen gegen unbefugte Systemnutzung...",
"schemaField": "systemAccessControl"
},
{
"id": "zugriffskontrolle",
"title": "Zugriffskontrolle",
"content": "Massnahmen zur Sicherstellung berechtigter Datenzugriffe...",
"schemaField": "dataAccessControl"
},
{
"id": "weitergabekontrolle",
"title": "Weitergabekontrolle / Uebertragungssicherheit",
"content": "Massnahmen bei Datenuebertragung und -transport...",
"schemaField": "transferControl"
},
{
"id": "eingabekontrolle",
"title": "Eingabekontrolle",
"content": "Nachvollziehbarkeit von Dateneingaben...",
"schemaField": "inputControl"
},
{
"id": "auftragskontrolle",
"title": "Auftragskontrolle",
"content": "Massnahmen zur weisungsgemaessen Auftragsverarbeitung...",
"schemaField": "orderControl"
},
{
"id": "verfuegbarkeitskontrolle",
"title": "Verfuegbarkeitskontrolle",
"content": "Schutz gegen Datenverlust...",
"schemaField": "availabilityControl"
},
{
"id": "trennungsgebot",
"title": "Trennungsgebot",
"content": "Getrennte Verarbeitung fuer verschiedene Zwecke...",
"schemaField": "separationControl"
}
]
}
Fuelle fehlende Informationen mit [PLATZHALTER: ...].
Halte die Tiefe exakt auf Level ${level}.`
}

View File

@@ -0,0 +1,109 @@
/**
* VVT Draft Prompt - Verarbeitungsverzeichnis (Art. 30 DSGVO)
*/
import type { DraftContext } from '../types'
export interface VVTDraftInput {
context: DraftContext
activityName?: string
activityPurpose?: string
instructions?: string
}
export function buildVVTDraftPrompt(input: VVTDraftInput): string {
const { context, activityName, activityPurpose, instructions } = input
const level = context.decisions.level
const depthItems = context.constraints.depthRequirements.detailItems
return `## Aufgabe: VVT-Eintrag entwerfen (Art. 30 DSGVO)
### Unternehmensprofil
- Name: ${context.companyProfile.name}
- Branche: ${context.companyProfile.industry}
- Mitarbeiter: ${context.companyProfile.employeeCount}
- Geschaeftsmodell: ${context.companyProfile.businessModel}
${context.companyProfile.dataProtectionOfficer ? `- DSB: ${context.companyProfile.dataProtectionOfficer.name} (${context.companyProfile.dataProtectionOfficer.email})` : '- DSB: Nicht benannt'}
### Compliance-Level: ${level}
Tiefe: ${context.constraints.depthRequirements.depth}
### Erforderliche Inhalte fuer Level ${level}:
${depthItems.map((item, i) => `${i + 1}. ${item}`).join('\n')}
### Constraints
${context.constraints.boundaries.map(b => `- ${b}`).join('\n')}
${context.constraints.riskFlags.length > 0 ? `### Risiko-Flags
${context.constraints.riskFlags.map(f => `- [${f.severity}] ${f.title}: ${f.recommendation}`).join('\n')}` : ''}
${activityName ? `### Gewuenschte Verarbeitungstaetigkeit: ${activityName}` : ''}
${activityPurpose ? `### Zweck: ${activityPurpose}` : ''}
${instructions ? `### Zusaetzliche Anweisungen: ${instructions}` : ''}
${context.existingDocumentData ? `### Bestehende VVT-Eintraege: ${JSON.stringify(context.existingDocumentData).slice(0, 500)}` : ''}
### Antwort-Format
Antworte als JSON:
{
"sections": [
{
"id": "bezeichnung",
"title": "Bezeichnung der Verarbeitungstaetigkeit",
"content": "...",
"schemaField": "name"
},
{
"id": "verantwortlicher",
"title": "Verantwortlicher",
"content": "...",
"schemaField": "controller"
},
{
"id": "zweck",
"title": "Zweck der Verarbeitung",
"content": "...",
"schemaField": "purpose"
},
{
"id": "rechtsgrundlage",
"title": "Rechtsgrundlage",
"content": "...",
"schemaField": "legalBasis"
},
{
"id": "betroffene",
"title": "Kategorien betroffener Personen",
"content": "...",
"schemaField": "dataSubjects"
},
{
"id": "datenkategorien",
"title": "Kategorien personenbezogener Daten",
"content": "...",
"schemaField": "dataCategories"
},
{
"id": "empfaenger",
"title": "Empfaenger",
"content": "...",
"schemaField": "recipients"
},
{
"id": "speicherdauer",
"title": "Speicherdauer / Loeschfristen",
"content": "...",
"schemaField": "retentionPeriod"
},
{
"id": "tom_referenz",
"title": "TOM-Referenz",
"content": "...",
"schemaField": "tomReference"
}
]
}
Fuelle fehlende Informationen mit [PLATZHALTER: Beschreibung was hier eingetragen werden muss].
Halte die Tiefe exakt auf Level ${level} (${context.constraints.depthRequirements.depth}).`
}

View File

@@ -0,0 +1,11 @@
/**
* Drafting Engine Prompts - Re-Exports
*/
export { buildVVTDraftPrompt, type VVTDraftInput } from './draft-vvt'
export { buildTOMDraftPrompt, type TOMDraftInput } from './draft-tom'
export { buildDSFADraftPrompt, type DSFADraftInput } from './draft-dsfa'
export { buildPrivacyPolicyDraftPrompt, type PrivacyPolicyDraftInput } from './draft-privacy-policy'
export { buildLoeschfristenDraftPrompt, type LoeschfristenDraftInput } from './draft-loeschfristen'
export { buildCrossCheckPrompt, type CrossCheckInput } from './validate-cross-check'
export { buildGapAnalysisPrompt, type GapAnalysisInput } from './ask-gap-analysis'

View File

@@ -0,0 +1,66 @@
/**
* Cross-Document Validation Prompt
*/
import type { ValidationContext } from '../types'
export interface CrossCheckInput {
context: ValidationContext
focusDocuments?: string[]
instructions?: string
}
export function buildCrossCheckPrompt(input: CrossCheckInput): string {
const { context, focusDocuments, instructions } = input
return `## Aufgabe: Cross-Dokument-Konsistenzpruefung
### Scope-Level: ${context.scopeLevel}
### Vorhandene Dokumente:
${context.documents.map(d => `- ${d.type}: ${d.contentSummary}`).join('\n')}
### Cross-Referenzen:
- VVT-Kategorien: ${context.crossReferences.vvtCategories.join(', ') || 'Keine'}
- DSFA-Risiken: ${context.crossReferences.dsfaRisks.join(', ') || 'Keine'}
- TOM-Controls: ${context.crossReferences.tomControls.join(', ') || 'Keine'}
- Loeschfristen-Kategorien: ${context.crossReferences.retentionCategories.join(', ') || 'Keine'}
### Tiefenpruefung pro Dokument:
${context.documents.map(d => {
const req = context.depthRequirements[d.type]
return req ? `- ${d.type}: Erforderlich=${req.required}, Tiefe=${req.depth}` : `- ${d.type}: Keine Requirements`
}).join('\n')}
${focusDocuments ? `### Fokus auf: ${focusDocuments.join(', ')}` : ''}
${instructions ? `### Zusaetzliche Anweisungen: ${instructions}` : ''}
### Pruefkriterien:
1. Jede VVT-Taetigkeit muss einen TOM-Verweis haben
2. Jede VVT-Kategorie muss eine Loeschfrist haben
3. Bei DSFA-pflichtigen Verarbeitungen muss eine DSFA existieren
4. TOM-Massnahmen muessen zum Risikoprofil passen
5. Loeschfristen duerfen gesetzliche Minima nicht unterschreiten
6. Dokument-Tiefe muss Level ${context.scopeLevel} entsprechen
### Antwort-Format
Antworte als JSON:
{
"passed": true/false,
"errors": [
{
"id": "ERR-001",
"severity": "error",
"category": "scope_violation|inconsistency|missing_content|depth_mismatch|cross_reference",
"title": "...",
"description": "...",
"documentType": "vvt|tom|dsfa|...",
"crossReferenceType": "...",
"legalReference": "Art. ... DSGVO",
"suggestion": "..."
}
],
"warnings": [...],
"suggestions": [...]
}`
}