'use client' import { useState, useEffect, useRef, Fragment } 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 { Brain, Shield, ScanLine, Zap, Cpu, Layers, Wrench, X, Users, Lock, Server, BadgeCheck, } from 'lucide-react' interface ArchitectureSlideProps { lang: Language } type NodeId = 'certifai' | 'complai' | 'scanner' | 'litellm' | 'llm' | 'embeddings' | 'tools' interface NodeDef { id: NodeId icon: React.ElementType title: string subtitle: string color: string tech: string[] services: { name: string; desc: string }[] primary?: boolean tier: 'product' | 'proxy' | 'inference' } function getNodes(de: boolean): NodeDef[] { return [ { id: 'certifai', icon: Brain, title: 'CERTifAI', subtitle: de ? 'GenAI Mandantenportal' : 'GenAI Tenant Portal', color: '#c084fc', tier: 'product', tech: ['Rust', 'Dioxus', 'MongoDB', 'Keycloak', 'SearXNG', 'LangGraph'], services: [ { name: 'LiteLLM Dashboard', desc: de ? 'Modellverwaltung & Kostentracking' : 'Model mgmt & cost tracking' }, { name: 'LibreChat + SSO', desc: de ? 'Mandanten-Chat mit Keycloak' : 'Tenant chat with Keycloak' }, { name: 'LangGraph Agents', desc: de ? 'Agent-Orchestrierung' : 'Agent orchestration' }, { name: 'MCP Hub', desc: de ? 'Tool-Integration für KI-Clients' : 'Tool integration for AI clients' }, ], }, { id: 'complai', icon: Shield, title: 'COMPLAI', subtitle: de ? 'Compliance & Audit' : 'Compliance & Audit', color: '#818cf8', tier: '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: 'Control Pipeline', desc: de ? 'Gesetzestextanalyse via LLM' : 'Legal text analysis via LLM' }, { name: 'MCP Client', desc: de ? 'Echtzeit-Findings vom Scanner' : 'Real-time findings from Scanner' }, ], }, { id: 'scanner', icon: ScanLine, title: 'Compliance Scanner', subtitle: de ? 'Code-Sicherheit' : 'Code Security', color: '#34d399', tier: 'product', 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 COMPLAI' : 'Live findings for COMPLAI' }, ], }, { id: 'litellm', icon: Zap, title: 'LiteLLM Proxy', subtitle: de ? 'KI-Gateway & Guardrails' : 'AI Gateway & Guardrails', color: '#fbbf24', tier: 'proxy', primary: true, tech: ['OpenAI-kompatible API', 'Bearer Auth', 'Rate Limiting', 'PII-Filter', 'Spend Tracking'], services: [ { name: de ? 'Token-Budget' : 'Token Budget', desc: de ? 'Pro-Mandant Kontingente & Abrechnung' : 'Per-tenant quotas & billing' }, { name: 'PII Guardrails', desc: de ? 'Datenschutz-Filter für alle Anfragen' : 'Privacy filter on all requests' }, { name: de ? 'Web-Suche (anonym)' : 'Web Search (anon)', desc: de ? 'SearXNG-Proxy, kein US-Anbieter' : 'SearXNG proxy, no US providers' }, { name: de ? 'Namespace-Isolierung' : 'Namespace Isolation', desc: de ? 'Mandantentrennung per API-Key' : 'Tenant isolation per API key' }, { name: de ? 'Failover-Routing' : 'Failover Routing', desc: de ? 'Automatisches Fallback' : 'Automatic fallback between models' }, ], }, { id: 'llm', icon: Cpu, title: de ? 'LLM Inferenz' : 'LLM Inference', subtitle: de ? 'Lokale Sprachmodelle' : 'Local Language Models', color: '#60a5fa', tier: 'inference', tech: ['Qwen3-32B', 'Qwen3-Coder-30B', 'DeepSeek-R1-8B', 'Ollama'], 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' }, { name: de ? 'GPU-optimiert' : 'GPU-optimized', desc: de ? 'Dedizierte Inferenz-Hardware' : 'Dedicated inference hardware' }, ], }, { id: 'embeddings', icon: Layers, title: 'Embeddings', subtitle: de ? 'Semantische Suche' : 'Semantic Search', color: '#a78bfa', tier: 'inference', tech: ['bge-m3', 'Qdrant Vector DB', 'Sentence-Transformers'], services: [ { name: 'RAG Pipeline', desc: de ? '75+ Rechtsquellen indexiert' : '75+ legal sources indexed' }, { name: de ? 'Semantische Suche' : 'Semantic Search', desc: de ? 'Multi-linguale Einbettungen' : 'Multi-lingual embeddings' }, { name: de ? 'Lokal' : 'Fully local', desc: de ? 'Keine externen APIs' : 'No external APIs' }, ], }, { id: 'tools', icon: Wrench, title: de ? 'KI-Tools' : 'AI Tools', subtitle: de ? 'Web-Suche & MCP' : 'Web Search & MCP', color: '#2dd4bf', tier: 'inference', tech: ['SearXNG', 'MCP Protocol', 'Semgrep API', 'Gitleaks API'], services: [ { name: 'SearXNG', desc: de ? 'Anonymisierte EU-Websuche' : 'Anonymized EU web search' }, { name: 'MCP Tools', desc: de ? 'Auditdokumente & Code-Findings' : 'Audit docs & code findings' }, { name: de ? 'Kein US-Anbieter' : 'No US providers', desc: de ? '100% DSGVO-konform' : '100% GDPR-compliant' }, ], }, ] } const LAYERS: { id: string; nodeIds: NodeId[]; tint: string; depth: number }[] = [ { id: 'product', nodeIds: ['certifai', 'complai', 'scanner'], tint: '#a78bfa', depth: 24 }, { id: 'proxy', nodeIds: ['litellm'], tint: '#fbbf24', depth: 12 }, { id: 'inference', nodeIds: ['llm', 'embeddings', 'tools'], tint: '#8b5cf6', depth: 0 }, ] const CSS_KF = ` @keyframes v4FlowDown { from { stroke-dashoffset: 0 } to { stroke-dashoffset: -18px } } @keyframes v4Pulse { 0%,100% { opacity:1;transform:scale(1) } 50% { opacity:.4;transform:scale(1.4) } } @keyframes v4Caret { 0%,50% { opacity:1 } 51%,100% { opacity:0 } } @keyframes v4DotFall { 0% { transform: translateY(-5px); opacity: 0; } 12% { opacity: 1; } 88% { opacity: 1; } 100% { transform: translateY(38px); opacity: 0; } } ` const MONO: React.CSSProperties = { fontFamily: '"JetBrains Mono","SF Mono",ui-monospace,monospace', fontVariantNumeric: 'tabular-nums', } // ── Theme detection ─────────────────────────────────────────────────────────── function useIsLight() { const [isLight, setIsLight] = useState(false) useEffect(() => { const check = () => setIsLight(document.documentElement.classList.contains('theme-light')) check() const obs = new MutationObserver(check) obs.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }) return () => obs.disconnect() }, []) return isLight } // ── Ticker primitives ───────────────────────────────────────────────────────── function useTicker(fn: () => void, min = 140, max = 360, skipChance = 0.1) { const ref = useRef(fn) ref.current = fn useEffect(() => { let tid: ReturnType const loop = () => { if (Math.random() > skipChance) ref.current() tid = setTimeout(loop, min + Math.random() * (max - min)) } loop() return () => clearTimeout(tid) }, [min, max, skipChance]) } function TickerShell({ color, children, isLight }: { color: string; children: React.ReactNode; isLight: boolean }) { return (
{children}
) } function Caret({ color }: { color: string }) { return ( ) } // ── Per-node tickers ────────────────────────────────────────────────────────── function TickCertifAI({ color, isLight }: { color: string; isLight: boolean }) { const [n, setN] = useState(8421) const [hash, setHash] = useState('9f3a…e10b') const pool = 'abcdef0123456789' const r = (k: number) => Array.from({ length: k }, () => pool[Math.floor(Math.random() * pool.length)]).join('') useTicker(() => { setN(v => v + 1); setHash(`${r(4)}…${r(4)}`) }, 1000, 2000, 0.1) return ( sig {n.toLocaleString()} {hash} ) } function TickComplAI({ color, isLight }: { color: string; isLight: boolean }) { const [evals, setEvals] = useState(1284) const [rate, setRate] = useState(99.2) useTicker(() => { setEvals(v => v + 1 + Math.floor(Math.random() * 3)) setRate(r => Math.max(97, Math.min(99.9, r + (Math.random() - 0.5) * 0.4))) }, 200, 500, 0.1) return ( eval {evals.toLocaleString()} pass {rate.toFixed(1)}% ) } function TickScanner({ color, isLight }: { color: string; isLight: boolean }) { const lines = [ { k: 'PASS', c: '#16a34a', cd: '#4ade80', t: 'CWE-79 xss check' }, { k: 'WARN', c: '#d97706', cd: '#fbbf24', t: 'drift: model v2.1→2.2' }, { k: 'PASS', c: '#16a34a', cd: '#4ade80', t: 'bias: demographic parity' }, { k: 'FAIL', c: '#dc2626', cd: '#f87171', t: 'license: GPL-3 detected' }, { k: 'PASS', c: '#16a34a', cd: '#4ade80', t: 'prompt-inject: 214 vectors' }, { k: 'SCAN', c: '#7c3aed', cd: '#a78bfa', t: 'artifact model-card.json' }, ] const [i, setI] = useState(0) useTicker(() => setI(x => (x + 1) % lines.length), 700, 1200, 0.05) const l = lines[i] return ( {l.k} {l.t} ) } function TickLiteLLM({ color, isLight }: { color: string; isLight: boolean }) { const [rps, setRps] = useState(428) const [p50, setP50] = useState(84) useTicker(() => { setRps(v => Math.max(200, Math.min(800, v + (Math.random() - 0.5) * 60))) setP50(v => Math.max(40, Math.min(160, v + (Math.random() - 0.5) * 20))) }, 250, 500, 0.05) return ( req/s {Math.round(rps)} · p50 {Math.round(p50)}ms ) } function TickLLM({ color, isLight }: { color: string; isLight: boolean }) { const [tokens, setTokens] = useState(14832) const [stream, setStream] = useState('t_a91f') const pool = 'abcdef0123456789' useTicker(() => { setTokens(v => v + 1 + Math.floor(Math.random() * 5)) setStream('t_' + Array.from({ length: 4 }, () => pool[Math.floor(Math.random() * pool.length)]).join('')) }, 120, 340, 0.15) return ( tok {tokens.toLocaleString()} {stream} ) } function TickEmbeddings({ color, isLight }: { color: string; isLight: boolean }) { const [vecs, setVecs] = useState(284112) useTicker(() => setVecs(v => v + 1 + Math.floor(Math.random() * 8)), 180, 420, 0.1) return ( idx {vecs.toLocaleString()} · 1024d ) } function TickTools({ color, isLight }: { color: string; isLight: boolean }) { const ops = [ 'search("BSI C5 controls")', 'fetch eur-lex.europa.eu', 'grep -r "DSGVO"', 'read docs/policy.md', 'mcp.call(filesystem)', 'search("vLLM 0.6 release")', ] const [i, setI] = useState(0) useTicker(() => setI(x => (x + 1) % ops.length), 900, 1600, 0.05) return ( call {ops[i]} ) } const NODE_TICKER: Record> = { certifai: TickCertifAI, complai: TickComplAI, scanner: TickScanner, litellm: TickLiteLLM, llm: TickLLM, embeddings: TickEmbeddings, tools: TickTools, } // ── Animated connector ──────────────────────────────────────────────────────── function LayerConnector({ tint }: { tint: string }) { const tracks = [ { x: '32%', primary: false }, { x: '50%', primary: true }, { x: '68%', primary: false }, ] return (
{tracks.map(({ x, primary }, ti) => { const color = primary ? '#fbbf24' : tint const dots = primary ? 4 : 3 const dur = primary ? 1.6 : 2.4 return (
{Array.from({ length: dots }, (_, j) => (
))}
) })}
) } // ── Node card ───────────────────────────────────────────────────────────────── function NodeCard({ node, selected, onClick, isLight }: { node: NodeDef; selected: boolean; onClick: () => void; isLight: boolean }) { const [hover, setHover] = useState(false) const active = hover || selected const c = node.color const Ticker = NODE_TICKER[node.id] const Icon = node.icon return ( ) } // ── 3D slab ─────────────────────────────────────────────────────────────────── function LayerSlab({ label, sublabel, nodes, tint, depth, selectedId, onSelect, isLight }: { label: string; sublabel: string; nodes: NodeDef[] tint: string; depth: number selectedId: NodeId | null; onSelect: (id: NodeId) => void isLight: boolean }) { const isProxy = nodes.length === 1 && !!nodes[0].primary return (
{label}
{sublabel}
{isProxy ? (
onSelect(nodes[0].id)} isLight={isLight} />
) : ( nodes.map(n => ( onSelect(n.id)} isLight={isLight} /> )) )}
) } // ── Main slide ──────────────────────────────────────────────────────────────── export default function ArchitectureSlide({ lang }: ArchitectureSlideProps) { const i = t(lang) const de = lang === 'de' const isLight = useIsLight() const allNodes = getNodes(de) const nodeMap = Object.fromEntries(allNodes.map(n => [n.id, n])) as Record const [activeId, setActiveId] = useState(null) function toggle(id: NodeId) { setActiveId(prev => prev === id ? null : id) } const active = activeId ? nodeMap[activeId] : null const tenants = de ? ['Mandant A', 'Mandant B', 'Mandant C', 'Mandant N…'] : ['Namespace A', 'Namespace B', 'Namespace C', 'Namespace N…'] const layerLabels = de ? ['01 · Anwendung', '02 · Gateway', '03 · Infrastruktur'] : ['01 · Application', '02 · Gateway', '03 · Infrastructure'] const layerSublabels = de ? ['Benutzeroberflächen', 'Routing & Guardrails', 'Compute & Daten'] : ['User-facing services', 'Routing & guardrails', 'Compute & data'] return (

{de ? 'Anhang' : 'Appendix'}

{i.annex.architecture.title}

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

{de ? 'Kundenmandanten' : 'Customer Namespaces'} {tenants.map(tn => ( {tn} ))}
{/* ── Main canvas ── */}
{/* Ambient glows */} {!isLight && ( <>
)} {/* Slabs + connectors */}
{LAYERS.map((layer, li) => { const nodes = layer.nodeIds.map(id => nodeMap[id]) return ( {li < LAYERS.length - 1 && } ) })}
{/* Footer badges */}
{([ { Icon: Lock, label: de ? 'Kein US-Anbieter · 100% DSGVO' : 'No US providers · 100% GDPR' }, { Icon: Server, label: de ? 'BSI-zertifiziertes Rechenzentrum' : 'BSI-certified data center' }, { Icon: BadgeCheck, label: de ? 'EU-souveräne Inferenz' : 'EU-sovereign inference' }, ] as { Icon: React.ElementType; label: string }[]).map(({ Icon, label }) => (
{label}
))}
{/* Detail panel */} {active && (
{active.title} {active.tier === 'product' ? (de ? 'Anwendung' : 'Application') : active.tier === 'proxy' ? 'Gateway' : (de ? 'Inferenz' : 'Inference')}
{active.subtitle}
{de ? 'Stack' : 'Tech Stack'}
{active.tech.map(tk => ( {tk} ))}
{de ? 'Funktionen' : 'Capabilities'}
{active.services.map(s => (
{s.name} {s.desc}
))}
)}
) }