'use client' import React, { useState, useEffect, useCallback } from 'react' // ============================================================================= // TYPES // ============================================================================= interface ISMSOverview { overall_status: string certification_readiness: number chapters: ChapterStatus[] scope_approved: boolean soa_approved: boolean last_management_review: string | null last_internal_audit: string | null open_major_findings: number open_minor_findings: number policies_count: number policies_approved: number objectives_count: number objectives_achieved: number } interface ChapterStatus { chapter: string title: string status: string completion_percentage: number open_findings: number key_documents: string[] last_reviewed: string | null } interface ISMSScope { id: string scope_statement: string included_locations: string[] included_processes: string[] included_services: string[] excluded_items: string[] exclusion_justification: string organizational_boundary: string physical_boundary: string technical_boundary: string status: string version: string created_by: string approved_by: string | null approved_at: string | null effective_date: string | null review_date: string | null created_at: string } interface ISMSContext { id: string internal_issues: Record[] | null external_issues: Record[] | null interested_parties: Record[] | null regulatory_requirements: string[] contractual_requirements: string[] swot_strengths: string[] swot_weaknesses: string[] swot_opportunities: string[] swot_threats: string[] status: string created_at: string } interface ISMSPolicy { id: string policy_id: string title: string policy_type: string description: string policy_text: string applies_to: string[] review_frequency_months: number related_controls: string[] status: string version: string authored_by: string reviewed_by: string | null approved_by: string | null approved_at: string | null effective_date: string | null next_review_date: string | null created_at: string } interface SecurityObjective { id: string objective_id: string title: string description: string category: string kpi_name: string kpi_target: number kpi_unit: string measurement_frequency: string owner: string target_date: string progress_percentage: number status: string achieved_date: string | null } interface SoAEntry { id: string annex_a_control: string annex_a_title: string annex_a_category: string is_applicable: boolean applicability_justification: string implementation_status: string implementation_notes: string breakpilot_control_ids: string[] coverage_level: string evidence_description: string version: string approved_at: string | null } interface InternalAudit { id: string audit_id: string title: string audit_type: string scope_description: string iso_chapters_covered: string[] planned_date: string actual_end_date: string | null lead_auditor: string audit_team: string[] status: string total_findings: number major_findings: number minor_findings: number ofi_count: number audit_conclusion: string | null overall_assessment: string | null } interface AuditFinding { id: string finding_id: string finding_type: string iso_chapter: string annex_a_control: string | null title: string description: string objective_evidence: string owner: string auditor: string status: string due_date: string | null closed_date: string | null internal_audit_id: string | null is_blocking: boolean } interface CAPA { id: string capa_id: string finding_id: string capa_type: string title: string description: string assigned_to: string status: string planned_completion: string actual_completion: string | null effectiveness_verified: boolean | null } interface ManagementReview { id: string review_id: string title: string review_date: string review_period_start: string review_period_end: string chairperson: string attendees: Record[] | null status: string approved_by: string | null approved_at: string | null next_review_date: string | null action_items: Record[] | null } interface ReadinessCheck { id: string check_date: string overall_status: string certification_possible: boolean readiness_score: number chapter_4_status: string chapter_5_status: string chapter_6_status: string chapter_7_status: string chapter_8_status: string chapter_9_status: string chapter_10_status: string potential_majors: PotentialFinding[] potential_minors: PotentialFinding[] priority_actions: string[] } interface PotentialFinding { check: string status: string recommendation: string iso_reference: string } type TabId = 'overview' | 'policies' | 'soa' | 'objectives' | 'audits' | 'reviews' const API = '/api/sdk/v1/isms' // ============================================================================= // HELPER COMPONENTS // ============================================================================= function StatusBadge({ status, size = 'sm' }: { status: string; size?: 'sm' | 'md' }) { const colors: Record = { ready: 'bg-green-100 text-green-700', compliant: 'bg-green-100 text-green-700', approved: 'bg-green-100 text-green-700', pass: 'bg-green-100 text-green-700', implemented: 'bg-green-100 text-green-700', completed: 'bg-green-100 text-green-700', verified: 'bg-green-100 text-green-700', achieved: 'bg-green-100 text-green-700', closed: 'bg-green-100 text-green-700', at_risk: 'bg-yellow-100 text-yellow-700', partial: 'bg-yellow-100 text-yellow-700', warning: 'bg-yellow-100 text-yellow-700', planned: 'bg-blue-100 text-blue-700', draft: 'bg-gray-100 text-gray-700', active: 'bg-blue-100 text-blue-700', in_progress: 'bg-blue-100 text-blue-700', not_ready: 'bg-red-100 text-red-700', non_compliant: 'bg-red-100 text-red-700', fail: 'bg-red-100 text-red-700', open: 'bg-red-100 text-red-700', corrective_action_pending: 'bg-orange-100 text-orange-700', verification_pending: 'bg-yellow-100 text-yellow-700', } const cls = colors[status] || 'bg-gray-100 text-gray-600' const labels: Record = { ready: 'Bereit', not_ready: 'Nicht bereit', at_risk: 'Risiko', compliant: 'Konform', non_compliant: 'Nicht konform', partial: 'Teilweise', approved: 'Genehmigt', draft: 'Entwurf', pass: 'Bestanden', fail: 'Fehlgeschlagen', warning: 'Warnung', implemented: 'Implementiert', planned: 'Geplant', active: 'Aktiv', achieved: 'Erreicht', completed: 'Abgeschlossen', open: 'Offen', closed: 'Geschlossen', verified: 'Verifiziert', corrective_action_pending: 'CAPA ausstehend', verification_pending: 'Verifizierung', in_progress: 'In Bearbeitung', not_applicable: 'N/A', } const pad = size === 'md' ? 'px-3 py-1 text-sm' : 'px-2 py-0.5 text-xs' return {labels[status] || status} } function StatCard({ label, value, sub, color = 'purple' }: { label: string; value: string | number; sub?: string; color?: string }) { const colors: Record = { purple: 'border-purple-200 bg-purple-50', green: 'border-green-200 bg-green-50', red: 'border-red-200 bg-red-50', yellow: 'border-yellow-200 bg-yellow-50', blue: 'border-blue-200 bg-blue-50', } return (
{value}
{label}
{sub &&
{sub}
}
) } function LoadingSpinner() { return (
) } function EmptyState({ text, action, onAction }: { text: string; action?: string; onAction?: () => void }) { return (

{text}

{action && onAction && ( )}
) } // ============================================================================= // TAB: OVERVIEW // ============================================================================= function OverviewTab() { const [overview, setOverview] = useState(null) const [readiness, setReadiness] = useState(null) const [scope, setScope] = useState(null) const [loading, setLoading] = useState(true) const [running, setRunning] = useState(false) const load = useCallback(async () => { setLoading(true) try { const [ovRes, rdRes, scRes] = await Promise.allSettled([ fetch(`${API}/overview`), fetch(`${API}/readiness-check/latest`), fetch(`${API}/scope`), ]) if (ovRes.status === 'fulfilled' && ovRes.value.ok) setOverview(await ovRes.value.json()) if (rdRes.status === 'fulfilled' && rdRes.value.ok) setReadiness(await rdRes.value.json()) if (scRes.status === 'fulfilled' && scRes.value.ok) setScope(await scRes.value.json()) } catch { /* ignore */ } setLoading(false) }, []) useEffect(() => { load() }, [load]) const runCheck = async () => { setRunning(true) try { const res = await fetch(`${API}/readiness-check`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ triggered_by: 'admin-ui' }), }) if (res.ok) { setReadiness(await res.json()) load() } } catch { /* ignore */ } setRunning(false) } if (loading) return return (
{/* Readiness Score */}

ISO 27001 Zertifizierungsbereitschaft

{overview && (
= 80 ? 'green' : overview.certification_readiness >= 50 ? 'yellow' : 'red'} /> 0 ? 'red' : 'green'} /> 0 ? 'yellow' : 'green'} />
)} {/* Chapter Overview */} {overview?.chapters && (

ISO 27001 Kapitel-Status

{overview.chapters.map(ch => (
Kap.{ch.chapter} {ch.title}
= 80 ? 'bg-green-500' : ch.completion_percentage >= 50 ? 'bg-yellow-500' : 'bg-red-500'}`} style={{ width: `${ch.completion_percentage}%` }} />
{Math.round(ch.completion_percentage)}%
))}
)}
{/* Readiness Findings */} {readiness && (

Readiness-Check Ergebnis

Score: {Math.round(readiness.readiness_score)}%
{readiness.potential_majors.length > 0 && (

Potenzielle Major-Findings ({readiness.potential_majors.length})

{readiness.potential_majors.map((f, i) => (
{f.check}
{f.recommendation}
ISO Referenz: {f.iso_reference}
))}
)} {readiness.potential_minors.length > 0 && (

Potenzielle Minor-Findings ({readiness.potential_minors.length})

{readiness.potential_minors.map((f, i) => (
{f.check}
{f.recommendation}
))}
)} {readiness.priority_actions.length > 0 && (

Prioritaere Massnahmen

    {readiness.priority_actions.map((a, i) =>
  1. {a}
  2. )}
)}
)} {/* Scope Summary */} {scope && (

ISMS Scope (Kap. 4.3)

{scope.scope_statement}

Standorte:
    {scope.included_locations?.map((l, i) =>
  • {l}
  • )}
Prozesse:
    {scope.included_processes?.map((p, i) =>
  • {p}
  • )}
{scope.approved_by && (
Genehmigt von {scope.approved_by} am {new Date(scope.approved_at!).toLocaleDateString('de-DE')}
)}
)}
) } // ============================================================================= // TAB: POLICIES // ============================================================================= function PoliciesTab() { const [policies, setPolicies] = useState([]) const [loading, setLoading] = useState(true) const [showCreate, setShowCreate] = useState(false) const [filter, setFilter] = useState('') const load = useCallback(async () => { setLoading(true) try { const url = filter ? `${API}/policies?policy_type=${filter}` : `${API}/policies` const res = await fetch(url) if (res.ok) { const data = await res.json() setPolicies(data.policies || []) } } catch { /* ignore */ } setLoading(false) }, [filter]) useEffect(() => { load() }, [load]) const createPolicy = async (form: Record) => { try { const res = await fetch(`${API}/policies`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(form), }) if (res.ok) { setShowCreate(false); load() } } catch { /* ignore */ } } const approvePolicy = async (policyId: string) => { try { await fetch(`${API}/policies/${policyId}/approve`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ reviewed_by: 'admin', approved_by: 'admin', effective_date: new Date().toISOString().split('T')[0], }), }) load() } catch { /* ignore */ } } if (loading) return const policyTypes = ['master', 'topic', 'operational', 'standard'] return (
{policyTypes.map(t => ( ))}
{policies.length === 0 ? ( setShowCreate(true)} /> ) : (
{policies.map(p => (
{p.policy_id} {p.title} v{p.version}

{p.description}

Typ: {p.policy_type} Review: alle {p.review_frequency_months} Monate {p.next_review_date && Naechste Review: {new Date(p.next_review_date).toLocaleDateString('de-DE')}}
{p.status === 'draft' && ( )}
))}
)} {/* Create Modal */} {showCreate && ( setShowCreate(false)} onSave={createPolicy} /> )}
) } function PolicyCreateModal({ onClose, onSave }: { onClose: () => void; onSave: (data: Record) => void }) { const [form, setForm] = useState({ policy_id: '', title: '', policy_type: 'topic', description: '', policy_text: '', applies_to: ['Alle Mitarbeiter'], review_frequency_months: 12, related_controls: [] as string[], authored_by: 'admin', }) return (

Neue ISMS Policy

setForm({ ...form, policy_id: e.target.value })} className="w-full border rounded-lg px-3 py-2 text-sm" placeholder="z.B. POL-SEC-001" />
setForm({ ...form, title: e.target.value })} className="w-full border rounded-lg px-3 py-2 text-sm" />