diff --git a/admin-compliance/app/sdk/agent/_hooks/useAgentAnalysis.ts b/admin-compliance/app/sdk/agent/_hooks/useAgentAnalysis.ts index 2e01814..b8ea735 100644 --- a/admin-compliance/app/sdk/agent/_hooks/useAgentAnalysis.ts +++ b/admin-compliance/app/sdk/agent/_hooks/useAgentAnalysis.ts @@ -39,7 +39,7 @@ export function useAgentAnalysis() { const [result, setResult] = useState(null) const [history, setHistory] = useState([]) - async function analyze(url: string) { + async function analyze(url: string, mode: string = 'post_launch') { setLoading(true) setError(null) setResult(null) @@ -48,7 +48,7 @@ export function useAgentAnalysis() { const fetchRes = await fetch('/api/sdk/v1/agent/analyze', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ url }), + body: JSON.stringify({ url, mode }), }) if (!fetchRes.ok) { diff --git a/admin-compliance/app/sdk/agent/page.tsx b/admin-compliance/app/sdk/agent/page.tsx index 2b7f471..20cf5ab 100644 --- a/admin-compliance/app/sdk/agent/page.tsx +++ b/admin-compliance/app/sdk/agent/page.tsx @@ -6,14 +6,32 @@ import { AnalysisResult } from './_components/AnalysisResult' import { AnalysisHistory } from './_components/AnalysisHistory' import { FollowUpQuestions } from './_components/FollowUpQuestions' +type AnalysisMode = 'pre_launch' | 'post_launch' + +const MODES: { id: AnalysisMode; label: string; desc: string; icon: string }[] = [ + { + id: 'pre_launch', + label: 'Internes Dokument pruefen', + desc: 'Dokument oder Website VOR Veroeffentlichung pruefen', + icon: '📋', + }, + { + id: 'post_launch', + label: 'Live-Website pruefen', + desc: 'Bereits veroeffentlichte Website oder Dokument analysieren', + icon: '🌐', + }, +] + export default function AgentPage() { const [url, setUrl] = useState('') + const [mode, setMode] = useState('post_launch') const { analyze, answerFollowUp, loading, error, result, history } = useAgentAnalysis() const handleSubmit = (e: React.FormEvent) => { e.preventDefault() if (!url.trim()) return - analyze(url.trim()) + analyze(url.trim(), mode) } return ( @@ -22,18 +40,44 @@ export default function AgentPage() {

Compliance Agent

- Analysiere Webseiten auf DSGVO-Konformitaet. Der Agent holt das Dokument, - klassifiziert es, bewertet das Risiko und weist die Aufgabe der zustaendigen Rolle zu. + Analysiere Dokumente und Webseiten auf DSGVO-Konformitaet.

+ {/* Mode Selection */} +
+ {MODES.map(m => ( + + ))} +
+ {/* URL Input */}
setUrl(e.target.value)} - placeholder="https://example.com/datenschutz" + placeholder={mode === 'pre_launch' + ? 'https://staging.example.com/datenschutz' + : 'https://www.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" disabled={loading} required @@ -87,7 +131,7 @@ export default function AgentPage() { history={history} onSelect={r => { setUrl(r.url) - analyze(r.url) + analyze(r.url, mode) }} /> diff --git a/backend-compliance/compliance/api/agent_analyze_routes.py b/backend-compliance/compliance/api/agent_analyze_routes.py index e36474d..51399b0 100644 --- a/backend-compliance/compliance/api/agent_analyze_routes.py +++ b/backend-compliance/compliance/api/agent_analyze_routes.py @@ -41,6 +41,7 @@ SDK_HEADERS = { class AnalyzeRequest(BaseModel): url: str recipient: str = "dsb@breakpilot.local" + mode: str = "post_launch" # "pre_launch" or "post_launch" class FollowUpQuestion(BaseModel): @@ -97,12 +98,13 @@ async def analyze_url(req: AnalyzeRequest): esc_level = "E1" role = ESCALATION_ROLES["E1"] - summary = _build_summary(req.url, classification, assessment, role, findings_str, controls_str) + summary = _build_summary(req.url, classification, assessment, role, findings_str, controls_str, req.mode) # Step 7: Send notification + mode_label = "INTERNE PRUEFUNG" if req.mode == "pre_launch" else "LIVE-WEBSITE" email_result = send_email( recipient=req.recipient, - subject=f"Compliance-Finding: {classification} — {req.url[:60]}", + subject=f"[{mode_label}] Compliance-Finding: {classification} — {req.url[:60]}", body_html=f"
{summary}
", ) @@ -350,17 +352,27 @@ def _risk_to_escalation(risk_level: str) -> str: def _build_summary( url: str, classification: str, assessment: dict, role: str, findings_str: list[str], controls_str: list[str], + mode: str = "post_launch", ) -> str: - """Build a German manager summary.""" + """Build a German manager summary, adapted to pre/post-launch context.""" risk = assessment.get("risk_level", "unbekannt") score = assessment.get("risk_score", 0) recommendation = assessment.get("recommendation", "") dsfa = assessment.get("dsfa_recommended", False) + is_live = mode == "post_launch" findings_text = "\n".join(f"- {f}" for f in findings_str[:5]) if findings_str else "Keine" controls_text = "\n".join(f"- {c}" for c in controls_str[:5]) if controls_str else "Keine" + mode_header = ( + "PRUEFUNG LIVE-WEBSITE — Das Dokument ist bereits oeffentlich zugaenglich." + if is_live else + "INTERNE PRUEFUNG — Das Dokument ist noch nicht veroeffentlicht." + ) + parts = [ + mode_header, + "", f"Dokumenttyp: {classification}", f"Quelle: {url}", f"Risikobewertung: {risk} ({score}/100)", @@ -371,6 +383,19 @@ def _build_summary( "", f"Erforderliche Massnahmen:\n{controls_text}", ] + + if is_live and findings_str: + parts.extend([ + "", + "ACHTUNG: Diese Maengel sind bereits oeffentlich sichtbar. " + "Sofortige Nachbesserung empfohlen um Abmahnrisiken zu minimieren.", + ]) + elif not is_live and controls_str: + parts.extend([ + "", + "Empfehlung: Implementieren Sie die erforderlichen Kontrollen vor der Veroeffentlichung.", + ]) + if recommendation: - parts.extend(["", f"Empfehlung: {recommendation}"]) + parts.extend(["", f"Weitere Empfehlung: {recommendation}"]) return "\n".join(parts)