85d261a3f8
- 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>
97 lines
2.6 KiB
TypeScript
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>
|
|
)
|
|
}
|