'use client' import React, { useEffect, useState, useCallback, use } from 'react' import { useRouter } from 'next/navigation' import { ClassificationBadge } from '../../_components/ClassificationBadge' interface CRAProject { id: string name: string cra_classification: string | null conformity_path: string | null status: string } type PathId = 'self_assessment' | 'harmonized_standard' | 'eucc' | 'notified_body' interface PathOption { id: PathId modul: string title: string short: string details: string[] available?: boolean // false = rechtlich vorgesehen, aber noch nicht nutzbar note?: string bpRole: string // was BreakPilot bei diesem Weg leistet (immer sichtbar) info?: string[] // aufklappbarer Erklaer-Text } const PATHS: PathOption[] = [ { id: 'self_assessment', modul: 'Modul A', title: 'Selbstbewertung (interne Kontrolle)', short: 'Hersteller erklaert die Konformitaet selbst', bpRole: 'Komplett mit BreakPilot durchführbar — keine externe Stelle nötig.', details: [ 'Hersteller fuehrt die Konformitaetsbewertung selbst durch', 'Geringster externer Aufwand, schnelle Umsetzung', 'Nur fuer Standard- und (mit Norm) wichtige Klasse-I-Produkte', 'Technische Dokumentation + Konformitaetserklaerung bleiben Pflicht', ], info: [ 'Bei Modul A erklärst du die CRA-Konformität selbst, ohne externe Prüfstelle.', 'BreakPilot erzeugt dafür Risikobeurteilung, technische Dokumentation und die Konformitätserklärung direkt im Tool — du gehst end-to-end mit uns durch.', ], }, { id: 'harmonized_standard', 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.', bpRole: 'Sobald die Normen gelistet sind, prüfen wir die Vermutungswirkung automatisch mit.', details: [ '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: 'EUCC', title: 'EU-Cybersicherheitszertifikat', short: 'Zertifizierung nach EUCC-Schema (Common-Criteria-basiert)', bpRole: 'Wir machen dich audit-fähig — die formale Prüfung macht ein akkreditiertes Labor (ITSEF), nicht BreakPilot.', details: [ 'EUCC-Zertifikat (in der Regel Stufe „substanziell")', 'Eigener Weg unter dem Cybersecurity Act', 'Hohe Anerkennung in EU + Drittstaaten', 'Regulaerer Weg fuer wichtige Klasse II und kritische Produkte', ], info: [ 'EUCC ist das EU-Cybersicherheits-Zertifizierungsschema (VO 2024/482) unter dem Cybersecurity Act, methodisch auf Common Criteria (ISO/IEC 15408) aufgebaut. Zertifiziert wird ein konkretes Produkt/eine Komponente — nicht die ganze Anlage.', 'Stufen: „substanziell" oder „hoch", Gültigkeit i. d. R. bis 5 Jahre. Die formale Prüfung führt ein akkreditiertes Labor (ITSEF) durch; das Zertifikat stellt eine Zertifizierungsstelle aus (Stufe „hoch": mit dem BSI).', 'Mit BreakPilot: Prüfobjekt abgrenzen, Nachweise (sichere Entwicklung, Konfiguration, Schwachstellen-Management, Anwender-Doku) strukturieren und Lücken VOR dem Labor schließen. Du gehst vorbereitet ins ITSEF-Audit — das spart Zeit und teure Nachprüf-Schleifen.', 'Oft sinnvoller: eine bereits EUCC-zertifizierte Komponente zukaufen und die Vermutungswirkung erben.', ], }, { id: 'notified_body', modul: 'Modul B+C', title: 'Benannte Stelle (Baumusterpruefung)', short: 'Dritte Stelle prueft (EU-Baumusterpruefung + Produktionskontrolle)', bpRole: 'Wir bereiten Doku + Nachweise auf — geprüft wird von der benannten Stelle.', details: [ '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', ], info: [ 'Eine akkreditierte benannte Stelle prüft das Baumuster (Modul B) und die Produktionskontrolle (Modul C) — alternativ ein vollständiges Qualitätssicherungssystem (Modul H).', 'Mit BreakPilot: wir erstellen die technische Dokumentation und das Nachweis-Paket und machen einen Gap-Check, damit das Audit glatt läuft. Die Prüfung selbst macht die benannte Stelle.', ], }, ] const ALLOWED: Record = { STANDARD: ['self_assessment', 'harmonized_standard', 'eucc', 'notified_body'], IMPORTANT_I: ['self_assessment', 'harmonized_standard', 'eucc', '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 = { STANDARD: 'self_assessment', IMPORTANT_I: 'self_assessment', IMPORTANT_II: 'notified_body', CRITICAL: 'notified_body', } export default function PathSelectPage({ params, }: { params: Promise<{ projectId: string }> }) { const { projectId } = use(params) const router = useRouter() const [project, setProject] = useState(null) const [selected, setSelected] = useState(null) const [infoOpen, setInfoOpen] = useState>({}) const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [error, setError] = useState('') const tenant = '9282a473-5c95-4b3a-bf78-0ecc0ec71d3e' const load = useCallback(async () => { try { const res = await fetch(`/api/sdk/v1/cra/projects/${projectId}`, { headers: { 'X-Tenant-ID': tenant }, }) if (!res.ok) throw new Error(await res.text()) const p: CRAProject = await res.json() setProject(p) if (p.conformity_path) { setSelected(p.conformity_path as PathId) } else if (p.cra_classification && DEFAULT_FOR[p.cra_classification]) { setSelected(DEFAULT_FOR[p.cra_classification]) } } catch (e) { setError(e instanceof Error ? e.message : 'Fehler beim Laden') } finally { setLoading(false) } }, [projectId]) useEffect(() => { load() }, [load]) const submit = async () => { if (!selected) return setSaving(true) setError('') try { const res = await fetch(`/api/sdk/v1/cra/projects/${projectId}/path-select`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Tenant-ID': tenant }, body: JSON.stringify({ conformity_path: selected }), }) if (!res.ok) throw new Error(await res.text()) router.push(`/sdk/cra/${projectId}`) } catch (e) { setError(e instanceof Error ? e.message : 'Speichern fehlgeschlagen') } finally { setSaving(false) } } if (loading) return

Laedt...

if (!project) return null if (!project.cra_classification) { return (

Bitte erst den Scope-Check ausfuehren. → Zum Scope-Check

) } const allowedPaths = ALLOWED[project.cra_classification] || [] return (
← Zurueck zum Projekt

Konformitaetspfad waehlen

Schritt 3 von 3 — basierend auf der Klassifikation siehst du die zulaessigen Pfade.

Klassifikation:
{error && (
{error}
)}
{PATHS.map(path => { const allowed = allowedPaths.includes(path.id) const available = path.available !== false const selectable = allowed && available const isSelected = selected === path.id return (
{path.modul}

{path.title}

{isSelected ? ( Gewaehlt ) : !available ? ( Noch nicht verfügbar ) : !allowed ? ( Nicht zulaessig ) : null}

{path.short}

{path.note && (

{path.note}

)}

Mit BreakPilot: {path.bpRole}

    {path.details.map((d, i) => (
  • {d}
  • ))}
{path.info && ( <> {infoOpen[path.id] && (
{path.info.map((p, i) => (

{p}

))}
)} )}
) })}
{selected ? ( <>Ausgewaehlt: {PATHS.find(p => p.id === selected)?.title} ) : ( 'Keine Auswahl getroffen' )}
) }