feat(audit): P79 Pre-Scan-Wizard (8 Pflichtfelder) + P99 erweitert + P102 Replay-Fix
CI / guardrail-integrity (push) Has been skipped
CI / secret-scan (push) Has been skipped
CI / dep-audit (push) Has been skipped
CI / sbom-scan (push) Has been skipped
CI / validate-canonical-controls (push) Successful in 14s
CI / nodejs-lint (push) Has been skipped
CI / detect-changes (push) Successful in 11s
CI / branch-name (push) Has been skipped
CI / loc-budget (push) Failing after 17s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-build (push) Successful in 2m56s
CI / test-go (push) Has been skipped
CI / iace-gt-coverage (push) Has been skipped
CI / test-python-backend (push) Successful in 40s
CI / test-python-document-crawler (push) Has been skipped
CI / test-python-dsms-gateway (push) Has been skipped

P79: PreScanWizard.tsx mit 8 Pflichtfeldern (Branche, B2B/B2C,
Direkt-Vertrieb, Rechtsform, Konzern-Struktur, MA-Zahl, Besondere
Daten, Drittland). Scan-Button disabled bis alle 8 ausgefuellt. Werte
landen in scan_context und ueber Backend in compliance_check_snapshots.

P99: DOC_TYPES um dsa + legal_notice + lizenzhinweise + nutzungsbedingungen
erweitert. URL-hinzufuegen-Button war schon da.

P102 (Replay-Bug): check_replay.py liest jetzt e.get('text') statt
nur full_text — Snapshot-Schema verwendet 'text'. Library-Mismatch-
Block wird damit auch im Replay angezeigt.

Backend: ComplianceCheckRequest.scan_context optional; save_snapshot
persistiert ihn in compliance_check_snapshots.scan_context.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-21 15:59:01 +02:00
parent 94057b1536
commit 50fc0ecc59
4 changed files with 298 additions and 9 deletions
@@ -2,6 +2,7 @@
import React, { useState } from 'react'
import { ChecklistView } from './ChecklistView'
import { PreScanWizard, useScanContext, isContextComplete } from './PreScanWizard'
interface DocEntry {
id: string
@@ -11,13 +12,17 @@ interface DocEntry {
}
const DOC_TYPES = [
{ id: 'dse', label: 'DSI (Datenschutzinformation)' },
{ id: 'dse', label: 'Datenschutzerklärung / DSI' },
{ id: 'cookie', label: 'Cookie-Richtlinie' },
{ id: 'impressum', label: 'Impressum' },
{ id: 'agb', label: 'AGB' },
{ id: 'nutzungsbedingungen', label: 'Nutzungsbedingungen' },
{ id: 'widerruf', label: 'Widerrufsbelehrung' },
{ id: 'social_media', label: 'DSE Social Media (Art. 26)' },
{ id: 'dsfa', label: 'DSFA (Art. 35)' },
{ id: 'agb', label: 'AGB / Nutzungsbedingungen' },
{ id: 'impressum', label: 'Impressum' },
{ id: 'cookie', label: 'Cookie-Richtlinie' },
{ id: 'widerruf', label: 'Widerrufsbelehrung' },
{ id: 'dsa', label: 'DSA / Digital Services Act' },
{ id: 'legal_notice', label: 'Rechtliche Hinweise (IP, Forward-Looking)' },
{ id: 'lizenzhinweise', label: 'Lizenzhinweise Dritter (OSS)' },
{ id: 'other', label: 'Sonstiges' },
]
@@ -26,6 +31,7 @@ function newEntry(): DocEntry {
}
export function DocCheckTab() {
const [scanContext, setScanContext] = useScanContext()
const [entries, setEntries] = useState<DocEntry[]>(() => {
if (typeof window === 'undefined') return [newEntry()]
try { const s = localStorage.getItem('doc-check-entries'); return s ? JSON.parse(s) : [newEntry()] } catch { return [newEntry()] }
@@ -94,6 +100,7 @@ export function DocCheckTab() {
})),
check_cookie_banner: checkCookieBanner,
use_agent: useAgent,
scan_context: scanContext,
}),
})
if (!startRes.ok) throw new Error(`Pruefung konnte nicht gestartet werden: ${startRes.status}`)
@@ -133,8 +140,13 @@ export function DocCheckTab() {
}
}
const contextReady = isContextComplete(scanContext)
return (
<div className="space-y-4">
{/* P79 Pre-Scan-Wizard — 8 Pflichtfelder */}
<PreScanWizard value={scanContext} onChange={setScanContext} />
{/* URL Entries */}
<div className="space-y-2">
{entries.map((entry, i) => (
@@ -212,8 +224,9 @@ export function DocCheckTab() {
{/* Submit */}
<button
onClick={handleSubmit}
disabled={loading || entries.every(e => !e.url.trim())}
disabled={loading || entries.every(e => !e.url.trim()) || !contextReady}
className="w-full px-4 py-3 bg-purple-600 text-white rounded-lg font-medium hover:bg-purple-700 disabled:opacity-50 transition-colors text-sm flex items-center justify-center gap-2"
title={!contextReady ? 'Bitte zuerst die 8 Pflichtfelder ausfüllen' : undefined}
>
{loading ? (
<>
@@ -223,6 +236,8 @@ export function DocCheckTab() {
</svg>
Pruefe...
</>
) : !contextReady ? (
`Klassifizierung unvollständig (8 Pflichtfelder)`
) : (
`${entries.filter(e => e.url.trim()).length} Dokument${entries.filter(e => e.url.trim()).length !== 1 ? 'e' : ''} pruefen`
)}