diff --git a/ai-act-kompass/src/engine/templates.test.ts b/ai-act-kompass/src/engine/templates.test.ts index c7248bf..7eb5c93 100644 --- a/ai-act-kompass/src/engine/templates.test.ts +++ b/ai-act-kompass/src/engine/templates.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest'; import { CONTENT_PACK, getContentPack } from '../content/pack'; import { classify } from './classify'; import { aiPolicy, trainingPlan, worksAgreement } from './templatesCompany'; +import { approvalRequest, auditChecklist, reportingPolicy } from './templatesInternal'; import { employeeInfo, friaTemplate, incidentReportForm, worksCouncilInfo } from './templatesSystem'; import type { AISystem, AssessmentAnswers, CompanyProfile } from './types'; @@ -102,3 +103,35 @@ describe('unternehmensweite Vorlagen', () => { expect(md).toContain('Betriebsrat: _______________'); }); }); + +describe('interne Prozess-Dokumente', () => { + it('Melderichtlinie enthält interne Fristen, Eskalationsstufen und HinSchG-Schutz', () => { + const md = reportingPolicy(CONTENT_PACK, TODAY, profile); + expect(md).toContain('interne Meldepflicht'); + expect(md).toContain('24 Stunden'); + expect(md).toContain('Eskalationsstufen'); + expect(md).toContain('HinSchG'); + expect(md).toContain('Art. 73'); + }); + + it('Freigabeantrag enthält Prüffelder und Entscheidungsblock', () => { + const md = approvalRequest(CONTENT_PACK, TODAY, profile); + expect(md).toContain('Freigabeantrag'); + expect(md).toContain('Risiko-Voreinschätzung'); + expect(md).toContain('☐ freigegeben'); + expect(md).toContain('KI-Inventar'); + }); + + it('Audit-Checkliste enthält nummerierte Prüfpunkte und Abzeichnung', () => { + const md = auditChecklist(CONTENT_PACK, TODAY, profile); + expect(md).toContain('| 1 |'); + expect(md).toContain('Schatten-IT'); + expect(md).toContain('Abzeichnung'); + }); + + it('interne Dokumente sind auch auf Englisch verfügbar', () => { + const md = reportingPolicy(getContentPack('en'), TODAY, profile, 'en'); + expect(md).toContain('escalation policy'); + expect(md).toContain('within 24 hours'); + }); +}); diff --git a/ai-act-kompass/src/engine/templatesInternal.ts b/ai-act-kompass/src/engine/templatesInternal.ts new file mode 100644 index 0000000..fe6aeec --- /dev/null +++ b/ai-act-kompass/src/engine/templatesInternal.ts @@ -0,0 +1,179 @@ +import type { Locale } from '../i18n/types'; +import { docStrings, formatDocDate } from './docStrings'; +import type { CompanyProfile, ContentPack } from './types'; + +/** Gemeinsamer Kopf für interne Prozess-Dokumente. */ +function head( + title: string, + pack: ContentPack, + today: string, + locale: Locale, + profile?: CompanyProfile, +): string { + const s = docStrings(locale); + const company = profile && profile.name.trim() !== '' ? profile.name : '_______________'; + return [ + `# ${title}`, + '', + `**${s.meta.company}:** ${company} · **${s.meta.createdAt}:** ${formatDocDate(today, locale)} · Content-Pack v${pack.version}`, + '', + s.disclaimer, + '', + ].join('\n'); +} + +/** + * Vordruck: Interne Melde- und Eskalationsrichtlinie für KI-Vorfälle + * (interne Meldepflicht — Prozess, der die Art.-73-Meldung vorbereitet). + */ +export function reportingPolicy( + pack: ContentPack, + today: string, + profile?: CompanyProfile, + locale: Locale = 'de', +): string { + const T = locale === 'en' + ? { + title: 'Internal reporting and escalation policy for AI incidents (draft)', + sections: [ + ['1. Purpose', 'This policy defines the internal reporting duty for malfunctions and incidents involving AI systems. It ensures that the company can meet its statutory reporting deadlines (Art. 73 EU AI Act: 15 days, death 10 days, widespread infringement/critical infrastructure 2 days).'], + ['2. What must be reported', 'Every employee reports without undue delay: (a) malfunctions or unexpected behaviour of an AI system, (b) suspected harm to health, safety or fundamental rights, (c) suspected discrimination by AI-supported decisions, (d) data protection incidents involving AI, (e) circumvention of human oversight.'], + ['3. Reporting channel', 'First report to: AI officer [name, contact] — verbally or via [channel]. If unavailable: [deputy]. Reports may also be made confidentially; whistleblower protection under the applicable whistleblowing rules remains unaffected.'], + ['4. Internal deadlines', 'Report by employee: immediately, at the latest within 24 hours of becoming aware. Initial assessment by AI officer: within 48 hours. Decision on external report (Art. 73) with management: without undue delay, so that the statutory deadlines are met.'], + ['5. Escalation levels', 'Level 1: AI officer (assessment, containment). Level 2: management + data protection officer + legal. Level 3: external report to the market surveillance authority and, where applicable, information of the provider (Art. 26(5)) and affected persons.'], + ['6. Documentation', 'Every report is documented using the serious incident report form and retained for at least [5] years. The AI officer maintains the incident register.'], + ['7. No sanctions for good-faith reports', 'Employees who report in good faith must not suffer any disadvantage.'], + ['8. Entry into force', 'This policy enters into force on [date].'], + ], + } + : { + title: 'Interne Melde- und Eskalationsrichtlinie für KI-Vorfälle (Entwurf)', + sections: [ + ['1. Zweck', 'Diese Richtlinie regelt die interne Meldepflicht für Störungen und Vorfälle im Zusammenhang mit KI-Systemen. Sie stellt sicher, dass das Unternehmen die gesetzlichen Meldefristen einhalten kann (Art. 73 EU-KI-VO: 15 Tage, Todesfall 10 Tage, weitverbreiteter Verstoß/kritische Infrastruktur 2 Tage).'], + ['2. Was zu melden ist', 'Jede/r Beschäftigte meldet unverzüglich: (a) Fehlfunktionen oder unerwartetes Verhalten eines KI-Systems, (b) Verdacht auf Schäden für Gesundheit, Sicherheit oder Grundrechte, (c) Verdacht auf Diskriminierung durch KI-gestützte Entscheidungen, (d) Datenschutzvorfälle mit KI-Bezug, (e) Umgehung der menschlichen Aufsicht.'], + ['3. Meldeweg', 'Erstmeldung an: KI-Beauftragte/r [Name, Kontakt] — mündlich oder über [Kanal]. Bei Nichterreichbarkeit: [Vertretung]. Meldungen sind auch vertraulich möglich; der Schutz nach dem Hinweisgeberschutzgesetz (HinSchG) bleibt unberührt.'], + ['4. Interne Fristen', 'Meldung durch Beschäftigte: sofort, spätestens 24 Stunden nach Kenntnis. Erstbewertung durch KI-Beauftragte/n: binnen 48 Stunden. Entscheidung über externe Meldung (Art. 73) mit der Geschäftsleitung: unverzüglich, sodass die gesetzlichen Fristen gewahrt bleiben.'], + ['5. Eskalationsstufen', 'Stufe 1: KI-Beauftragte/r (Bewertung, Eindämmung). Stufe 2: Geschäftsleitung + Datenschutzbeauftragte/r + Recht. Stufe 3: externe Meldung an die Marktüberwachungsbehörde sowie ggf. Information des Anbieters (Art. 26 Abs. 5) und Betroffener.'], + ['6. Dokumentation', 'Jede Meldung wird mit dem Formular „Vorfallmeldung (Art. 73)" dokumentiert und mindestens [5] Jahre aufbewahrt. Der/die KI-Beauftragte führt das Vorfallregister.'], + ['7. Keine Sanktionen bei gutgläubiger Meldung', 'Beschäftigten, die in gutem Glauben melden, dürfen keine Nachteile entstehen.'], + ['8. Inkrafttreten', 'Diese Richtlinie tritt am [Datum] in Kraft.'], + ], + }; + + const lines = [head(T.title, pack, today, locale, profile)]; + for (const [sec, body] of T.sections) { + lines.push(`## ${sec}`, '', body ?? '', ''); + } + return lines.join('\n'); +} + +/** Vordruck: Freigabeantrag für ein neues KI-System (interner Genehmigungsprozess). */ +export function approvalRequest( + pack: ContentPack, + today: string, + profile?: CompanyProfile, + locale: Locale = 'de', +): string { + const s = docStrings(locale); + const T = locale === 'en' + ? { + title: 'Approval request for a new AI system (internal form)', + intro: 'To be completed by the requesting department before any productive use of a new AI system or a substantial change to an existing one. Approval is granted by [AI officer / management].', + fields: [ + 'Requesting department / person / date', + 'Name and provider of the AI system (incl. version, deployment form: cloud/on-premises)', + 'Intended purpose and expected benefit', + 'Categories of data processed (personal data? special categories? trade secrets?)', + 'Affected persons (employees, applicants, customers)', + 'Preliminary risk view (Annex III area affected? transparency triggers?)', + 'Provider documents available (instructions for use, DPA, certifications)', + 'Planned human oversight and responsible person', + ], + decision: 'Decision', + decisionBody: '☐ approved ☐ approved with conditions: _______________ ☐ rejected\n\nConditions/notes: _______________\n\nDate, signature (AI officer): _______________ Date, signature (management, where required): _______________\n\nAfter approval: enter the system in the AI inventory and run the risk assessment in this tool.', + } + : { + title: 'Freigabeantrag für ein neues KI-System (internes Formular)', + intro: 'Von der anfordernden Fachabteilung auszufüllen, bevor ein neues KI-System produktiv genutzt oder ein bestehendes wesentlich geändert wird. Die Freigabe erteilt [KI-Beauftragte/r / Geschäftsleitung].', + fields: [ + 'Anfordernde Abteilung / Person / Datum', + 'Name und Anbieter des KI-Systems (inkl. Version, Bereitstellungsform: Cloud/On-Premises)', + 'Zweckbestimmung und erwarteter Nutzen', + 'Verarbeitete Datenarten (personenbezogen? besondere Kategorien? Geschäftsgeheimnisse?)', + 'Betroffene Personen (Beschäftigte, Bewerber, Kunden)', + 'Risiko-Voreinschätzung (Annex-III-Bereich betroffen? Transparenz-Auslöser?)', + 'Vorliegende Anbieterunterlagen (Betriebsanleitung, AVV, Zertifizierungen)', + 'Geplante menschliche Aufsicht und verantwortliche Person', + ], + decision: 'Entscheidung', + decisionBody: '☐ freigegeben ☐ freigegeben mit Auflagen: _______________ ☐ abgelehnt\n\nAuflagen/Hinweise: _______________\n\nDatum, Unterschrift (KI-Beauftragte/r): _______________ Datum, Unterschrift (Geschäftsleitung, soweit erforderlich): _______________\n\nNach Freigabe: System ins KI-Inventar aufnehmen und die Risikobewertung in diesem Tool durchführen.', + }; + + const lines = [head(T.title, pack, today, locale, profile)]; + lines.push(T.intro, ''); + T.fields.forEach((f, i) => { + lines.push(`## ${i + 1}. ${f}`, '', s.todo, ''); + }); + lines.push(`## ${T.decision}`, '', T.decisionBody); + return lines.join('\n'); +} + +/** Vordruck: Interne Audit-Checkliste KI-Compliance (periodische Selbstprüfung). */ +export function auditChecklist( + pack: ContentPack, + today: string, + profile?: CompanyProfile, + locale: Locale = 'de', +): string { + const T = locale === 'en' + ? { + title: 'Internal AI compliance audit checklist (periodic self-review)', + intro: 'Recommended interval: every [6] months and after material changes. Auditor: [AI officer]. Result to management.', + cols: '| # | Check | Result (OK / gap) | Action / owner / due date |', + sep: '|---|---|---|---|', + rows: [ + 'AI inventory complete? (shadow IT check: new tools in departments, browser extensions, API usage)', + 'Risk classifications still accurate? (purpose or scope changed? reassessment run?)', + 'All obligations in the task list processed or on schedule?', + 'AI literacy trainings (Art. 4) carried out and documented for all relevant staff?', + 'Transparency duties (Art. 50) implemented in all customer-facing systems?', + 'Logs of high-risk systems retained (min. 6 months) and accessible?', + 'Incident register maintained; internal reporting policy known to staff?', + 'Provider documents (instructions, DPA, certificates) current and on file?', + 'Works council agreements / employee information up to date?', + 'National module changes checked (new decrees, authority guidance)?', + 'Backup of this tool’s data exported and stored?', + ], + result: 'Overall result & sign-off', + resultBody: 'Gaps found: _______________\n\nDate, signature (auditor): _______________ Date, signature (management): _______________', + } + : { + title: 'Interne Audit-Checkliste KI-Compliance (periodische Selbstprüfung)', + intro: 'Empfohlener Turnus: alle [6] Monate sowie nach wesentlichen Änderungen. Prüfer: [KI-Beauftragte/r]. Ergebnis an die Geschäftsleitung.', + cols: '| # | Prüfpunkt | Ergebnis (OK / Lücke) | Maßnahme / Verantwortlich / Frist |', + sep: '|---|---|---|---|', + rows: [ + 'KI-Inventar vollständig? (Schatten-IT-Check: neue Tools in Fachabteilungen, Browser-Erweiterungen, API-Nutzung)', + 'Risikoklassifizierungen noch zutreffend? (Zweck oder Umfang geändert? Neubewertung durchgeführt?)', + 'Alle Pflichten der Aufgabenliste abgearbeitet oder im Plan?', + 'KI-Kompetenz-Schulungen (Art. 4) für alle relevanten Beschäftigten durchgeführt und dokumentiert?', + 'Transparenzpflichten (Art. 50) in allen kundenseitigen Systemen umgesetzt?', + 'Protokolle der Hochrisiko-Systeme aufbewahrt (mind. 6 Monate) und zugänglich?', + 'Vorfallregister geführt; interne Melderichtlinie den Beschäftigten bekannt?', + 'Anbieterunterlagen (Betriebsanleitung, AVV, Zertifikate) aktuell und abgelegt?', + 'Betriebsvereinbarungen / Mitarbeiterinformationen auf aktuellem Stand?', + 'Änderungen der Länder-Module geprüft (neue Dekrete, Behördenleitlinien)?', + 'Backup der Daten dieses Tools exportiert und abgelegt?', + ], + result: 'Gesamtergebnis & Abzeichnung', + resultBody: 'Festgestellte Lücken: _______________\n\nDatum, Unterschrift (Prüfer): _______________ Datum, Unterschrift (Geschäftsleitung): _______________', + }; + + const lines = [head(T.title, pack, today, locale, profile)]; + lines.push(T.intro, '', T.cols, T.sep); + T.rows.forEach((row, i) => { + lines.push(`| ${i + 1} | ${row} | | |`); + }); + lines.push('', `## ${T.result}`, '', T.resultBody); + return lines.join('\n'); +} diff --git a/ai-act-kompass/src/i18n/ui.ts b/ai-act-kompass/src/i18n/ui.ts index 0263a69..25b8422 100644 --- a/ai-act-kompass/src/i18n/ui.ts +++ b/ai-act-kompass/src/i18n/ui.ts @@ -165,6 +165,12 @@ const DE = { docEmployeeInfo: 'Mitarbeiterinformation KI-Einsatz', docFria: 'FRIA-Vorlage (Art. 27)', docIncident: 'Vorfallmeldung (Art. 73)', + tplReporting: 'Interne Melde- & Eskalationsrichtlinie', + tplReportingDesc: 'Interne Meldepflicht für KI-Vorfälle: Meldewege, 24h-/48h-Fristen, Eskalationsstufen, Vorfallregister — bereitet die Art.-73-Meldung vor.', + tplApproval: 'Freigabeantrag KI-System', + tplApprovalDesc: 'Internes Formular für den Genehmigungsprozess neuer KI-Tools — gegen Schatten-KI, mit Entscheidungsfeld.', + tplAudit: 'Interne Audit-Checkliste KI-Compliance', + tplAuditDesc: 'Periodische Selbstprüfung (Inventar, Schulungen, Logs, Vorfälle, Anbieterunterlagen) mit Abzeichnung.', }; export type UIStrings = typeof DE; @@ -332,6 +338,12 @@ const EN: UIStrings = { docEmployeeInfo: 'Employee information on AI use', docFria: 'FRIA template (Art. 27)', docIncident: 'Incident report (Art. 73)', + tplReporting: 'Internal reporting & escalation policy', + tplReportingDesc: 'Internal reporting duty for AI incidents: channels, 24h/48h deadlines, escalation levels, incident register — prepares the Art. 73 report.', + tplApproval: 'AI system approval request', + tplApprovalDesc: 'Internal form for approving new AI tools — against shadow AI, with decision section.', + tplAudit: 'Internal AI compliance audit checklist', + tplAuditDesc: 'Periodic self-review (inventory, trainings, logs, incidents, provider documents) with sign-off.', }; const DICTS: Readonly> = { de: DE, en: EN }; diff --git a/ai-act-kompass/src/ui/TemplatesView.tsx b/ai-act-kompass/src/ui/TemplatesView.tsx index 37487f7..9074877 100644 --- a/ai-act-kompass/src/ui/TemplatesView.tsx +++ b/ai-act-kompass/src/ui/TemplatesView.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; import { aiPolicy, trainingPlan, worksAgreement } from '../engine/templatesCompany'; +import { approvalRequest, auditChecklist, reportingPolicy } from '../engine/templatesInternal'; import type { AISystem, CompanyProfile } from '../engine/types'; import { useI18n } from '../i18n/context'; import { printDocument } from '../print/print'; @@ -10,7 +11,7 @@ interface TemplatesViewProps { readonly profile: CompanyProfile; } -type TplKind = 'policy' | 'training' | 'worksAgreement'; +type TplKind = 'policy' | 'reporting' | 'approval' | 'audit' | 'training' | 'worksAgreement'; /** Unternehmensweite Vorlagen: KI-Richtlinie, Schulungsplan, Betriebsvereinbarung. */ export function TemplatesView({ systems, profile }: TemplatesViewProps): JSX.Element { @@ -28,6 +29,24 @@ export function TemplatesView({ systems, profile }: TemplatesViewProps): JSX.Ele file: `ki-richtlinie-${today}.md`, render: () => aiPolicy(pack, today, profile, locale), }, + reporting: { + label: t.tplReporting, + desc: t.tplReportingDesc, + file: `melde-richtlinie-${today}.md`, + render: () => reportingPolicy(pack, today, profile, locale), + }, + approval: { + label: t.tplApproval, + desc: t.tplApprovalDesc, + file: `freigabeantrag-ki-${today}.md`, + render: () => approvalRequest(pack, today, profile, locale), + }, + audit: { + label: t.tplAudit, + desc: t.tplAuditDesc, + file: `audit-checkliste-ki-${today}.md`, + render: () => auditChecklist(pack, today, profile, locale), + }, training: { label: t.tplTraining, desc: t.tplTrainingDesc,