feat: Multi-URL Document Check with full checklist visibility

New "Dokumenten-Pruefung" tab in Compliance Agent:
- User adds multiple URLs with document type (DSI, AGB, Impressum, Cookie, Widerruf)
- Each document loaded via Playwright, accordions expanded, text extracted
- Checked against type-specific legal checklist
- Optional: Cookie banner check via checkbox

Checklisten-UX (solves "100% looks like nothing was checked"):
- All checks shown per document: green checkmark + matched text excerpt
- Red X for missing fields with legal reference
- Builds user trust: "9 Punkte geprueft, alle bestanden"
- Expandable per document with completeness bar

New checklists:
- Impressum: §5 TMG (6 fields: name, address, contact, register, VAT, representative)
- Cookie-Richtlinie: §25 TDDDG (5 fields: types, purposes, retention, third-party, opt-out)

Backend:
- POST /agent/doc-check — async with polling (same pattern as /scan)
- DocCheckResult includes checks[] with passed/failed + matched_text
- dsi_document_checker returns all_checks in SCORE finding
- Email report shows per-document checklist

Files: agent_doc_check_routes.py (280 LOC), DocCheckTab.tsx (248 LOC),
ChecklistView.tsx (130 LOC), dsi_document_checker.py (+70 LOC)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-05-06 10:08:40 +02:00
parent 254dbab566
commit 4c68caac4e
7 changed files with 770 additions and 8 deletions
+9 -4
View File
@@ -6,9 +6,10 @@ import { AnalysisResult } from './_components/AnalysisResult'
import { AnalysisHistory } from './_components/AnalysisHistory'
import { FollowUpQuestions } from './_components/FollowUpQuestions'
import { ScanResult } from './_components/ScanResult'
import { DocCheckTab } from './_components/DocCheckTab'
type AnalysisMode = 'pre_launch' | 'post_launch'
type AnalysisTab = 'quick' | 'scan'
type AnalysisTab = 'quick' | 'scan' | 'doc-check'
const MODES: { id: AnalysisMode; label: string; desc: string; icon: string }[] = [
{ id: 'pre_launch', label: 'Internes Dokument', desc: 'Vor Veroeffentlichung pruefen', icon: '📋' },
@@ -18,6 +19,7 @@ const MODES: { id: AnalysisMode; label: string; desc: string; icon: string }[] =
const TABS: { id: AnalysisTab; label: string; desc: string }[] = [
{ id: 'quick', label: 'Schnellanalyse', desc: 'Einzelne Seite klassifizieren + bewerten' },
{ id: 'scan', label: 'Website-Scan', desc: 'Mehrere Seiten scannen + Dienstleister abgleichen' },
{ id: 'doc-check', label: 'Dokumenten-Pruefung', desc: 'Einzelne Dokumente gezielt pruefen' },
]
export default function AgentPage() {
@@ -219,8 +221,11 @@ export default function AgentPage() {
))}
</div>
{/* URL Input */}
<form onSubmit={handleSubmit} className="flex gap-3">
{/* Doc Check Tab — own component */}
{tab === 'doc-check' && <DocCheckTab />}
{/* URL Input (quick + scan only) */}
{tab !== 'doc-check' && <form onSubmit={handleSubmit} className="flex gap-3">
<input type="url" value={url} onChange={e => setUrl(e.target.value)}
placeholder={tab === 'scan' ? 'https://www.example.com/' : 'https://example.com/datenschutz'}
className="flex-1 px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent text-sm"
@@ -234,7 +239,7 @@ export default function AgentPage() {
</svg>{tab === 'scan' ? 'Scanne...' : 'Analysiere...'}</>
) : tab === 'scan' ? 'Website scannen' : 'Analysieren'}
</button>
</form>
</form>}
{/* Scan Progress */}
{scanProgress && tab === 'scan' && (