feat: Add DevSecOps tools, Woodpecker proxy, Vault persistent storage, pitch-deck annex slides
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
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
- 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>
This commit is contained in:
274
pitch-deck/components/slides/EngineeringSlide.tsx
Normal file
274
pitch-deck/components/slides/EngineeringSlide.tsx
Normal file
@@ -0,0 +1,274 @@
|
||||
'use client'
|
||||
|
||||
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 {
|
||||
Code2,
|
||||
Container,
|
||||
GitBranch,
|
||||
Layers,
|
||||
ShieldCheck,
|
||||
Terminal,
|
||||
Cpu,
|
||||
Database,
|
||||
Braces,
|
||||
FileCode2,
|
||||
Server,
|
||||
Workflow,
|
||||
} from 'lucide-react'
|
||||
|
||||
interface EngineeringSlideProps {
|
||||
lang: Language
|
||||
}
|
||||
|
||||
export default function EngineeringSlide({ lang }: EngineeringSlideProps) {
|
||||
const i = t(lang)
|
||||
const de = lang === 'de'
|
||||
|
||||
const heroStats = [
|
||||
{
|
||||
value: '691K',
|
||||
label: de ? 'Zeilen Code' : 'Lines of Code',
|
||||
sub: 'Go · Python · TypeScript',
|
||||
color: 'text-indigo-400',
|
||||
borderColor: 'border-indigo-500/30',
|
||||
},
|
||||
{
|
||||
value: '45',
|
||||
label: de ? 'Docker Container' : 'Docker Containers',
|
||||
sub: de ? 'Produktiv auf einem Mac Studio' : 'Production on one Mac Studio',
|
||||
color: 'text-emerald-400',
|
||||
borderColor: 'border-emerald-500/30',
|
||||
},
|
||||
{
|
||||
value: '27',
|
||||
label: de ? 'Microservices' : 'Microservices',
|
||||
sub: '10 Go · 9 Python · 8 Next.js',
|
||||
color: 'text-purple-400',
|
||||
borderColor: 'border-purple-500/30',
|
||||
},
|
||||
{
|
||||
value: '37',
|
||||
label: 'Dockerfiles',
|
||||
sub: de ? 'Vollstaendig containerisiert' : 'Fully containerized',
|
||||
color: 'text-amber-400',
|
||||
borderColor: 'border-amber-500/30',
|
||||
},
|
||||
]
|
||||
|
||||
const languageBreakdown = [
|
||||
{ lang: 'TypeScript / TSX', pct: 58, loc: '403K', color: 'bg-blue-500', icon: Braces },
|
||||
{ lang: 'Python', pct: 23, loc: '160K', color: 'bg-yellow-500', icon: Terminal },
|
||||
{ lang: 'Go', pct: 18, loc: '127K', color: 'bg-cyan-500', icon: Code2 },
|
||||
]
|
||||
|
||||
const devopsStack = [
|
||||
{
|
||||
icon: GitBranch,
|
||||
label: 'Gitea',
|
||||
desc: de ? 'Self-hosted Git · 4 Repos · Code Review' : 'Self-hosted Git · 4 Repos · Code Review',
|
||||
},
|
||||
{
|
||||
icon: Workflow,
|
||||
label: 'Woodpecker CI',
|
||||
desc: de ? 'Self-hosted CI/CD · Lint · Test · Build · Deploy' : 'Self-hosted CI/CD · Lint · Test · Build · Deploy',
|
||||
},
|
||||
{
|
||||
icon: Container,
|
||||
label: 'Docker Compose',
|
||||
desc: de ? '66 Service-Definitionen · Multi-Stage Builds' : '66 Service Definitions · Multi-Stage Builds',
|
||||
},
|
||||
{
|
||||
icon: ShieldCheck,
|
||||
label: 'DevSecOps',
|
||||
desc: 'Semgrep · Trivy · Gitleaks · CycloneDX SBOM',
|
||||
},
|
||||
{
|
||||
icon: Database,
|
||||
label: 'HashiCorp Vault',
|
||||
desc: de ? 'Secrets Management · Auto-Rotation · PKI' : 'Secrets Management · Auto-Rotation · PKI',
|
||||
},
|
||||
{
|
||||
icon: Server,
|
||||
label: de ? 'Infrastruktur' : 'Infrastructure',
|
||||
desc: 'Nginx · PostgreSQL · Qdrant · MinIO · Valkey',
|
||||
},
|
||||
]
|
||||
|
||||
const serviceArchitecture = [
|
||||
{
|
||||
project: 'breakpilot-core',
|
||||
color: 'text-indigo-400',
|
||||
dotColor: 'bg-indigo-400',
|
||||
services: de
|
||||
? ['Admin Dashboard', 'Consent Service (Go)', 'Billing Service (Go)', 'RAG Pipeline', 'Embedding Service', 'Voice Service', 'Pitch Deck', 'Nginx Reverse Proxy']
|
||||
: ['Admin Dashboard', 'Consent Service (Go)', 'Billing Service (Go)', 'RAG Pipeline', 'Embedding Service', 'Voice Service', 'Pitch Deck', 'Nginx Reverse Proxy'],
|
||||
},
|
||||
{
|
||||
project: 'breakpilot-lehrer',
|
||||
color: 'text-purple-400',
|
||||
dotColor: 'bg-purple-400',
|
||||
services: de
|
||||
? ['Lehrer Dashboard', 'Studio v2', 'Website', 'Klausur Service', 'School Service (Go)', 'Edu Search (Go)']
|
||||
: ['Teacher Dashboard', 'Studio v2', 'Website', 'Exam Service', 'School Service (Go)', 'Edu Search (Go)'],
|
||||
},
|
||||
{
|
||||
project: 'breakpilot-compliance',
|
||||
color: 'text-emerald-400',
|
||||
dotColor: 'bg-emerald-400',
|
||||
services: de
|
||||
? ['Compliance Dashboard', 'Developer Portal', 'AI SDK (Go)', 'Document Crawler', 'DSMS Gateway', 'Security Scanner (Go)']
|
||||
: ['Compliance Dashboard', 'Developer Portal', 'AI SDK (Go)', 'Document Crawler', 'DSMS Gateway', 'Security Scanner (Go)'],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FadeInView className="text-center mb-6">
|
||||
<p className="text-xs font-mono text-indigo-400/60 uppercase tracking-widest mb-2">
|
||||
{de ? 'Anhang' : 'Appendix'}
|
||||
</p>
|
||||
<h2 className="text-4xl md:text-5xl font-bold mb-2">
|
||||
<GradientText>{i.annex.engineering.title}</GradientText>
|
||||
</h2>
|
||||
<p className="text-lg text-white/50 max-w-2xl mx-auto">{i.annex.engineering.subtitle}</p>
|
||||
</FadeInView>
|
||||
|
||||
{/* Hero Stats */}
|
||||
<FadeInView delay={0.1}>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3 mb-5">
|
||||
{heroStats.map((stat, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className={`border rounded-xl p-3 bg-white/[0.03] text-center ${stat.borderColor}`}
|
||||
>
|
||||
<p className={`text-3xl font-black tracking-tight ${stat.color}`}>{stat.value}</p>
|
||||
<p className="text-xs font-semibold text-white/70 mt-0.5">{stat.label}</p>
|
||||
<p className="text-[10px] text-white/30 mt-0.5">{stat.sub}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</FadeInView>
|
||||
|
||||
<div className="grid md:grid-cols-12 gap-4">
|
||||
{/* Left Column: Language Breakdown + Service Map */}
|
||||
<div className="md:col-span-5 space-y-4">
|
||||
{/* Language Breakdown */}
|
||||
<FadeInView delay={0.2}>
|
||||
<GlassCard hover={false} className="p-4">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<FileCode2 className="w-4 h-4 text-white/40" />
|
||||
<p className="text-xs font-semibold text-white/40 uppercase tracking-wider">
|
||||
{de ? 'Sprachen-Mix' : 'Language Mix'}
|
||||
</p>
|
||||
</div>
|
||||
{/* Stacked bar */}
|
||||
<div className="flex rounded-full overflow-hidden h-3 mb-3">
|
||||
{languageBreakdown.map((l, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
className={`${l.color} transition-all`}
|
||||
style={{ width: `${l.pct}%` }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="space-y-1.5">
|
||||
{languageBreakdown.map((l, idx) => {
|
||||
const Icon = l.icon
|
||||
return (
|
||||
<div key={idx} className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className={`w-2 h-2 rounded-full ${l.color}`} />
|
||||
<Icon className="w-3 h-3 text-white/40" />
|
||||
<span className="text-xs text-white/60">{l.lang}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs font-mono text-white/40">{l.loc}</span>
|
||||
<span className="text-xs font-bold text-white/70">{l.pct}%</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</GlassCard>
|
||||
</FadeInView>
|
||||
|
||||
{/* Service Map */}
|
||||
<FadeInView delay={0.3}>
|
||||
<GlassCard hover={false} className="p-4">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<Layers className="w-4 h-4 text-white/40" />
|
||||
<p className="text-xs font-semibold text-white/40 uppercase tracking-wider">
|
||||
{de ? 'Service-Architektur' : 'Service Architecture'}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{serviceArchitecture.map((proj, idx) => (
|
||||
<div key={idx}>
|
||||
<p className={`text-[10px] font-bold uppercase tracking-wider ${proj.color} mb-1`}>
|
||||
{proj.project}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{proj.services.map((svc, sidx) => (
|
||||
<span
|
||||
key={sidx}
|
||||
className="text-[10px] px-1.5 py-0.5 rounded bg-white/[0.05] text-white/50 border border-white/[0.06]"
|
||||
>
|
||||
{svc}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</GlassCard>
|
||||
</FadeInView>
|
||||
</div>
|
||||
|
||||
{/* Right Column: DevOps Stack */}
|
||||
<div className="md:col-span-7">
|
||||
<FadeInView delay={0.25}>
|
||||
<GlassCard hover={false} className="p-4 h-full">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<Cpu className="w-4 h-4 text-white/40" />
|
||||
<p className="text-xs font-semibold text-white/40 uppercase tracking-wider">
|
||||
{de ? 'DevOps & Toolchain' : 'DevOps & Toolchain'}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
{devopsStack.map((tool, idx) => {
|
||||
const Icon = tool.icon
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className="flex items-start gap-3 p-2.5 rounded-lg bg-white/[0.03] border border-white/5"
|
||||
>
|
||||
<div className="w-8 h-8 rounded-lg bg-indigo-500/10 border border-indigo-500/20 flex items-center justify-center shrink-0">
|
||||
<Icon className="w-4 h-4 text-indigo-400" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-sm font-semibold text-white/80">{tool.label}</p>
|
||||
<p className="text-xs text-white/40 mt-0.5">{tool.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{/* Footer note */}
|
||||
<div className="mt-3 pt-3 border-t border-white/5">
|
||||
<p className="text-[10px] text-white/20 text-center">
|
||||
{de
|
||||
? '100% Self-Hosted · Kein externer Cloud-Anbieter · Vollstaendige Kontrolle ueber Code und Daten'
|
||||
: '100% Self-Hosted · No External Cloud Provider · Full Control Over Code and Data'}
|
||||
</p>
|
||||
</div>
|
||||
</GlassCard>
|
||||
</FadeInView>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user