Files
breakpilot-compliance/admin-compliance/app/sdk/gap-analysis/page.tsx
T
Benjamin Admin 85d261a3f8 feat(frontend): Gap Analysis UI — Product Wizard + Dashboard
- ProductWizard: Product type, technologies, data processing, certifications
- GapDashboard: Summary cards, regulation overview, prioritized gap table
- Expandable rows with recommendations
- Filter by severity and status
- Route: /sdk/gap-analysis

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-10 23:19:21 +02:00

97 lines
2.6 KiB
TypeScript

'use client'
import React, { useState } from 'react'
import { ProductWizard } from './_components/ProductWizard'
import { GapDashboard } from './_components/GapDashboard'
interface GapReport {
profile_id: string
profile_name: string
regulations: Array<{
id: string
name: string
applicable: boolean
confidence: number
reasoning: string
risk_level: string
deadline?: string
requirements?: string[]
}>
summary: {
total_applicable_regulations: number
total_gaps: number
gaps_by_status: Record<string, number>
gaps_by_severity: Record<string, number>
gaps_by_regulation: Record<string, number>
overall_compliance_percent: number
estimated_effort_weeks: number
}
gaps: Array<{
mc_id: string
mc_name: string
regulation: string
status: string
title: string
severity: string
priority: { score: number; rank: number }
recommendation: string
control_count: number
}>
}
export default function GapAnalysisPage() {
const [report, setReport] = useState<GapReport | null>(null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
const handleAnalyze = async (profile: Record<string, unknown>) => {
setLoading(true)
setError('')
try {
const res = await fetch('/api/sdk/v1/gap/analyze', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(profile),
})
if (!res.ok) throw new Error(await res.text())
const data = await res.json()
setReport(data)
} catch (e) {
setError(e instanceof Error ? e.message : 'Analyse fehlgeschlagen')
} finally {
setLoading(false)
}
}
return (
<div className="min-h-screen bg-gray-50 py-8">
<div className="max-w-6xl mx-auto px-4">
<div className="mb-8">
<h1 className="text-3xl font-bold text-gray-900">
Regulatory Gap-Analyse
</h1>
<p className="text-gray-600 mt-2">
Beschreiben Sie Ihr Produkt und erhalten Sie eine priorisierte
Liste der Compliance-Anforderungen.
</p>
</div>
{error && (
<div className="mb-6 bg-red-50 border border-red-200 rounded-lg p-4">
<p className="text-red-700">{error}</p>
</div>
)}
{!report ? (
<ProductWizard onAnalyze={handleAnalyze} loading={loading} />
) : (
<GapDashboard
report={report}
onBack={() => setReport(null)}
/>
)}
</div>
</div>
)
}