diff --git a/pitch-deck/app/api/data/route.ts b/pitch-deck/app/api/data/route.ts index 413a179..58899d9 100644 --- a/pitch-deck/app/api/data/route.ts +++ b/pitch-deck/app/api/data/route.ts @@ -78,6 +78,16 @@ export async function GET() { } } catch (error) { console.error('Database query error:', error) + // Return minimal stub in dev so the pitch renders without a DB connection + if (process.env.NODE_ENV === 'development') { + return NextResponse.json({ + company: { name: 'BreakPilot', tagline: '[dev mode — no DB]' }, + team: [], financials: [], market: [], competitors: [], + features: [], milestones: [], metrics: [], + funding: { instrument: 'Wandeldarlehen', amount: 500000, valuation_cap: 3000000, currency: 'EUR' }, + products: [], + }) + } return NextResponse.json({ error: 'Failed to load pitch data' }, { status: 500 }) } } diff --git a/pitch-deck/components/slides/ArchitectureSlide.tsx b/pitch-deck/components/slides/ArchitectureSlide.tsx index bc293e4..f4beb86 100644 --- a/pitch-deck/components/slides/ArchitectureSlide.tsx +++ b/pitch-deck/components/slides/ArchitectureSlide.tsx @@ -1,129 +1,588 @@ '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 GlassCard from '../ui/GlassCard' -import { Server, Cpu, Shield, Database, Globe, Lock, Layers, Workflow } from 'lucide-react' +import { + Shield, Brain, ScanLine, Zap, Cpu, Globe, Cloud, + X, Users, Lock, Server, Network, ChevronRight, Layers, +} from 'lucide-react' interface ArchitectureSlideProps { lang: Language } -export default function ArchitectureSlide({ lang }: ArchitectureSlideProps) { - const i = t(lang) - const de = lang === 'de' +type NodeId = 'breakpilot' | 'certifai' | 'compliance-scanner' | 'litellm' | 'ollama' | 'claude' | 'openai' - const layers = [ - { - icon: Server, - color: 'text-indigo-400', - bg: 'bg-indigo-500/10 border-indigo-500/20', - title: de ? 'Hardware-Schicht' : 'Hardware Layer', - items: [ - { label: 'ComplAI Mini', desc: de ? 'Mac Mini M4 (geplant, optional)' : 'Mac Mini M4 (planned, optional)' }, - { label: 'ComplAI Studio', desc: de ? 'Mac Studio M4 Max (geplant, optional)' : 'Mac Studio M4 Max (planned, optional)' }, - { label: 'ComplAI Cloud', desc: de ? 'BSI-zertifizierte Cloud in Deutschland' : 'BSI-certified cloud in Germany' }, - ], - }, - { - icon: Cpu, - color: 'text-purple-400', - bg: 'bg-purple-500/10 border-purple-500/20', - title: de ? 'KI-Engine' : 'AI Engine', - items: [ - { label: 'Ollama Runtime', desc: de ? 'Lokale LLM-Inferenz, GPU-optimiert' : 'Local LLM inference, GPU-optimized' }, - { label: 'RAG Pipeline', desc: de ? 'Vektorsuche mit Compliance-Wissensbasis' : 'Vector search with compliance knowledge base' }, - { label: 'Agent Framework', desc: de ? 'Autonome Compliance-Agenten (Audit, Monitoring, Reporting)' : 'Autonomous compliance agents (Audit, Monitoring, Reporting)' }, - ], - }, +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, - color: 'text-emerald-400', - bg: 'bg-emerald-500/10 border-emerald-500/20', - title: de ? 'Compliance-Module' : 'Compliance Modules', - items: [ - { label: 'DSGVO Engine', desc: de ? 'VVT, DSFA, Betroffenenrechte, Löschkonzept' : 'RoPA, DPIA, Data Subject Rights, Deletion Concept' }, - { label: 'AI Act Module', desc: de ? 'Risikoklassifizierung, Konformitätsbewertung, Dokumentation' : 'Risk Classification, Conformity Assessment, Documentation' }, - { label: 'NIS2 Module', desc: de ? 'Cybersecurity-Policies, Incident Response, Meldewege' : 'Cybersecurity Policies, Incident Response, Reporting Chains' }, + 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' }, ], }, { - icon: Layers, - color: 'text-blue-400', - bg: 'bg-blue-500/10 border-blue-500/20', - title: de ? 'Plattform-Services' : 'Platform Services', - items: [ - { label: de ? 'Admin-Dashboard' : 'Admin Dashboard', desc: 'Next.js · ' + (de ? 'Mandantenfähig · Rollenbasiert' : 'Multi-Tenant · Role-Based') }, - { label: 'SDK API', desc: 'Go/Gin · REST · ' + (de ? 'Tenant-isoliert' : 'Tenant-Isolated') }, - { label: 'DevSecOps Suite', desc: 'Semgrep · Trivy · Gitleaks · CycloneDX SBOM' }, + 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' }, ], }, ] +} - const securityFeatures = [ - { icon: Lock, label: de ? 'Zero-Trust Architektur' : 'Zero-Trust Architecture' }, - { icon: Database, label: de ? 'Daten verlassen nie BSI-zertifizierte Server in DE' : 'Data Never Leaves BSI-Certified Servers in DE' }, - { icon: Globe, label: de ? '100% EU-Cloud · Keine US-Anbieter' : '100% EU Cloud · No US Providers' }, - { icon: Workflow, label: de ? 'Air-Gap fähig' : 'Air-Gap Capable' }, - ] +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 ( -
- -

- {de ? 'Anhang' : 'Appendix'} -

-

- {i.annex.architecture.title} -

-

{i.annex.architecture.subtitle}

-
+ +
+ {/* Ripple pulse when active */} + {active && ( + + )} - {/* Architecture Layers */} -
- {layers.map((layer, idx) => { - const Icon = layer.icon - return ( - -
-
- -

{layer.title}

-
-
- {layer.items.map((item, iidx) => ( -
-
-
- {item.label} - {item.desc} -
-
- ))} -
-
- - ) - })} + {/* Icon circle */} +
+ + {/* Spinning dashed ring on active hub */} + {isHub && active && ( + + )} +
- {/* Security Bar */} - - -
- {securityFeatures.map((feat, idx) => { - const Icon = feat.icon + {/* 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 ( -
- - {feat.label} -
+ + {/* 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} + + ))} + + )}
) diff --git a/pitch-deck/lib/i18n.ts b/pitch-deck/lib/i18n.ts index a3e68b3..7a7d0b0 100644 --- a/pitch-deck/lib/i18n.ts +++ b/pitch-deck/lib/i18n.ts @@ -26,7 +26,9 @@ const translations = { 'Investition & Cap Table', 'Kundenersparnis', 'KI Q&A', - 'Anhang: Architektur', + 'Anhang: Annahmen', + 'Anhang: Systemarchitektur', + 'Anhang: Go-to-Market', 'Anhang: Regulatorik', 'Anhang: Engineering', 'Anhang: KI-Pipeline', @@ -276,8 +278,8 @@ const translations = { subtitle: 'Drei Szenarien für robuste Planung', }, architecture: { - title: 'Technische Architektur', - subtitle: 'Self-Hosted KI-Stack für maximale Datensouveränität', + title: 'Systemarchitektur', + subtitle: 'BreakPilot · CERTifAI · Compliance Scanner — verbunden über LiteLLM', }, gtm: { title: 'Go-to-Market Strategie', @@ -322,7 +324,9 @@ const translations = { 'Investment & Cap Table', 'Customer Savings', 'AI Q&A', - 'Appendix: Architecture', + 'Appendix: Assumptions', + 'Appendix: System Architecture', + 'Appendix: Go-to-Market', 'Appendix: Regulatory', 'Appendix: Engineering', 'Appendix: AI Pipeline', @@ -572,8 +576,8 @@ const translations = { subtitle: 'Three scenarios for robust planning', }, architecture: { - title: 'Technical Architecture', - subtitle: 'Self-hosted AI stack for maximum data sovereignty', + title: 'System Architecture', + subtitle: 'BreakPilot · CERTifAI · Compliance Scanner — connected via LiteLLM', }, gtm: { title: 'Go-to-Market Strategy', diff --git a/pitch-deck/middleware.ts b/pitch-deck/middleware.ts index 5a0f33d..2cfd3ba 100644 --- a/pitch-deck/middleware.ts +++ b/pitch-deck/middleware.ts @@ -34,6 +34,11 @@ export async function middleware(request: NextRequest) { const { pathname } = request.nextUrl const secret = process.env.PITCH_JWT_SECRET + // Skip all auth in local dev when no secret is configured + if (!secret && process.env.NODE_ENV === 'development') { + return NextResponse.next() + } + // Allow public paths if (isPublicPath(pathname)) { return NextResponse.next() diff --git a/pitch-deck/package.json b/pitch-deck/package.json index 2c0a658..e78f486 100644 --- a/pitch-deck/package.json +++ b/pitch-deck/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "private": true, "scripts": { - "dev": "next dev -p 3012", + "dev": "next dev --turbopack -p 3012", "build": "next build", "start": "next start -p 3012", "admin:create": "tsx scripts/create-admin.ts",