'use client' import { useState } from 'react' import { motion, AnimatePresence } from 'framer-motion' import { Language } from '@/lib/types' import { t } from '@/lib/i18n' import GradientText from '../ui/GradientText' import FadeInView from '../ui/FadeInView' import { Shield, Brain, ScanLine, Zap, Cpu, Globe, Cloud, X, Users, Lock, Server, Network, ChevronRight, Layers, } from 'lucide-react' interface ArchitectureSlideProps { lang: Language } type NodeId = 'breakpilot' | 'certifai' | 'compliance-scanner' | 'litellm' | 'ollama' | 'claude' | 'openai' interface NodeDef { id: NodeId icon: React.ElementType title: string subtitle: string color: string twColor: string twBorder: string twBg: string twDot: string cx: number cy: number tier: 'product' | 'proxy' | 'inference' tech: string[] services: { name: string; desc: string }[] badge?: string } const CONNECTIONS: [NodeId, NodeId][] = [ ['breakpilot', 'litellm'], ['certifai', 'litellm'], ['compliance-scanner', 'litellm'], ['litellm', 'ollama'], ['litellm', 'claude'], ['litellm', 'openai'], ] // Quadratic bezier paths in 0-100 viewBox space const ROUTES: Record = { 'breakpilot-litellm': 'M 15 22 Q 26 43 50 50', 'certifai-litellm': 'M 50 18 Q 50 34 50 50', 'compliance-scanner-litellm': 'M 85 22 Q 74 43 50 50', 'litellm-ollama': 'M 50 50 Q 39 64 15 80', 'litellm-claude': 'M 50 50 Q 50 65 50 80', 'litellm-openai': 'M 50 50 Q 61 64 85 80', } function getNodes(de: boolean): NodeDef[] { return [ { id: 'breakpilot', icon: Shield, title: 'BreakPilot', subtitle: de ? 'Compliance & Bildung' : 'Compliance & Education', color: '#818cf8', twColor: 'text-indigo-400', twBorder: 'border-indigo-500/50', twBg: 'bg-indigo-500/10', twDot: 'bg-indigo-400', cx: 15, cy: 22, tier: 'product', badge: de ? 'Kernprodukt' : 'Core Product', tech: ['Next.js 15', 'FastAPI', 'Go/Gin', 'PostgreSQL', 'Qdrant', 'Valkey'], services: [ { name: de ? 'DSGVO / AI Act / NIS2' : 'GDPR / AI Act / NIS2', desc: de ? '70k+ auditierbare Controls' : '70k+ auditable controls' }, { name: 'RAG Pipeline', desc: de ? '75+ Rechtsquellen, semantische Suche' : '75+ legal sources, semantic search' }, { name: de ? 'Lehrer Plattform' : 'Lehrer Platform', desc: de ? 'KI-Unterrichtsassistent' : 'AI teaching assistant' }, { name: 'Control Pipeline', desc: de ? 'Gesetzestextanalyse via Claude' : 'Legal text analysis via Claude' }, ], }, { id: 'certifai', icon: Brain, title: 'CERTifAI', subtitle: de ? 'GenAI Infrastruktur' : 'GenAI Infrastructure', color: '#c084fc', twColor: 'text-purple-400', twBorder: 'border-purple-500/50', twBg: 'bg-purple-500/10', twDot: 'bg-purple-400', cx: 50, cy: 18, tier: 'product', badge: de ? 'DSGVO-konform' : 'GDPR-Compliant', tech: ['Rust', 'Dioxus', 'MongoDB', 'Keycloak', 'SearXNG'], services: [ { name: 'LiteLLM Dashboard', desc: de ? 'Modellverwaltung & Kosten' : 'Model mgmt & spend tracking' }, { name: 'LibreChat + SSO', desc: de ? 'Mandanten-Chat' : 'Tenant chat with Keycloak' }, { name: 'LangGraph Agents', desc: de ? 'Agent-Orchestrierung' : 'Agent orchestration' }, { name: 'MCP Hub', desc: de ? 'Tool-Integration für KI' : 'Tool integration for AI clients' }, ], }, { id: 'compliance-scanner', icon: ScanLine, title: 'Compliance Scanner', subtitle: de ? 'Autonome Sicherheit' : 'Autonomous Security', color: '#34d399', twColor: 'text-emerald-400', twBorder: 'border-emerald-500/50', twBg: 'bg-emerald-500/10', twDot: 'bg-emerald-400', cx: 85, cy: 22, tier: 'product', badge: 'Rust + AI', tech: ['Rust', 'Axum', 'MongoDB', 'Semgrep', 'Gitleaks', 'Syft'], services: [ { name: 'SAST / SBOM / CVE', desc: de ? 'Vollautomatische Pipeline' : 'Fully automated pipeline' }, { name: de ? 'KI-Triage' : 'AI Triage', desc: de ? 'LLM filtert False Positives' : 'LLM filters false positives' }, { name: de ? 'KI-Pentest' : 'AI Pentest', desc: de ? 'Autonome Angriffsketten' : 'Autonomous attack chains' }, { name: 'MCP Server', desc: de ? 'Live-Findings für AI-Tools' : 'Live findings for AI tools' }, ], }, { id: 'litellm', icon: Zap, title: 'LiteLLM Proxy', subtitle: de ? 'Zentrale KI-Infrastruktur' : 'Central AI Proxy', color: '#fbbf24', twColor: 'text-amber-400', twBorder: 'border-amber-500/60', twBg: 'bg-amber-500/10', twDot: 'bg-amber-400', cx: 50, cy: 50, tier: 'proxy', badge: 'Hub', tech: ['OpenAI-compatible API', 'Bearer Auth', 'Rate Limiting', 'Spend Tracking'], services: [ { name: de ? 'Multi-Provider' : 'Multi-Provider', desc: 'Ollama · Claude · OpenAI · HuggingFace' }, { name: de ? 'Namespace-Isolierung' : 'Namespace Isolation', desc: de ? 'Mandantentrennung per API-Key' : 'Tenant isolation per API key' }, { name: de ? 'Kosten-Tracking' : 'Cost Tracking', desc: de ? 'Token-Verbrauch & USD-Kosten' : 'Token usage & USD costs' }, { name: de ? 'Failover-Routing' : 'Failover Routing', desc: de ? 'Automatisches Fallback' : 'Automatic fallback routing' }, ], }, { id: 'ollama', icon: Cpu, title: 'Ollama', subtitle: de ? 'Lokale Inferenz' : 'Local Inference', color: '#60a5fa', twColor: 'text-blue-400', twBorder: 'border-blue-500/50', twBg: 'bg-blue-500/10', twDot: 'bg-blue-400', cx: 15, cy: 80, tier: 'inference', badge: de ? 'On-Premise' : 'On-Premise', tech: ['Qwen3-Coder-30B', 'Qwen3-32b', 'bge-m3', 'GPU-optimized'], services: [ { name: de ? 'Vollständig lokal' : 'Fully local', desc: de ? 'Daten verlassen nie den Server' : 'Data never leaves the server' }, { name: de ? 'Air-Gap fähig' : 'Air-Gap Capable', desc: de ? 'Kein Internet erforderlich' : 'No internet required' }, ], }, { id: 'claude', icon: Globe, title: 'Anthropic Claude', subtitle: de ? 'Externe Inferenz' : 'External Inference', color: '#fb7185', twColor: 'text-rose-400', twBorder: 'border-rose-500/50', twBg: 'bg-rose-500/10', twDot: 'bg-rose-400', cx: 50, cy: 80, tier: 'inference', badge: de ? 'Optional' : 'Optional', tech: ['claude-sonnet-4-6', 'claude-haiku-4-5', 'Direct API'], services: [ { name: 'Control Pipeline', desc: de ? 'Gesetzestextanalyse & Control-Gen.' : 'Legal text analysis & control gen.' }, { name: 'Pitch Deck Chatbot', desc: de ? 'Investor-FAQ' : 'Investor FAQ' }, ], }, { id: 'openai', icon: Cloud, title: de ? 'OpenAI / Weitere' : 'OpenAI / Others', subtitle: de ? 'Cloud-Modelle' : 'Cloud Models', color: '#2dd4bf', twColor: 'text-teal-400', twBorder: 'border-teal-500/50', twBg: 'bg-teal-500/10', twDot: 'bg-teal-400', cx: 85, cy: 80, tier: 'inference', badge: de ? 'Optional' : 'Optional', tech: ['gpt-oss-120b', 'HuggingFace', 'text-embedding-3-small'], services: [ { name: de ? 'Erweiterbar' : 'Extensible', desc: de ? 'Jeder OpenAI-kompatibler Anbieter' : 'Any OpenAI-compatible provider' }, ], }, ] } function SeaRoute({ d, color, active }: { d: string; color: string; active: boolean }) { return ( {active && ( )} ) } function MapMarker({ node, active, onClick }: { node: NodeDef; active: boolean; onClick: () => void }) { const Icon = node.icon const isHub = node.id === 'litellm' const iconSize = isHub ? 'w-[52px] h-[52px]' : 'w-[40px] h-[40px]' return (
{/* Ripple pulse when active */} {active && ( )} {/* Icon circle */}
{/* Spinning dashed ring on active hub */} {isHub && active && ( )}
{/* Label */}

{node.title}

{(active || isHub) && (

{node.subtitle}

)} {node.badge && ( {node.badge} )}
) } export default function ArchitectureSlide({ lang }: ArchitectureSlideProps) { const i = t(lang) const de = lang === 'de' const nodes = getNodes(de) const [activeId, setActiveId] = useState(null) const active = nodes.find(n => n.id === activeId) ?? null function toggle(id: NodeId) { setActiveId(prev => (prev === id ? null : id)) } const tenants = de ? ['Mandant A', 'Mandant B', 'Mandant C', 'Mandant N…'] : ['Namespace A', 'Namespace B', 'Namespace C', 'Namespace N…'] return (
{/* Header */}

{de ? 'Anhang' : 'Appendix'}

{i.annex.architecture.title}

{de ? 'Klicke auf eine Komponente für Details' : 'Click any component to explore'}

{/* Customer namespace strip */}
{de ? 'Kundenmandanten' : 'Customer Namespaces'} {tenants.map(tn => ( {tn} ))}
{/* ── THE MAP ──────────────────────────────────────────────────── */}
{/* Ocean background (clipped to rounded rect) */}
{/* Fine dot grid */}
{/* Zone separator lines */} {(['35%', '65%'] as const).map(y => (
))}
{/* Zone labels */} {[ { y: '22%', label: de ? 'Produkte' : 'Products', clr: '#818cf8' }, { y: '50%', label: de ? 'KI-Proxy' : 'AI Proxy', clr: '#fbbf24' }, { y: '80%', label: de ? 'Inferenz' : 'Inference', clr: '#60a5fa' }, ].map(({ y, label, clr }) => (
{label}
))} {/* SVG: island territories + sea routes */} {/* Wide zone territory fills */} {/* Per-node island blobs (outer contour + fill) */} {nodes.map(node => { const isHub = node.id === 'litellm' const isActive = activeId === node.id const rx = isHub ? 10 : 7 const ry = isHub ? 6 : 3.8 const rxOuter = isHub ? 14.5 : 10 const ryOuter = isHub ? 8.5 : 5.5 return ( {/* Outer contour ring */} {/* Inner island fill */} ) })} {/* Sea routes */} {CONNECTIONS.map(([fromId, toId]) => { const key = `${fromId}-${toId}` const from = nodes.find(n => n.id === fromId)! const to = nodes.find(n => n.id === toId)! const isActive = activeId === fromId || activeId === toId const color = isActive ? (activeId === fromId ? from.color : to.color) : '#ffffff' return ( ) })} {/* Node markers */} {nodes.map(node => ( toggle(node.id)} /> ))} {!activeId && (
{de ? 'Komponente anklicken' : 'Click any node'}
)}
{/* ── DETAIL PANEL ─────────────────────────────────────────────── */} {active && (

{active.title}

{active.badge && ( {active.badge} )}

{active.subtitle}

{de ? 'Stack' : 'Tech Stack'}

{active.tech.map(tk => ( {tk} ))}

{de ? 'Funktionen' : 'Capabilities'}

{active.services.map(s => (
{s.name} {s.desc}
))}
{de ? 'Verbunden mit:' : 'Connects to:'} {CONNECTIONS .filter(([a, b]) => a === active.id || b === active.id) .map(([a, b]) => { const peerId = a === active.id ? b : a const peer = nodes.find(n => n.id === peerId)! return ( ) })}
)} {/* Bottom legend */} {!active && ( {[ { icon: Lock, text: de ? 'DSGVO-konform · BSI-zertifizierbar' : 'GDPR-compliant · BSI-certifiable' }, { icon: Server, text: de ? 'On-Premise oder EU-Cloud' : 'On-Premise or EU Cloud' }, { icon: Layers, text: de ? 'Air-Gap fähig' : 'Air-Gap Capable' }, ].map(({ icon: Icon, text }) => ( {text} ))} )}
) }