|
|
|
@@ -20,55 +20,58 @@ interface PathOption {
|
|
|
|
|
title: string
|
|
|
|
|
short: string
|
|
|
|
|
details: string[]
|
|
|
|
|
available?: boolean // false = rechtlich vorgesehen, aber noch nicht nutzbar
|
|
|
|
|
note?: string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const PATHS: PathOption[] = [
|
|
|
|
|
{
|
|
|
|
|
id: 'self_assessment',
|
|
|
|
|
modul: 'Modul A',
|
|
|
|
|
title: 'Self-Assessment',
|
|
|
|
|
short: 'Konformitaetsbewertung durch interne Pruefung',
|
|
|
|
|
title: 'Selbstbewertung (interne Kontrolle)',
|
|
|
|
|
short: 'Hersteller erklaert die Konformitaet selbst',
|
|
|
|
|
details: [
|
|
|
|
|
'Hersteller fuehrt Konformitaetsbewertung selbst durch',
|
|
|
|
|
'Hersteller fuehrt die Konformitaetsbewertung selbst durch',
|
|
|
|
|
'Geringster externer Aufwand, schnelle Umsetzung',
|
|
|
|
|
'Default fuer Standard-Produkte',
|
|
|
|
|
'Technische Dokumentation + DoC bleibt Pflicht',
|
|
|
|
|
'Nur fuer Standard- und (mit Norm) wichtige Klasse-I-Produkte',
|
|
|
|
|
'Technische Dokumentation + Konformitaetserklaerung bleiben Pflicht',
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'harmonized_standard',
|
|
|
|
|
modul: 'Modul B',
|
|
|
|
|
title: 'Harmonized Standard',
|
|
|
|
|
short: 'Konformitaetsvermutung durch harmonisierte Norm',
|
|
|
|
|
modul: 'Konformitaetsvermutung',
|
|
|
|
|
title: 'Harmonisierte Normen',
|
|
|
|
|
short: 'Vermutungswirkung durch eine harmonisierte EU-Norm',
|
|
|
|
|
available: false,
|
|
|
|
|
note: 'Fuer den CRA noch keine harmonisierte Norm veroeffentlicht — Entwuerfe erwartet ~Ende 2026, Listung im Amtsblatt voraussichtlich 2027.',
|
|
|
|
|
details: [
|
|
|
|
|
'Anwendung einer harmonisierten EU-Norm (z.B. DIN EN 40000-1-2 Entwurf)',
|
|
|
|
|
'Konformitaetsvermutung gemaess EU-Recht',
|
|
|
|
|
'Geringeres Audit-Risiko',
|
|
|
|
|
'Empfohlen bei verfuegbarer harmonisierter Norm',
|
|
|
|
|
'Kein eigenes Modul, sondern Grundlage der Konformitaetsvermutung',
|
|
|
|
|
'Wer danach baut, gilt als CRA-konform und darf (Standard/Klasse I) selbst bewerten',
|
|
|
|
|
'Bis dahin ggf. ueber gemeinsame Spezifikationen der Kommission (Art. 27)',
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'eucc',
|
|
|
|
|
modul: 'Modul H',
|
|
|
|
|
title: 'EUCC Zertifizierung',
|
|
|
|
|
short: 'European Cybersecurity Certification Scheme',
|
|
|
|
|
modul: 'EUCC',
|
|
|
|
|
title: 'EU-Cybersicherheitszertifikat',
|
|
|
|
|
short: 'Zertifizierung nach EUCC-Schema (Common-Criteria-basiert)',
|
|
|
|
|
details: [
|
|
|
|
|
'ENISA-EUCC-Zertifizierung (Common Criteria-basiert)',
|
|
|
|
|
'Hoechste Anerkennung in EU + Drittstaaten',
|
|
|
|
|
'Hoher Aufwand, ITSEF-Pruefung erforderlich',
|
|
|
|
|
'Pflicht bei einigen Important Class II-Produkten',
|
|
|
|
|
'EUCC-Zertifikat (in der Regel Stufe „substanziell")',
|
|
|
|
|
'Eigener Weg unter dem Cybersecurity Act, keine benannte Stelle noetig',
|
|
|
|
|
'Hohe Anerkennung in EU + Drittstaaten, ITSEF-Pruefung',
|
|
|
|
|
'Regulaerer Weg fuer wichtige Klasse II und kritische Produkte',
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'notified_body',
|
|
|
|
|
modul: 'Modul C',
|
|
|
|
|
title: 'Notified Body Assessment',
|
|
|
|
|
short: 'Drittprueforganisation pruefn die Konformitaet',
|
|
|
|
|
modul: 'Modul B+C',
|
|
|
|
|
title: 'Benannte Stelle (Baumusterpruefung)',
|
|
|
|
|
short: 'Dritte Stelle prueft (EU-Baumusterpruefung + Produktionskontrolle)',
|
|
|
|
|
details: [
|
|
|
|
|
'Externe Bewertung durch akkreditierte Stelle',
|
|
|
|
|
'PFLICHT fuer Critical-Produkte (Annex IV)',
|
|
|
|
|
'Hoechste Auditierbarkeit + Vertrauen',
|
|
|
|
|
'Laufzeit + Kosten am hoechsten',
|
|
|
|
|
'EU-Baumusterpruefung (Modul B) durch akkreditierte benannte Stelle',
|
|
|
|
|
'gefolgt von Produktionskontrolle (Modul C); alternativ volle QS (Modul H)',
|
|
|
|
|
'Pflichtweg fuer wichtige Klasse II und kritische Produkte (Annex IV)',
|
|
|
|
|
'Hoechste Auditierbarkeit, hoechste Laufzeit + Kosten',
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
@@ -76,14 +79,15 @@ const PATHS: PathOption[] = [
|
|
|
|
|
const ALLOWED: Record<string, PathId[]> = {
|
|
|
|
|
STANDARD: ['self_assessment', 'harmonized_standard', 'eucc', 'notified_body'],
|
|
|
|
|
IMPORTANT_I: ['self_assessment', 'harmonized_standard', 'eucc', 'notified_body'],
|
|
|
|
|
IMPORTANT_II: ['harmonized_standard', 'eucc', 'notified_body'],
|
|
|
|
|
CRITICAL: ['notified_body'],
|
|
|
|
|
// Klasse II darf nicht selbst bewerten; harmonisierte Norm allein genuegt nicht.
|
|
|
|
|
IMPORTANT_II: ['eucc', 'notified_body'],
|
|
|
|
|
CRITICAL: ['eucc', 'notified_body'],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const DEFAULT_FOR: Record<string, PathId> = {
|
|
|
|
|
STANDARD: 'self_assessment',
|
|
|
|
|
IMPORTANT_I: 'self_assessment',
|
|
|
|
|
IMPORTANT_II: 'harmonized_standard',
|
|
|
|
|
IMPORTANT_II: 'notified_body',
|
|
|
|
|
CRITICAL: 'notified_body',
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -185,31 +189,37 @@ export default function PathSelectPage({
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
|
|
|
|
{PATHS.map(path => {
|
|
|
|
|
const allowed = allowedPaths.includes(path.id)
|
|
|
|
|
const available = path.available !== false
|
|
|
|
|
const selectable = allowed && available
|
|
|
|
|
const isSelected = selected === path.id
|
|
|
|
|
return (
|
|
|
|
|
<button
|
|
|
|
|
key={path.id}
|
|
|
|
|
onClick={() => allowed && setSelected(path.id)}
|
|
|
|
|
disabled={!allowed}
|
|
|
|
|
onClick={() => selectable && setSelected(path.id)}
|
|
|
|
|
disabled={!selectable}
|
|
|
|
|
className={`text-left p-5 rounded-xl border-2 transition-all ${
|
|
|
|
|
isSelected ? 'border-red-500 bg-red-50' :
|
|
|
|
|
allowed ? 'border-gray-200 bg-white hover:border-red-300 hover:shadow-md' :
|
|
|
|
|
'border-gray-200 bg-gray-50 opacity-50 cursor-not-allowed'
|
|
|
|
|
selectable ? 'border-gray-200 bg-white hover:border-red-300 hover:shadow-md' :
|
|
|
|
|
'border-gray-200 bg-gray-50 opacity-60 cursor-not-allowed'
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
<div className="flex items-start justify-between mb-2">
|
|
|
|
|
<div className="flex items-start justify-between mb-2 gap-2">
|
|
|
|
|
<div>
|
|
|
|
|
<span className="text-xs font-semibold text-gray-500 uppercase tracking-wide">{path.modul}</span>
|
|
|
|
|
<h3 className="text-lg font-semibold text-gray-900">{path.title}</h3>
|
|
|
|
|
</div>
|
|
|
|
|
{isSelected && (
|
|
|
|
|
<span className="px-2 py-0.5 text-xs bg-red-600 text-white rounded">Gewaehlt</span>
|
|
|
|
|
)}
|
|
|
|
|
{!allowed && (
|
|
|
|
|
<span className="px-2 py-0.5 text-xs bg-gray-200 text-gray-600 rounded">Nicht zulaessig</span>
|
|
|
|
|
)}
|
|
|
|
|
{isSelected ? (
|
|
|
|
|
<span className="px-2 py-0.5 text-xs bg-red-600 text-white rounded whitespace-nowrap">Gewaehlt</span>
|
|
|
|
|
) : !available ? (
|
|
|
|
|
<span className="px-2 py-0.5 text-xs bg-amber-100 text-amber-700 rounded whitespace-nowrap">Noch nicht verfügbar</span>
|
|
|
|
|
) : !allowed ? (
|
|
|
|
|
<span className="px-2 py-0.5 text-xs bg-gray-200 text-gray-600 rounded whitespace-nowrap">Nicht zulaessig</span>
|
|
|
|
|
) : null}
|
|
|
|
|
</div>
|
|
|
|
|
<p className="text-sm text-gray-600 mb-3">{path.short}</p>
|
|
|
|
|
<p className="text-sm text-gray-600 mb-2">{path.short}</p>
|
|
|
|
|
{path.note && (
|
|
|
|
|
<p className="text-xs text-amber-700 bg-amber-50 border border-amber-200 rounded px-2 py-1.5 mb-2">{path.note}</p>
|
|
|
|
|
)}
|
|
|
|
|
<ul className="text-xs text-gray-600 space-y-1">
|
|
|
|
|
{path.details.map((d, i) => (
|
|
|
|
|
<li key={i} className="flex items-start gap-1.5">
|
|
|
|
|