Files
breakpilot-core/pitch-deck/components/slides/ProblemSlide.tsx
Benjamin Boenisch b7d21daa24
All checks were successful
CI / test-bqas (push) Successful in 32s
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-consent (push) Successful in 46s
CI / test-python-voice (push) Successful in 38s
feat: Add DevSecOps tools, Woodpecker proxy, Vault persistent storage, pitch-deck annex slides
- Install Gitleaks, Trivy, Grype, Syft, Semgrep, Bandit in backend-core Dockerfile
- Add Woodpecker SQLite proxy API (fallback without API token)
- Mount woodpecker_data volume read-only to backend-core
- Add backend proxy fallback in admin-core Woodpecker route
- Add Vault file-based persistent storage (config.hcl, init-vault.sh)
- Auto-init, unseal and root-token persistence for Vault
- Add 6 pitch-deck annex slides (Assumptions, Architecture, GTM, Regulatory, Engineering, AI Pipeline)
- Dynamic margin/amortization KPIs in BusinessModelSlide
- Market sources modal with citations in MarketSlide
- Redesign nginx landing page to 3-column layout (Lehrer/Compliance/Core)
- Extend MkDocs nav with Services and SDK documentation sections
- Add SDK Protection architecture doc

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 15:42:43 +01:00

219 lines
8.8 KiB
TypeScript

'use client'
import { useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { Language } from '@/lib/types'
import { t } from '@/lib/i18n'
import { AlertTriangle, Scale, Shield, ExternalLink, X } from 'lucide-react'
import GlassCard from '../ui/GlassCard'
import GradientText from '../ui/GradientText'
import FadeInView from '../ui/FadeInView'
interface ProblemSlideProps {
lang: Language
}
interface SourceInfo {
name: string
url: string
date: string
excerpt_de: string
excerpt_en: string
}
interface ProblemCardData {
sources: SourceInfo[]
}
// Quellenangaben fuer jede Behauptung
const cardSources: ProblemCardData[] = [
{
// DSGVO: 4.1 Mrd EUR Bussgelder, 83% KMU
sources: [
{
name: 'GDPR Enforcement Tracker (CMS Law)',
url: 'https://www.enforcementtracker.com/',
date: '2025',
excerpt_de: 'Der GDPR Enforcement Tracker dokumentiert alle oeffentlich bekannten DSGVO-Bussgelder in der EU. Kumuliert belaufen sich die Bussgelder auf ueber 4,1 Mrd. EUR seit Inkrafttreten der DSGVO im Mai 2018.',
excerpt_en: 'The GDPR Enforcement Tracker documents all publicly known GDPR fines across the EU. Cumulative fines exceed EUR 4.1 billion since the GDPR took effect in May 2018.',
},
{
name: 'DIHK Digitalisierungsumfrage 2024',
url: 'https://www.dihk.de/de/themen-und-positionen/wirtschaft-digital/digitalisierung',
date: '2024',
excerpt_de: 'Laut der DIHK-Digitalisierungsumfrage 2024 geben 83% der befragten KMU an, die DSGVO-Anforderungen nicht vollstaendig umgesetzt zu haben. Hauptgruende sind mangelnde Ressourcen, fehlendes Know-how und die Komplexitaet der Vorschriften.',
excerpt_en: 'According to the DIHK Digitization Survey 2024, 83% of surveyed SMEs report not having fully implemented GDPR requirements. Main reasons cited are lack of resources, missing expertise, and regulatory complexity.',
},
],
},
{
// AI Act: August 2025
sources: [
{
name: 'EU AI Act — Verordnung (EU) 2024/1689',
url: 'https://eur-lex.europa.eu/eli/reg/2024/1689',
date: '2024-08-01',
excerpt_de: 'Die EU-KI-Verordnung (AI Act) trat am 1. August 2024 in Kraft. Ab dem 2. August 2025 gelten die Verbote fuer KI-Systeme mit unannehmbarem Risiko (Art. 5) sowie die Verpflichtungen fuer Anbieter von KI-Modellen mit allgemeinem Verwendungszweck (Art. 51-56). Ab August 2026 gelten die Anforderungen fuer Hochrisiko-KI-Systeme.',
excerpt_en: 'The EU AI Act (Regulation 2024/1689) entered into force on August 1, 2024. From August 2, 2025, prohibitions on unacceptable-risk AI systems (Art. 5) and obligations for general-purpose AI model providers (Art. 51-56) apply. Requirements for high-risk AI systems apply from August 2026.',
},
],
},
{
// NIS2: 30.000+ Unternehmen
sources: [
{
name: 'BSI — NIS-2-Umsetzungs- und Cybersicherheitsstaerkungsgesetz',
url: 'https://www.bsi.bund.de/DE/Themen/Regulierte-Wirtschaft/NIS-2-regulierte-Unternehmen/nis-2-regulierte-unternehmen_node.html',
date: '2025',
excerpt_de: 'Das NIS-2-Umsetzungsgesetz (NIS2UmsuCG) erweitert den Kreis der regulierten Unternehmen in Deutschland erheblich. Nach Schaetzungen des BSI und des BMI sind kuenftig mehr als 30.000 Unternehmen und Einrichtungen von den neuen Cybersicherheitsanforderungen betroffen — gegenueber bisher ca. 4.500 unter der NIS-1-Richtlinie.',
excerpt_en: 'The NIS-2 Implementation Act significantly expands the scope of regulated entities in Germany. According to BSI and BMI estimates, more than 30,000 companies and institutions will be affected by the new cybersecurity requirements — compared to approximately 4,500 under NIS-1.',
},
],
},
]
const icons = [AlertTriangle, Scale, Shield]
function SourceModal({
isOpen,
onClose,
cardIndex,
lang,
cardTitle,
}: {
isOpen: boolean
onClose: () => void
cardIndex: number
lang: Language
cardTitle: string
}) {
if (!isOpen) return null
const sources = cardSources[cardIndex]?.sources || []
return (
<AnimatePresence>
{isOpen && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-50 flex items-center justify-center p-4"
onClick={onClose}
>
<div className="absolute inset-0 bg-black/60 backdrop-blur-sm" />
<motion.div
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.9, opacity: 0 }}
className="relative bg-slate-900/95 border border-white/10 rounded-2xl p-6 max-w-2xl w-full max-h-[80vh] overflow-y-auto"
onClick={(e) => e.stopPropagation()}
>
<button
onClick={onClose}
className="absolute top-4 right-4 p-1 text-white/40 hover:text-white/80 transition-colors"
>
<X className="w-5 h-5" />
</button>
<h3 className="text-xl font-bold text-white mb-1">{cardTitle}</h3>
<p className="text-sm text-white/40 mb-6">
{lang === 'de' ? 'Quellenangaben' : 'Sources'}
</p>
<div className="space-y-4">
{sources.map((src, idx) => (
<div
key={idx}
className="bg-white/[0.05] border border-white/10 rounded-xl p-4"
>
<div className="flex items-start justify-between gap-3 mb-2">
<div>
<p className="text-sm font-semibold text-white">{src.name}</p>
<p className="text-xs text-white/30">{src.date}</p>
</div>
<a
href={src.url}
target="_blank"
rel="noopener noreferrer"
className="flex-shrink-0 p-1.5 text-indigo-400 hover:text-indigo-300 hover:bg-indigo-500/10 rounded-lg transition-colors"
title={lang === 'de' ? 'Quelle oeffnen' : 'Open source'}
>
<ExternalLink className="w-4 h-4" />
</a>
</div>
<p className="text-sm text-white/60 leading-relaxed">
{lang === 'de' ? src.excerpt_de : src.excerpt_en}
</p>
</div>
))}
</div>
</motion.div>
</motion.div>
)}
</AnimatePresence>
)
}
export default function ProblemSlide({ lang }: ProblemSlideProps) {
const i = t(lang)
const [activeModal, setActiveModal] = useState<number | null>(null)
return (
<div>
<FadeInView className="text-center mb-12">
<h2 className="text-4xl md:text-5xl font-bold mb-3">
<GradientText>{i.problem.title}</GradientText>
</h2>
<p className="text-lg text-white/50 max-w-2xl mx-auto">{i.problem.subtitle}</p>
</FadeInView>
<div className="grid md:grid-cols-3 gap-6 mb-12">
{i.problem.cards.map((card, idx) => {
const Icon = icons[idx]
const sourceCount = cardSources[idx]?.sources.length || 0
return (
<GlassCard
key={idx}
delay={0.2 + idx * 0.15}
className="text-center cursor-pointer group"
onClick={() => setActiveModal(idx)}
>
<div className="w-12 h-12 mx-auto mb-4 rounded-xl bg-red-500/10 flex items-center justify-center">
<Icon className="w-6 h-6 text-red-400" />
</div>
<h3 className="text-lg font-bold mb-2 text-white">{card.title}</h3>
<p className="text-3xl font-bold text-red-400 mb-3">{card.stat}</p>
<p className="text-sm text-white/50 leading-relaxed mb-3">{card.desc}</p>
<p className="text-[10px] text-indigo-400/60 group-hover:text-indigo-400 transition-colors">
{sourceCount} {lang === 'de' ? (sourceCount === 1 ? 'Quelle' : 'Quellen') : (sourceCount === 1 ? 'source' : 'sources')}
{' · '}
{lang === 'de' ? 'Klicken fuer Details' : 'Click for details'}
</p>
</GlassCard>
)
})}
</div>
<FadeInView delay={0.8} className="max-w-3xl mx-auto">
<blockquote className="text-center">
<p className="text-lg md:text-xl text-white/70 italic leading-relaxed">
&ldquo;{i.problem.quote}&rdquo;
</p>
</blockquote>
</FadeInView>
{/* Source Modals */}
{i.problem.cards.map((card, idx) => (
<SourceModal
key={idx}
isOpen={activeModal === idx}
onClose={() => setActiveModal(null)}
cardIndex={idx}
lang={lang}
cardTitle={card.title}
/>
))}
</div>
)
}