-
- {d.hub.title}
- {d.hub.body}
- {d.hub.bullets && (
-
- )}
-
+
+
+
+ {de ? 'Die Schleife' : 'The Loop'}
+
+
{d.hub.title}
+
{d.hub.body}
+
)
@@ -168,33 +190,37 @@ export function PrintRegulatoryLandscapePage({ lang, pageNum, totalPages, versio
/* ===== PRODUCT / MODULAR TOOLKIT ===== */
+const MODULE_ICONS: LucideIcon[] = [
+ ScanLine, ShieldCheck, FileText, ClipboardCheck, Users, UserCheck,
+ AlertTriangle, Brain, Target, GraduationCap, TrendingUp, MessageSquare,
+]
const MODULES_FULL_DE = [
- { name: 'Code Security', icon: '◇', desc: 'SAST · DAST · SBOM · Container · Secrets · Pentesting', features: ['Bei jedem Push', 'Auto-Fix LLM', 'CI/CD-integriert'] },
- { name: 'CE-SW-Risikobeurteilung', icon: '◇', desc: 'CE-Kennzeichnung für Maschinen mit Software-Anteil', features: ['Maschinen-VO', 'CRA-konform', 'Code-Basis-Analyse'] },
- { name: 'Compliance-Dokumente', icon: '◇', desc: 'VVT (Art. 30) · TOMs · DSFA (Art. 35) · Löschkonzept', features: ['Auto-Generiert', 'Versionsverlauf', 'Audit-tauglich'] },
- { name: 'Audit Manager', icon: '◇', desc: 'Abweichungen End-to-End: Rollen · Stichtage · Eskalation', features: ['Tickets + Nachweise', 'GF-Eskalation', 'Compliance-SLA'] },
- { name: 'DSR / Betroffenenrechte', icon: '◇', desc: 'Auskunft, Berichtigung, Löschung, Datenübertragbarkeit', features: ['Self-Service', 'Identitätsprüfung', 'Frist-Tracking'] },
- { name: 'Consent', icon: '◇', desc: 'Einwilligungs-Management, Cookie-Banner, ePrivacy', features: ['CMP integriert', 'Audit-Log', 'Multi-Tenant'] },
- { name: 'Incident Response', icon: '◇', desc: 'Vorfälle, Meldung (72h), Mitigation, Forensik', features: ['Art. 33/34 DSGVO', 'BSI-Meldepfade', 'Forensik-Hooks'] },
- { name: 'Compliance LLM', icon: '◇', desc: 'GPT für Text + Audio, EU-gehostet, mit Quellenangabe', features: ['Self-Hosted', 'EU-souverän', 'Audit-zitierbar'] },
- { name: 'Tender Matching', icon: '◇', desc: 'RFQ-Antworten automatisch gegen Codebase + Policies', features: ['Stunden statt Wochen', 'Win-ready', 'Klausel-Mapping'] },
- { name: 'Academy', icon: '◇', desc: 'Online-Schulungen für Geschäftsführung und Mitarbeiter', features: ['Mandatory Training', 'Zertifikate', 'GF-Pflicht erfüllt'] },
- { name: 'Compliance Optimizer', icon: '◇', desc: 'Maximale KI-Nutzung im legalen Rahmen, ersetzt 20-200k € Anwaltskosten', features: ['ROI-ranking', 'Sweet-Spot', 'Risikobalance'] },
- { name: 'Kommunikation', icon: '◇', desc: 'Chat (Matrix) + Video (Jitsi) + KI-Support', features: ['Self-Hosted', 'EU-Hosting', 'Audit-Logs'] },
+ { name: 'Code Security', desc: 'SAST · DAST · SBOM · Container · Secrets · Pentesting', features: ['Bei jedem Push', 'Auto-Fix LLM', 'CI/CD-integriert'] },
+ { name: 'CE-SW-Risikobeurteilung', desc: 'CE-Kennzeichnung für Maschinen mit Software-Anteil', features: ['Maschinen-VO', 'CRA-konform', 'Code-Basis-Analyse'] },
+ { name: 'Compliance-Dokumente', desc: 'VVT (Art. 30) · TOMs · DSFA (Art. 35) · Löschkonzept', features: ['Auto-Generiert', 'Versionsverlauf', 'Audit-tauglich'] },
+ { name: 'Audit Manager', desc: 'Abweichungen End-to-End: Rollen · Stichtage · Eskalation', features: ['Tickets + Nachweise', 'GF-Eskalation', 'Compliance-SLA'] },
+ { name: 'DSR / Betroffenenrechte', desc: 'Auskunft, Berichtigung, Löschung, Datenübertragbarkeit', features: ['Self-Service', 'Identitätsprüfung', 'Frist-Tracking'] },
+ { name: 'Consent', desc: 'Einwilligungs-Management, Cookie-Banner, ePrivacy', features: ['CMP integriert', 'Audit-Log', 'Multi-Tenant'] },
+ { name: 'Incident Response', desc: 'Vorfälle, Meldung (72h), Mitigation, Forensik', features: ['Art. 33/34 DSGVO', 'BSI-Meldepfade', 'Forensik-Hooks'] },
+ { name: 'Compliance LLM', desc: 'GPT für Text + Audio, EU-gehostet, mit Quellenangabe', features: ['Self-Hosted', 'EU-souverän', 'Audit-zitierbar'] },
+ { name: 'Tender Matching', desc: 'RFQ-Antworten automatisch gegen Codebase + Policies', features: ['Stunden statt Wochen', 'Win-ready', 'Klausel-Mapping'] },
+ { name: 'Academy', desc: 'Online-Schulungen für Geschäftsführung und Mitarbeiter', features: ['Mandatory Training', 'Zertifikate', 'GF-Pflicht erfüllt'] },
+ { name: 'Compliance Optimizer', desc: 'Maximale KI-Nutzung im legalen Rahmen, ersetzt 20-200k € Anwaltskosten', features: ['ROI-ranking', 'Sweet-Spot', 'Risikobalance'] },
+ { name: 'Kommunikation', desc: 'Chat (Matrix) + Video (Jitsi) + KI-Support', features: ['Self-Hosted', 'EU-Hosting', 'Audit-Logs'] },
]
const MODULES_FULL_EN = [
- { name: 'Code Security', icon: '◇', desc: 'SAST · DAST · SBOM · Container · Secrets · Pentesting', features: ['Every push', 'Auto-fix LLM', 'CI/CD integrated'] },
- { name: 'CE SW Risk Assessment', icon: '◇', desc: 'CE marking for machinery with software', features: ['Machinery Reg.', 'CRA-compliant', 'Code-level analysis'] },
- { name: 'Compliance Documents', icon: '◇', desc: 'RoPA (Art. 30) · TOMs · DPIA (Art. 35) · Retention', features: ['Auto-generated', 'Version history', 'Audit-ready'] },
- { name: 'Audit Manager', icon: '◇', desc: 'Deviations end-to-end: roles · deadlines · escalation', features: ['Tickets + evidence', 'Mgmt escalation', 'Compliance SLA'] },
- { name: 'DSR / Data Subject Rights', icon: '◇', desc: 'Access, rectification, erasure, portability', features: ['Self-service', 'Identity check', 'Deadline tracking'] },
- { name: 'Consent', icon: '◇', desc: 'Consent mgmt, cookie banner, ePrivacy', features: ['CMP integrated', 'Audit log', 'Multi-tenant'] },
- { name: 'Incident Response', icon: '◇', desc: 'Breaches, reporting (72h), mitigation, forensics', features: ['GDPR Art. 33/34', 'BSI channels', 'Forensic hooks'] },
- { name: 'Compliance LLM', icon: '◇', desc: 'GPT for text + audio, EU-hosted, with citations', features: ['Self-hosted', 'EU-sovereign', 'Audit-citable'] },
- { name: 'Tender Matching', icon: '◇', desc: 'RFQ answers automatically against codebase + policies', features: ['Hours not weeks', 'Win-ready', 'Clause mapping'] },
- { name: 'Academy', icon: '◇', desc: 'Online training for management and staff', features: ['Mandatory training', 'Certificates', 'Mgmt duties fulfilled'] },
- { name: 'Compliance Optimizer', icon: '◇', desc: 'Max AI use within legal limits, replaces €20-200k legal fees', features: ['ROI ranking', 'Sweet spot', 'Risk balance'] },
- { name: 'Communication', icon: '◇', desc: 'Chat (Matrix) + video (Jitsi) + AI support', features: ['Self-hosted', 'EU hosting', 'Audit logs'] },
+ { name: 'Code Security', desc: 'SAST · DAST · SBOM · Container · Secrets · Pentesting', features: ['Every push', 'Auto-fix LLM', 'CI/CD integrated'] },
+ { name: 'CE SW Risk Assessment', desc: 'CE marking for machinery with software', features: ['Machinery Reg.', 'CRA-compliant', 'Code-level analysis'] },
+ { name: 'Compliance Documents', desc: 'RoPA (Art. 30) · TOMs · DPIA (Art. 35) · Retention', features: ['Auto-generated', 'Version history', 'Audit-ready'] },
+ { name: 'Audit Manager', desc: 'Deviations end-to-end: roles · deadlines · escalation', features: ['Tickets + evidence', 'Mgmt escalation', 'Compliance SLA'] },
+ { name: 'DSR / Data Subject Rights', desc: 'Access, rectification, erasure, portability', features: ['Self-service', 'Identity check', 'Deadline tracking'] },
+ { name: 'Consent', desc: 'Consent mgmt, cookie banner, ePrivacy', features: ['CMP integrated', 'Audit log', 'Multi-tenant'] },
+ { name: 'Incident Response', desc: 'Breaches, reporting (72h), mitigation, forensics', features: ['GDPR Art. 33/34', 'BSI channels', 'Forensic hooks'] },
+ { name: 'Compliance LLM', desc: 'GPT for text + audio, EU-hosted, with citations', features: ['Self-hosted', 'EU-sovereign', 'Audit-citable'] },
+ { name: 'Tender Matching', desc: 'RFQ answers automatically against codebase + policies', features: ['Hours not weeks', 'Win-ready', 'Clause mapping'] },
+ { name: 'Academy', desc: 'Online training for management and staff', features: ['Mandatory training', 'Certificates', 'Mgmt duties fulfilled'] },
+ { name: 'Compliance Optimizer', desc: 'Max AI use within legal limits, replaces €20-200k legal fees', features: ['ROI ranking', 'Sweet spot', 'Risk balance'] },
+ { name: 'Communication', desc: 'Chat (Matrix) + video (Jitsi) + AI support', features: ['Self-hosted', 'EU hosting', 'Audit logs'] },
]
export function PrintProductPage({ products, lang, pageNum, totalPages, versionName }: SlideBase & { products: PitchProduct[] }) {
@@ -205,16 +231,22 @@ export function PrintProductPage({ products, lang, pageNum, totalPages, versionN
- {modules.map((m, i) => (
-
-
-
{m.name}
-
{String(i + 1).padStart(2, '0')}
+ {modules.map((m, i) => {
+ const Icon = MODULE_ICONS[i]
+ return (
+
+
+
+
+
+
{m.name}
+
{String(i + 1).padStart(2, '0')}
+
+
{m.desc}
+
{m.features.join(' · ')}
-
{m.desc}
-
{m.features.join(' · ')}
-
- ))}
+ )
+ })}
@@ -249,18 +281,8 @@ export function PrintHowItWorksPage({ lang, pageNum, totalPages, versionName }:
return (
- {/* horizontal step flow */}
-
- {steps.map((s, i) => (
-
- {i < steps.length - 1 && (
-
- )}
-
{s.n}
-
{s.t}
-
{s.d}
-
- ))}
+
+
diff --git a/pitch-deck/app/pitch-print/[versionId]/page.tsx b/pitch-deck/app/pitch-print/[versionId]/page.tsx
index 737749e..1c92a2d 100644
--- a/pitch-deck/app/pitch-print/[versionId]/page.tsx
+++ b/pitch-deck/app/pitch-print/[versionId]/page.tsx
@@ -65,29 +65,28 @@ export default async function PitchPrintPage({ params, searchParams }: Ctx) {
fp_scenarios: (map.fm_scenarios || []) as FpScenarioRef[],
}
- // Financial variant: fetch FM results + parse assumptions
+ // Always fetch FM results + assumptions so the standard PDF can render the
+ // annex-finanzplan slide. The `financial` flag only adds the extra detail
+ // P&L page and the cap-table page.
let fmResults: FMResult[] = []
let fmAssumptions: FMAssumption[] = []
- if (financial) {
- const scenarios = (map.fm_scenarios || []) as FpScenarioRef[]
- const defaultScenario = scenarios.find(s => s.is_default) ?? scenarios[0] ?? null
-
- if (defaultScenario?.id) {
- const resultsRes = await pool.query(
- `SELECT * FROM pitch_fm_results WHERE scenario_id = $1 ORDER BY month`,
- [defaultScenario.id],
- )
- fmResults = resultsRes.rows as FMResult[]
- }
-
- const rawAssumptions = (map.fm_assumptions || []) as Array
>
- fmAssumptions = rawAssumptions.map(a => ({
- ...a,
- value: typeof a.value === 'string' ? JSON.parse(a.value as string) : a.value,
- })) as FMAssumption[]
+ const scenarios = (map.fm_scenarios || []) as FpScenarioRef[]
+ const defaultScenario = scenarios.find(s => s.is_default) ?? scenarios[0] ?? null
+ if (defaultScenario?.id) {
+ const resultsRes = await pool.query(
+ `SELECT * FROM pitch_fm_results WHERE scenario_id = $1 ORDER BY month`,
+ [defaultScenario.id],
+ )
+ fmResults = resultsRes.rows as FMResult[]
}
+ const rawAssumptions = (map.fm_assumptions || []) as Array>
+ fmAssumptions = rawAssumptions.map(a => ({
+ ...a,
+ value: typeof a.value === 'string' ? JSON.parse(a.value as string) : a.value,
+ })) as FMAssumption[]
+
return (