fix(pitch-print): architecture diagram overflow — compact ServiceNode
Build pitch-deck / build-push-deploy (push) Successful in 2m1s
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 41s
CI / test-python-voice (push) Successful in 36s
CI / test-bqas (push) Successful in 34s
Build pitch-deck / build-push-deploy (push) Successful in 2m1s
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 41s
CI / test-python-voice (push) Successful in 36s
CI / test-bqas (push) Successful in 34s
Infrastructure layer was being cut off (only the chip showed; the 3 inference service cards never rendered). Root cause: each tier was double-wrapped — an outer tinted layer card AND inner bordered FlowNode cards — which inflated the total height past A4 landscape. Replaces inner FlowNode (border + padding + footer rule) with a new flat ServiceNode used only inside the tinted layer wrappers: - no own border / no own padding - title 11pt → 10pt, kicker 7pt → 6pt - caps inner items to 4 max - mono tech footer in 6pt with hairline separator Also tightened the connectors between tiers: was a 12mm row of three VArrow SVGs each with its own padding, now a 5mm row of three compact down-arrow SVGs. Saves ~14mm of vertical space. Layer chip sizing reduced (7.5pt → 7pt, padding 1.5mm → 1mm) so each chip takes less of its layer card. Result: all three layers fit on one A4 landscape page with the LLM Inference / Embeddings / AI Tools cards visible. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -131,57 +131,90 @@ export function ArchitectureDiagram({
|
||||
|
||||
/** Layer pill: "01 · APPLICATION LAYER" + sub-label */
|
||||
const LayerChip = ({ n, label, sub, tint }: { n: string; label: string; sub: string; tint: string }) => (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '4mm', marginBottom: '3mm' }}>
|
||||
<span style={{ fontFamily: MONO, fontSize: '7.5pt', fontWeight: 700, color: tint, textTransform: 'uppercase', letterSpacing: '0.2em', background: '#ffffff', padding: '1.5mm 4mm', borderRadius: '99pt', border: `1px solid ${tint}55`, WebkitPrintColorAdjust: 'exact', printColorAdjust: 'exact' }}>{n} · {label}</span>
|
||||
<span style={{ fontSize: '8.5pt', color: COLORS.slate600, fontStyle: 'italic' }}>{sub}</span>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '3mm', marginBottom: '2mm' }}>
|
||||
<span style={{ fontFamily: MONO, fontSize: '7pt', fontWeight: 700, color: tint, textTransform: 'uppercase', letterSpacing: '0.2em', background: '#ffffff', padding: '1mm 3mm', borderRadius: '99pt', border: `1px solid ${tint}66`, WebkitPrintColorAdjust: 'exact', printColorAdjust: 'exact' }}>{n} · {label}</span>
|
||||
<span style={{ fontSize: '7.5pt', color: COLORS.slate600, fontStyle: 'italic' }}>{sub}</span>
|
||||
</div>
|
||||
)
|
||||
|
||||
const productLayerBg = `linear-gradient(135deg, ${COLORS.violet50} 0%, #ffffff 50%, ${COLORS.violet50} 100%)`
|
||||
const proxyLayerBg = `linear-gradient(135deg, ${COLORS.amber50} 0%, #fffaf0 50%, ${COLORS.amber50} 100%)`
|
||||
/**
|
||||
* ServiceNode — flat, no own border. Used INSIDE a tinted layer card so the
|
||||
* whole layer reads as one panel rather than nested boxes (which is what
|
||||
* was causing the architecture diagram to overflow).
|
||||
*/
|
||||
const ServiceNode = ({ kicker, title, subtitle, items, footer, accent }: { kicker?: string; title: string; subtitle?: string; items: string[]; footer?: string; accent: string }) => (
|
||||
<div style={{ padding: '0 1mm', display: 'flex', flexDirection: 'column' }}>
|
||||
{kicker && <div style={{ fontFamily: MONO, fontSize: '6pt', fontWeight: 700, color: accent, textTransform: 'uppercase', letterSpacing: '0.16em', marginBottom: '0.5mm' }}>{kicker}</div>}
|
||||
<div style={{ fontSize: '10pt', fontWeight: 700, color: COLORS.slate900, lineHeight: 1.15 }}>{title}</div>
|
||||
{subtitle && <div style={{ fontSize: '7.5pt', color: accent, fontWeight: 600, marginTop: '0.5mm' }}>{subtitle}</div>}
|
||||
<div style={{ marginTop: '1.5mm' }}>
|
||||
{items.slice(0, 4).map((it, i) => (
|
||||
<div key={i} style={{ fontSize: '7pt', color: COLORS.slate700, lineHeight: 1.35, padding: '0.4mm 0', borderTop: i > 0 ? `1px solid ${COLORS.slate100}` : 'none' }}>· {it}</div>
|
||||
))}
|
||||
</div>
|
||||
{footer && <div style={{ marginTop: '1.5mm', paddingTop: '1mm', borderTop: `1px solid ${COLORS.slate200}`, fontFamily: MONO, fontSize: '6pt', color: COLORS.slate500, lineHeight: 1.4 }}>{footer}</div>}
|
||||
</div>
|
||||
)
|
||||
|
||||
const productLayerBg = `linear-gradient(135deg, ${COLORS.violet50} 0%, #ffffff 60%, ${COLORS.violet50} 100%)`
|
||||
const proxyLayerBg = `linear-gradient(135deg, ${COLORS.amber50} 0%, #fffaf0 60%, ${COLORS.amber50} 100%)`
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '2mm' }}>
|
||||
{/* APPLICATION (PRODUCT) LAYER */}
|
||||
<div style={{ background: productLayerBg, border: `1px solid ${COLORS.violet200}`, borderRadius: '4pt', padding: '4mm 5mm', WebkitPrintColorAdjust: 'exact', printColorAdjust: 'exact' }}>
|
||||
<div style={{ background: productLayerBg, border: `1px solid ${COLORS.violet200}`, borderRadius: '4pt', padding: '3mm 4mm', WebkitPrintColorAdjust: 'exact', printColorAdjust: 'exact' }}>
|
||||
<LayerChip n="01" label={de ? 'Application Layer' : 'Application Layer'} sub={de ? 'Kundenseitige Services' : 'User-facing services'} tint={COLORS.violet600} />
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '4mm' }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '5mm' }}>
|
||||
{product.map((p, i) => (
|
||||
<FlowNode key={i} kicker={p.kicker} title={p.title} subtitle={p.subtitle} items={p.services} accent={COLORS.violet600} footer={p.tech} />
|
||||
<ServiceNode key={i} kicker={p.kicker} title={p.title} subtitle={p.subtitle} items={p.services} accent={COLORS.violet600} footer={p.tech} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* connectors */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '4mm', padding: '0 5mm' }}>
|
||||
{[0, 1, 2].map(i => <VArrow key={i} color={COLORS.violet500} />)}
|
||||
{/* compact connector strip */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '4mm', padding: '0 5mm', height: '5mm', alignItems: 'center' }}>
|
||||
{[0, 1, 2].map(i => (
|
||||
<div key={i} style={{ display: 'flex', justifyContent: 'center' }}>
|
||||
<svg viewBox="0 0 12 16" width="3mm" height="5mm">
|
||||
<line x1="6" y1="0" x2="6" y2="12" stroke={COLORS.violet500} strokeWidth="1.2" />
|
||||
<polyline points="3,11 6,15 9,11" fill="none" stroke={COLORS.violet500} strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* GATEWAY LAYER */}
|
||||
<div style={{ background: proxyLayerBg, border: `1.5px solid ${COLORS.amber600}`, borderRadius: '4pt', padding: '4mm 5mm', WebkitPrintColorAdjust: 'exact', printColorAdjust: 'exact' }}>
|
||||
{/* GATEWAY LAYER — compact: title row + features in 1 row */}
|
||||
<div style={{ background: proxyLayerBg, border: `1.5px solid ${COLORS.amber600}`, borderRadius: '4pt', padding: '3mm 4mm', WebkitPrintColorAdjust: 'exact', printColorAdjust: 'exact' }}>
|
||||
<LayerChip n="02" label={de ? 'Gateway Layer' : 'Gateway Layer'} sub={de ? 'Routing & Guardrails' : 'Routing & guardrails'} tint={COLORS.amber700} />
|
||||
<div style={{ display: 'flex', alignItems: 'baseline', gap: '4mm', marginBottom: '3mm' }}>
|
||||
<span style={{ fontSize: '13pt', fontWeight: 800, color: COLORS.slate900, letterSpacing: '-0.005em' }}>{proxy.title}</span>
|
||||
<span style={{ fontFamily: MONO, fontSize: '7.5pt', color: COLORS.amber700, fontWeight: 600, letterSpacing: '0.04em' }}>{proxy.subtitle}</span>
|
||||
<div style={{ display: 'flex', alignItems: 'baseline', gap: '4mm', marginBottom: '2mm' }}>
|
||||
<span style={{ fontSize: '12pt', fontWeight: 800, color: COLORS.slate900, letterSpacing: '-0.005em' }}>{proxy.title}</span>
|
||||
<span style={{ fontFamily: MONO, fontSize: '7pt', color: COLORS.amber700, fontWeight: 600 }}>{proxy.subtitle}</span>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: '3mm', fontSize: '7.5pt', color: COLORS.slate700 }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: '3mm', fontSize: '7pt', color: COLORS.slate700 }}>
|
||||
{proxy.features.map((f, i) => (
|
||||
<div key={i} style={{ paddingLeft: '2mm', borderLeft: `1px solid ${COLORS.amber600}`, lineHeight: 1.35 }}>{f}</div>
|
||||
<div key={i} style={{ paddingLeft: '2mm', borderLeft: `1px solid ${COLORS.amber600}`, lineHeight: 1.3 }}>{f}</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* connectors */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '4mm', padding: '0 5mm' }}>
|
||||
{[0, 1, 2].map(i => <VArrow key={i} color={COLORS.amber600} />)}
|
||||
{/* compact connector strip */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '4mm', padding: '0 5mm', height: '5mm', alignItems: 'center' }}>
|
||||
{[0, 1, 2].map(i => (
|
||||
<div key={i} style={{ display: 'flex', justifyContent: 'center' }}>
|
||||
<svg viewBox="0 0 12 16" width="3mm" height="5mm">
|
||||
<line x1="6" y1="0" x2="6" y2="12" stroke={COLORS.amber600} strokeWidth="1.2" />
|
||||
<polyline points="3,11 6,15 9,11" fill="none" stroke={COLORS.amber600} strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* INFRASTRUCTURE (INFERENCE) LAYER */}
|
||||
<div style={{ background: productLayerBg, border: `1px solid ${COLORS.violet200}`, borderRadius: '4pt', padding: '4mm 5mm', WebkitPrintColorAdjust: 'exact', printColorAdjust: 'exact' }}>
|
||||
<div style={{ background: productLayerBg, border: `1px solid ${COLORS.violet200}`, borderRadius: '4pt', padding: '3mm 4mm', WebkitPrintColorAdjust: 'exact', printColorAdjust: 'exact' }}>
|
||||
<LayerChip n="03" label={de ? 'Infrastructure Layer' : 'Infrastructure Layer'} sub={de ? 'Compute & Daten · lokal · air-gap-fähig' : 'Compute & data · local · air-gap capable'} tint={COLORS.violet600} />
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '4mm' }}>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '5mm' }}>
|
||||
{inference.map((p, i) => (
|
||||
<FlowNode key={i} title={p.title} subtitle={p.subtitle} items={[p.desc]} accent={COLORS.violet500} footer={p.tech} />
|
||||
<ServiceNode key={i} title={p.title} subtitle={p.subtitle} items={[p.desc]} accent={COLORS.violet500} footer={p.tech} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user