<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Sizing Calculator — Mek-Tech</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/style.css">
  <link rel="stylesheet" href="/css/dynamic.css">
  <link rel="icon" href="/img/favicon.svg" type="image/svg+xml">
<style>
:root{--sb-w:200px;--hdr-h:48px}
html,body{height:100%;margin:0;padding:0}
body{background:var(--bg);font-family:'Inter',-apple-system,sans-serif}
.app-layout{display:flex;min-height:100vh;padding-top:var(--hdr-h)}
.sidebar{position:fixed;top:var(--hdr-h);left:0;width:var(--sb-w);height:calc(100vh - var(--hdr-h));background:var(--bg-nav);border-right:1px solid var(--border);display:flex;flex-direction:column;z-index:50;overflow-y:auto}
.sb-brand{padding:.75rem 1rem;border-bottom:1px solid var(--border)}
.sb-brand h2{font-size:.8rem;font-weight:600;color:var(--text)}
.sb-brand p{font-size:.6rem;color:var(--text-dim)}
.sb-nav{flex:1;padding:.35rem 0}
.sb-item{display:flex;align-items:center;gap:.5rem;padding:.45rem .85rem;margin:1px .4rem;border-radius:var(--radius);cursor:pointer;font-size:.78rem;color:var(--text-muted);transition:all .12s;border:none;background:none;width:calc(100% - .8rem);text-align:left;font-family:inherit}
.sb-item:hover{color:var(--text);background:var(--border-light)}
.sb-item.active{color:var(--accent);background:rgba(88,166,255,.08);font-weight:600}
.sb-item .sb-icon{width:20px;text-align:center;font-size:.85rem;flex-shrink:0}
.main-area{flex:1;margin-left:var(--sb-w);padding:1.25rem 1.5rem 3rem;max-width:1200px}
.page-hdr{margin-bottom:1.25rem}
.page-hdr h1{font-size:1.4rem;color:var(--text);font-weight:600}
.page-hdr p{font-size:.8rem;color:var(--text-muted);margin-top:.1rem}
.sel-bar{display:flex;gap:.5rem;margin-bottom:1.25rem;flex-wrap:wrap}
.sel-bar select{padding:.45rem .7rem;font-size:.8rem;background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);color:var(--text);cursor:pointer;min-width:200px}
.sel-bar select:focus{outline:none;border-color:var(--accent)}
.calc-grid{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
@media(max-width:768px){.calc-grid{grid-template-columns:1fr}}
.calc-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:1.25rem}
.calc-card h3{font-size:.75rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:.3px;margin-bottom:1rem}
.calc-card h4{font-size:.85rem;color:var(--text);margin-bottom:.35rem}
.calc-input{margin-bottom:.75rem}
.calc-input label{display:block;font-size:.72rem;color:var(--text-muted);margin-bottom:.2rem}
.calc-input input,.calc-input select{width:100%;padding:.4rem .6rem;font-size:.8rem;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);color:var(--text)}
.calc-input input:focus{outline:none;border-color:var(--accent)}
.result-card{background:var(--bg-nav);border:1px solid var(--border);border-radius:var(--radius);padding:1rem;margin-top:.5rem}
.result-card .r-row{display:flex;justify-content:space-between;align-items:center;padding:.35rem 0;border-bottom:1px solid var(--border-light)}
.result-card .r-row:last-child{border-bottom:none}
.result-card .r-label{font-size:.75rem;color:var(--text-muted)}
.result-card .r-val{font-size:.85rem;color:var(--text);font-weight:600}
.result-card .r-val.accent{color:var(--accent)}
.result-card .r-val.green{color:var(--green)}
.result-card .r-val.orange{color:var(--orange)}
.result-card .r-val.purple{color:var(--purple)}
.r-highlight{background:rgba(88,166,255,.06);border-radius:var(--radius);padding:.6rem .75rem;margin-top:.5rem}
.r-highlight .rh-title{font-size:.65rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:.3px}
.r-highlight .rh-val{font-size:1.1rem;font-weight:700;color:var(--accent);margin-top:.1rem}
.r-recommendation{background:var(--green-bg);border:1px solid var(--green);border-radius:var(--radius);padding:.75rem;margin-top:.75rem}
.r-recommendation .rr-title{font-size:.65rem;color:var(--green);text-transform:uppercase;letter-spacing:.3px;margin-bottom:.25rem}
.r-recommendation .rr-text{font-size:.78rem;color:var(--text)}
.desc-text{font-size:.78rem;color:var(--text-muted);line-height:1.5;margin-bottom:.75rem}
</style>
<script src="https://unpkg.com/lucide@latest"></script></head>
<body>
<nav class="navbar"><div class="nav-inner"><a href="/" class="nav-brand"><img src="/img/logo.svg" class="nav-logo" alt="Mek-Tech"></a><div style="display:flex;align-items:center;gap:.4rem"><a href="/" class="nav-icon-btn" title="Dashboard"><i data-lucide="layout-dashboard" style="width:15px;height:15px"></i> Dashboard</a><button class="theme-toggle" id="themeToggle" onclick="toggleTheme()"></button><a href="/auth/logout" class="nav-icon-btn" style="color:var(--red)"><i data-lucide="log-out" style="width:15px;height:15px"></i> Uitloggen</a></div></div></nav>

<div class="app-layout">
<aside class="sidebar">
<div class="sb-brand"><h2>Mek-Tech Sizing</h2><p>Data Architecture Calculator</p></div>
<nav class="sb-nav">
<button class="sb-item active" data-platform="kafka"><span class="sb-icon">📨</span> Apache Kafka</button>
<button class="sb-item" data-platform="spark"><span class="sb-icon">⚡</span> Apache Spark</button>
<button class="sb-item" data-platform="minio"><span class="sb-icon">💾</span> MinIO / S3</button>
<button class="sb-item" data-platform="sap-hana"><span class="sb-icon">🔷</span> SAP HANA</button>
<button class="sb-item" data-platform="warehouse"><span class="sb-icon">🏛</span> Data Warehouse</button>
<button class="sb-item" data-platform="vector"><span class="sb-icon">🧠</span> Vector Store</button>
<button class="sb-item" data-platform="k8s"><span class="sb-icon">⎈</span> Kubernetes</button>
<button class="sb-item" data-platform="hadoop"><span class="sb-icon">📊</span> Hadoop HDFS</button>
<button class="theme-toggle" id="themeToggle" onclick="toggleTheme()"></button></nav>
</aside>

<div class="main-area">
<div class="page-hdr">
<h1>Data Architecture Sizing Calculator</h1>
<p>Best-practice dimensionering voor enterprise data platforms — gebaseerd op 15+ jaar ervaring</p>
</div>

<div class="sel-bar">
<select id="platformSelect" onchange="switchPlatform(this.value)">
<option value="kafka">Apache Kafka / Event Streaming</option>
<option value="spark">Apache Spark / Flink</option>
<option value="minio">MinIO / S3 Object Storage</option>
<option value="sap-hana">SAP HANA Platform</option>
<option value="warehouse">Data Warehouse / Iceberg</option>
<option value="vector">Vector Store / Embeddings</option>
<option value="k8s">Kubernetes Cluster</option>
<option value="hadoop">Hadoop HDFS / Data Lake</option>
</select>
</div>

<!-- KAFKA -->
<div class="calc-panel" id="panel-kafka">
<div class="desc-text">Bereken de optimale Kafka cluster configuratie op basis van throughput, retentie en replicatie. Geschikt voor Confluent, Red Hat AMQ Streams, en Apache Kafka.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Berichten per seconde (msg/s)</label><input type="number" id="k-msgs" value="500000" oninput="calcKafka()"></div>
<div class="calc-input"><label>Gem. berichtgrootte (KB)</label><input type="number" id="k-msgSize" value="5" step="0.5" oninput="calcKafka()"></div>
<div class="calc-input"><label>Retentie (dagen)</label><input type="number" id="k-retention" value="7" oninput="calcKafka()"></div>
<div class="calc-input"><label>Replicatie factor</label><select id="k-replicas" onchange="calcKafka()"><option value="2">2 (Standard)</option><option value="3" selected>3 (Enterprise)</option><option value="4">4 (Mission Critical)</option></select></div>
<div class="calc-input"><label>Disk snelheid (MB/s per disk)</label><select id="k-diskSpeed" onchange="calcKafka()"><option value="200">HDD 7200rpm (~200 MB/s)</option><option value="550" selected>SSD SATA (~550 MB/s)</option><option value="3500">NVMe (~3500 MB/s)</option><option value="7000">Optane (~7000 MB/s)</option></select></div>
<div class="calc-input"><label>Compressie</label><select id="k-compress" onchange="calcKafka()"><option value="1">Geen (1:1)</option><option value="0.4" selected>Snappy / LZ4 (0.4x)</option><option value="0.25">ZSTD (0.25x)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Doorvoer (bruto)</span><span class="r-val accent" id="k-throughput">—</span></div>
<div class="r-row"><span class="r-label">Doorvoer (netto na compressie)</span><span class="r-val" id="k-throughputNet">—</span></div>
<div class="r-row"><span class="r-label">Opslag per dag</span><span class="r-val" id="k-daily">—</span></div>
<div class="r-row"><span class="r-label">Totale opslag (retentie)</span><span class="r-val" id="k-total">—</span></div>
<div class="r-row"><span class="r-label">Totaal met replicatie</span><span class="r-val orange" id="k-totalRep">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen partitions</span><span class="r-val" id="k-partitions">—</span></div>
<div class="r-row"><span class="r-label">Min. brokers (performance)</span><span class="r-val" id="k-brokers">—</span></div>
</div>
<div class="r-highlight">
<div class="rh-title">Aanbevolen Cluster Configuratie</div>
<div class="rh-val" id="k-clusterRec">—</div>
</div>
<div class="r-recommendation" id="k-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">Voor enterprise Kafka deployments raden wij 3 replication factor aan met minstens 3 brokers. Gebruik NVMe storage voor critical workloads, SSD voor standard. Partition count = max(3 × brokers, throughput / 10MB).</div>
</div>
</div>
</div>
</div>

<!-- SPARK -->
<div class="calc-panel" id="panel-spark" style="display:none">
<div class="desc-text">Dimensionering voor Apache Spark en Flink workloads. Optimaliseer executors, cores, memory en dynamic allocation voor batch en streaming.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Data volume per dag (GB)</label><input type="number" id="s-data" value="500" oninput="calcSpark()"></div>
<div class="calc-input"><label>Processing type</label><select id="s-type" onchange="calcSpark()"><option value="batch">Batch (dagelijks)</option><option value="stream" selected>Streaming (real-time)</option><option value="ml">ML Training</option></select></div>
<div class="calc-input"><label>Gewenste processing time (min)</label><input type="number" id="s-time" value="30" oninput="calcSpark()"></div>
<div class="calc-input"><label>Beschikbaar geheugen per node (GB)</label><select id="s-ram" onchange="calcSpark()"><option value="64">64 GB</option><option value="128">128 GB</option><option value="256" selected>256 GB</option><option value="512">512 GB</option><option value="1024">1024 GB</option></select></div>
<div class="calc-input"><label>CPU cores per node</label><select id="s-cores" onchange="calcSpark()"><option value="16">16 cores</option><option value="32" selected>32 cores</option><option value="64">64 cores</option><option value="96">96 cores</option></select></div>
<div class="calc-input"><label>Dynamic allocation</label><select id="s-dynamic" onchange="calcSpark()"><option value="0">Uit</option><option value="1" selected>Aan (min-max)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Aanbevolen executors</span><span class="r-val accent" id="s-executors">—</span></div>
<div class="r-row"><span class="r-label">Cores per executor</span><span class="r-val" id="s-coresPerExec">—</span></div>
<div class="r-row"><span class="r-label">Memory per executor (GB)</span><span class="r-val" id="s-memPerExec">—</span></div>
<div class="r-row"><span class="r-label">Totale cluster RAM (GB)</span><span class="r-val purple" id="s-totalRam">—</span></div>
<div class="r-row"><span class="r-label">Totale vCores</span><span class="r-val" id="s-totalCores">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen worker nodes</span><span class="r-val green" id="s-workers">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Totale cluster capaciteit</div><div class="rh-val" id="s-clusterRec">—</div></div>
<div class="r-recommendation" id="s-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">Standaard Spark config: 5 cores per executor, 4-8 GB overhead per executor. Voor streaming gebruik 2-3 cores per executor. Altijd dynamic allocation inschakelen voor fluctuaties.</div>
</div>
</div>
</div>
</div>

<!-- MINIO -->
<div class="calc-panel" id="panel-minio" style="display:none">
<div class="desc-text">Sizing voor MinIO object storage clusters. Berekent erasure coding, drive configuratie en totale bruikbare capaciteit. Geschikt voor S3-compatible storage.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Bruto opslag capaciteit (TB)</label><input type="number" id="m-capacity" value="500" oninput="calcMinio()"></div>
<div class="calc-input"><label>Drive grootte (TB)</label><select id="m-driveSize" onchange="calcMinio()"><option value="4">4 TB</option><option value="8">8 TB</option><option value="14">14 TB</option><option value="18">18 TB</option><option value="22" selected>22 TB</option><option value="30">30 TB</option></select></div>
<div class="calc-input"><label>Erasure Code (EC)</label><select id="m-ec" onchange="calcMinio()"><option value="4:2">4 data + 2 parity (1.5x)</option><option value="8:4" selected>8 data + 4 parity (1.5x)</option><option value="12:4">12 data + 4 parity (1.33x)</option><option value="10:6">10 data + 6 parity (1.6x)</option><option value="16:8">16 data + 8 parity (1.5x)</option></select></div>
<div class="calc-input"><label>Redundantie</label><select id="m-redundancy" onchange="calcMinio()"><option value="no">Geen (single node)</option><option value="rack" selected>Rack-aware (3 racks)</option><option value="region">Region-aware (2 regio's)</option></select></div>
<div class="calc-input"><label>Compressie (avg)</label><select id="m-compress" onchange="calcMinio()"><option value="1">Geen</option><option value="0.6" selected>Gemiddeld (0.6x)</option><option value="0.3">Hoog (0.3x)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Aantal drives</span><span class="r-val" id="m-drives">—</span></div>
<div class="r-row"><span class="r-label">Aantal nodes</span><span class="r-val" id="m-nodes">—</span></div>
<div class="r-row"><span class="r-label">Bruto capaciteit</span><span class="r-val" id="m-gross">—</span></div>
<div class="r-row"><span class="r-label">EC overhead factor</span><span class="r-val" id="m-ecFactor">—</span></div>
<div class="r-row"><span class="r-label">Bruikbaar na EC</span><span class="r-val accent" id="m-usable">—</span></div>
<div class="r-row"><span class="r-label">Effectief na compressie</span><span class="r-val green" id="m-effective">—</span></div>
<div class="r-row"><span class="r-label">Min. nodes aanbevolen</span><span class="r-val purple" id="m-minNodes">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Aanbevolen Configuratie</div><div class="rh-val" id="m-clusterRec">—</div></div>
<div class="r-recommendation" id="m-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">Minio EC:8+4 is de sweet spot voor enterprise — 1.5x overhead met 4 parity failures tolerantie. Gebruik minimaal 12 nodes (24 drives) voor productie. Rack-aware deployment voor datacenter resiliency.</div>
</div>
</div>
</div>
</div>

<!-- SAP HANA -->
<div class="calc-panel" id="panel-sap-hana" style="display:none">
<div class="desc-text">SAP HANA memory en platform sizing. Berekent vereist geheugen, CPU en opslag op basis van SAP best practices en ervaringscijfers.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>SAP module / workload</label><select id="h-module" onchange="calcHana()"><option value="s4hana" selected>S/4HANA</option><option value="bw">BW/4HANA</option><option value="bpc">BPC</option><option value="slt">SLT</option><option value="mix">Mixed workload</option></select></div>
<div class="calc-input"><label>Actieve gebruikers</label><input type="number" id="h-users" value="500" oninput="calcHana()"></div>
<div class="calc-input"><label>Data volume (GB, huidig)</label><input type="number" id="h-data" value="500" oninput="calcHana()"></div>
<div class="calc-input"><label>Groei per jaar (%)</label><input type="number" id="h-growth" value="20" oninput="calcHana()"></div>
<div class="calc-input"><label>HA (High Availability)</label><select id="h-ha" onchange="calcHana()"><option value="1">Scale-up (standby)</option><option value="0">Geen HA</option></select></div>
<div class="calc-input"><label>DR (Disaster Recovery)</label><select id="h-dr" onchange="calcHana()"><option value="1">Async replicatie</option><option value="0" selected>Geen DR</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Berekend geheugen (RAM)</span><span class="r-val accent" id="h-ram">—</span></div>
<div class="r-row"><span class="r-label">waarvan data footprint</span><span class="r-val" id="h-dataFP">—</span></div>
<div class="r-row"><span class="r-label">waarvan overhead / growth</span><span class="r-val" id="h-overhead">—</span></div>
<div class="r-row"><span class="r-label">CPU cores aanbevolen</span><span class="r-val" id="h-cpu">—</span></div>
<div class="r-row"><span class="r-label">Opslag (data + logs)</span><span class="r-val orange" id="h-storage">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen node type</span><span class="r-val purple" id="h-nodeType">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Totale HANA Platform Sizing</div><div class="rh-val" id="h-clusterRec">—</div></div>
<div class="r-recommendation" id="h-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">SAP HANA geheugen: 1GB RAM per 50GB data (S/4HANA) of 1:4 (BW/4HANA). Tel 20-30% overhead voor growth en workloads. Scale-up voor performance, scale-out voor capaciteit. Gebruik minimaal 2x data voor opslag (logs + backups).</div>
</div>
</div>
</div>
</div>

<!-- DATA WAREHOUSE -->
<div class="calc-panel" id="panel-warehouse" style="display:none">
<div class="desc-text">Dimensionering voor Data Warehouse en Lakehouse architecturen (Iceberg, Snowflake, Redshift, BigQuery). Berekent compute/storage verhouding.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Bruto data volume (TB)</label><input type="number" id="w-volume" value="100" oninput="calcWarehouse()"></div>
<div class="calc-input"><label>Daily change (ingest/CDC)</label><input type="number" id="w-ingest" value="500" oninput="calcWarehouse()"><span style="font-size:.6rem;color:var(--text-dim)">GB per dag</span></div>
<div class="calc-input"><label>Concurrent queries</label><select id="w-queries" onchange="calcWarehouse()"><option value="5">5 (Small)</option><option value="20" selected>20 (Medium)</option><option value="50">50 (Large)</option><option value="100">100 (Enterprise)</option></select></div>
<div class="calc-input"><label>Query complexiteit</label><select id="w-complexity" onchange="calcWarehouse()"><option value="simple">Simpel (SELECT/WHERE)</option><option value="moderate" selected>Gemiddeld (JOINs, aggregaties)</option><option value="complex">Complex (multi-JOIN, window)</option></select></div>
<div class="calc-input"><label>Architectuur</label><select id="w-arch" onchange="calcWarehouse()"><option value="lakehouse" selected>Lakehouse (Iceberg + Trino)</option><option value="cloud">Cloud DW (Snowflake)</option><option value="mpp">MPP (Redshift)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Gecomprimeerde data (Snappy)</span><span class="r-val" id="w-compressed">—</span></div>
<div class="r-row"><span class="r-label">Effectieve opslag (incl. replicatie)</span><span class="r-val" id="w-total">—</span></div>
<div class="r-row"><span class="r-label">Compute eenheden</span><span class="r-val accent" id="w-compute">—</span></div>
<div class="r-row"><span class="r-label">Geheugen (GB)</span><span class="r-val" id="w-ram">—</span></div>
<div class="r-row"><span class="r-label">vCores</span><span class="r-val" id="w-vcores">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen nodes</span><span class="r-val green" id="w-nodes">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Aanbevolen Platform Configuratie</div><div class="rh-val" id="w-clusterRec">—</div></div>
<div class="r-recommendation" id="w-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">Lakehouse: Iceberg tables + Trino/Presto query engine. Reken op 5-8x compressie op Parquet. Compute/storage scheiding geeft flexibiliteit. Voor 100TB data: 4-8 worker nodes met 64GB RAM + 16 cores.</div>
</div>
</div>
</div>
</div>

<!-- VECTOR STORE -->
<div class="calc-panel" id="panel-vector" style="display:none">
<div class="desc-text">Sizing voor vector databases en embedding stores (Pinecone, Weaviate, Qdrant, Milvus). Berekent geheugen, dimensies en index grootte.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Aantal vectors (miljoenen)</label><input type="number" id="v-vectors" value="50" oninput="calcVector()"></div>
<div class="calc-input"><label>Vector dimensies</label><select id="v-dims" onchange="calcVector()"><option value="384">384 (all-MiniLM)</option><option value="768" selected>768 (gte-small)</option><option value="1024">1024 (ADA-002)</option><option value="1536">1536 (text-embedding-3)</option></select></div>
<div class="calc-input"><label>Index type</label><select id="v-index" onchange="calcVector()"><option value="flat">Flat (exact, brute force)</option><option value="hnsw" selected>HNSW (approximate, aanbevolen)</option><option value="ivf">IVF (inverted file)</option></select></div>
<div class="calc-input"><label>Replicatie factor</label><select id="v-replicas" onchange="calcVector()"><option value="1">Geen</option><option value="2" selected>2x (HA)</option><option value="3">3x (Enterprise)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Ruwe vector grootte (GB)</span><span class="r-val" id="v-raw">—</span></div>
<div class="r-row"><span class="r-label">Index overhead</span><span class="r-val" id="v-indexOverhead">—</span></div>
<div class="r-row"><span class="r-label">Totaal geheugen (RAM)</span><span class="r-val accent" id="v-ram">—</span></div>
<div class="r-row"><span class="r-label">Totaal met replicatie</span><span class="r-val orange" id="v-total">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen nodes</span><span class="r-val green" id="v-nodes">—</span></div>
<div class="r-row"><span class="r-label">Node type</span><span class="r-val purple" id="v-nodeType">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Aanbevolen Vector Store</div><div class="rh-val" id="v-clusterRec">—</div></div>
<div class="r-recommendation" id="v-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">HNSW index met 768 dims is de sweet spot voor enterprise. Reken op 2-3x ruwe data voor index overhead. Houd minimaal 2x RAM vrij naast de vector index voor query processing. Gebruik replica's voor HA.</div>
</div>
</div>
</div>
</div>

<!-- KUBERNETES -->
<div class="calc-panel" id="panel-k8s" style="display:none">
<div class="desc-text">Kubernetes cluster sizing voor data workloads. Berekent node pools, resource quotas, pod density en cluster capaciteit.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Totaal aantal pods</label><input type="number" id="k8-pods" value="200" oninput="calcK8s()"></div>
<div class="calc-input"><label>CPU request per pod (cores)</label><input type="number" id="k8-cpu" value="1" step="0.5" oninput="calcK8s()"></div>
<div class="calc-input"><label>Memory request per pod (GB)</label><input type="number" id="k8-mem" value="4" oninput="calcK8s()"></div>
<div class="calc-input"><label>Node type</label><select id="k8-nodeType" onchange="calcK8s()"><option value="small" selected>Small (16 cores, 64GB)</option><option value="medium">Medium (32 cores, 128GB)</option><option value="large">Large (64 cores, 256GB)</option><option value="gpu">GPU (32 cores, 256GB + NVIDIA A100)</option></select></div>
<div class="calc-input"><label>Overcommit ratio</label><select id="k8-overcommit" onchange="calcK8s()"><option value="1">Geen (1:1, critical)</option><option value="1.5" selected>Gemiddeld (1.5x)</option><option value="2">Hoog (2x, burstable)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Totale CPU request</span><span class="r-val" id="k8-totalCpu">—</span></div>
<div class="r-row"><span class="r-label">Totaal geheugen request</span><span class="r-val" id="k8-totalMem">—</span></div>
<div class="r-row"><span class="r-label">Node capaciteit (pods)</span><span class="r-val" id="k8-nodeCap">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen nodes</span><span class="r-val accent" id="k8-nodes">—</span></div>
<div class="r-row"><span class="r-label">Gebruikte capaciteit</span><span class="r-val" id="k8-usage">—</span></div>
<div class="r-row"><span class="r-label">N+1 redundantie</span><span class="r-val green" id="k8-nodesHA">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Aanbevolen Cluster</div><div class="rh-val" id="k8-clusterRec">—</div></div>
<div class="r-recommendation" id="k8-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">Gebruik medium nodes (32c/128GB) voor data workloads. Reken 110 pods max per node. Reserveer 20% capaciteit voor cluster overhead (system daemons, DNS, monitoring). Overcommit 1.5x voor batch jobs.</div>
</div>
</div>
</div>
</div>

<!-- HADOOP -->
<div class="calc-panel" id="panel-hadoop" style="display:none">
<div class="desc-text">Hadoop HDFS en data lake sizing. Berekent storage, replication, block size, en cluster configuratie voor big data workloads.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Bruto data volume (TB)</label><input type="number" id="hd-volume" value="1000" oninput="calcHadoop()"></div>
<div class="calc-input"><label>Replicatie factor</label><select id="hd-replicas" onchange="calcHadoop()"><option value="1">1 (dev/test)</option><option value="2">2 (standard)</option><option value="3" selected>3 (enterprise)</option></select></div>
<div class="calc-input"><label>Block size</label><select id="hd-block" onchange="calcHadoop()"><option value="128">128 MB</option><option value="256" selected>256 MB</option><option value="512">512 MB</option></select></div>
<div class="calc-input"><label>Disk (TB per node)</label><select id="hd-disk" onchange="calcHadoop()"><option value="4">4 TB HDD</option><option value="8">8 TB HDD</option><option value="12">12 TB HDD</option><option value="16" selected>16 TB HDD</option><option value="30">30 TB SSD</option></select></div>
<div class="calc-input"><label>Compressie</label><select id="hd-compress" onchange="calcHadoop()"><option value="1">Geen</option><option value="0.5" selected>Snappy/LZO (0.5x)</option><option value="0.35">ZSTD (0.35x)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Effectieve opslag (na compressie)</span><span class="r-val" id="hd-effective">—</span></div>
<div class="r-row"><span class="r-label">Totaal met replicatie</span><span class="r-val orange" id="hd-totalRep">—</span></div>
<div class="r-row"><span class="r-label">Bruto capacity per node</span><span class="r-val" id="hd-perNode">—</span></div>
<div class="r-row"><span class="r-label">Aantal data nodes</span><span class="r-val accent" id="hd-nodes">—</span></div>
<div class="r-row"><span class="r-label">Aantal blokken in cluster</span><span class="r-val" id="hd-blocks">—</span></div>
<div class="r-row"><span class="r-label">MapReduce capacity</span><span class="r-val purple" id="hd-mr">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Aanbevolen Hadoop Cluster</div><div class="rh-val" id="hd-clusterRec">—</div></div>
<div class="r-recommendation" id="hd-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">HDFS replicatie 3x is enterprise standaard. Gebruik 256MB block size voor data lake workloads. Reken 70-80% disk utilization na OS overhead. Snappy compressie voor balance tussen ratio en speed. Namenode heeft 1GB RAM per 1M blokken.</div>
</div>
</div>
</div>
</div>

</div>
</div>

<script>
function fmt(v){if(v>=1e6)return (v/1e6).toFixed(1)+' PB';if(v>=1e3)return (v/1e3).toFixed(1)+' TB';return Math.round(v)+' GB'}
function fmtBytes(v){return fmt(v)}
function fmtNum(v){if(v>=1e6)return (v/1e6).toFixed(1)+'M';if(v>=1e3)return (v/1e3).toFixed(1)+'K';return Math.round(v).toString()}
function tbToGb(t){return t*1000}
function gbToTb(g){return g/1000}

function calcKafka(){
  var msgs=+document.getElementById('k-msgs').value||0
  var msgKB=+document.getElementById('k-msgSize').value||0
  var retention=+document.getElementById('k-retention').value||0
  var replicas=+document.getElementById('k-replicas').value||3
  var diskSpeed=+document.getElementById('k-diskSpeed').value||550
  var compress=+document.getElementById('k-compress').value||0.4
  var mbps=msgs*msgKB/1024
  var mbpsNet=mbps*compress
  var dailyGB=mbpsNet*86400/1024
  var totalGB=dailyGB*retention
  var totalRepGB=totalGB*replicas
  var partitions=Math.max(msgs/100000,3*replicas)
  var brokersPerf=Math.ceil(mbps/diskSpeed)
  var brokers=max(3,brokersPerf,Math.ceil(totalRepGB/5000))
  document.getElementById('k-throughput').textContent=mbps.toFixed(1)+' MB/s'
  document.getElementById('k-throughputNet').textContent=mbpsNet.toFixed(1)+' MB/s'
  document.getElementById('k-daily').textContent=dailyGB<1000?Math.round(dailyGB)+' GB':(dailyGB/1000).toFixed(2)+' TB'
  document.getElementById('k-total').textContent=fmt(totalGB)
  document.getElementById('k-totalRep').textContent=fmt(totalRepGB)
  document.getElementById('k-partitions').textContent=Math.ceil(partitions)
  document.getElementById('k-brokers').textContent=brokers
  var nodeRec=''
  if(brokers<=3)nodeRec=brokers+' nodes × 4TB NVMe'
  else if(brokers<=6)nodeRec=brokers+' nodes × 8TB SSD'
  else if(brokers<=10)nodeRec=brokers+' nodes × 16TB SSD'
  else nodeRec=brokers+' nodes × 32TB SSD'
  document.getElementById('k-clusterRec').textContent=nodeRec+' (total ~'+fmt(totalRepGB)+')'
  var recEl=document.getElementById('k-rec').querySelector('.rr-text')
  if(compress<0.3)recEl.textContent='ZSTD compressie geeft ~75% reductie. Overweeg tiered storage voor data >14 dagen oud. Gebruik JBOD configuratie (geen RAID) voor max throughput.'
  else recEl.textContent='Voor '+msgs.toLocaleString()+' msg/s met '+msgKB+'KB berichten: '+brokers+' brokers '+nodeRec+'. Partities: '+Math.ceil(partitions)+'. Monitor follower fetch latency en under-replicated partitions.'
}

function calcSpark(){
  var data=+document.getElementById('s-data').value||0
  var type=document.getElementById('s-type').value
  var time=+document.getElementById('s-time').value||30
  var nodeRam=+document.getElementById('s-ram').value||256
  var nodeCores=+document.getElementById('s-cores').value||32
  var dynamic=document.getElementById('s-dynamic').value==='1'
  var execOverhead=type==='ml'?8:4
  var coresPerExec=type==='stream'?2:5
  if(type==='ml')coresPerExec=4
  var execsPerNode=Math.floor((nodeRam-execOverhead)/(coresPerExec*4+execOverhead))||1
  var totalExecs=execsPerNode
  var totalRam=totalExecs*(coresPerExec*4+execOverhead)
  var totalVCores=totalExecs*coresPerExec
  var workers=Math.ceil(totalExecs/execsPerNode)
  if(dynamic)workers=Math.ceil(workers*1.3)
  document.getElementById('s-executors').textContent=totalExecs
  document.getElementById('s-coresPerExec').textContent=coresPerExec
  document.getElementById('s-memPerExec').textContent=coresPerExec*4+execOverhead+' GB'
  document.getElementById('s-totalRam').textContent=totalRam+' GB'
  document.getElementById('s-totalCores').textContent=totalVCores
  document.getElementById('s-workers').textContent=workers
  document.getElementById('s-clusterRec').textContent=workers+' nodes × '+nodeRam+'GB RAM / '+nodeCores+' cores'
  document.getElementById('s-rec').querySelector('.rr-text').textContent='Voor '+type+' workloads met '+data+'GB data: '+workers+' worker nodes. '+(dynamic?'Dynamic allocation actief — efficiënt voor fluctuerende loads.':'Static allocation — consistent maar minder flexibel.')+' Gebruik RDD persistance voor iterative ML workloads.'
}

function max(){return Math.max.apply(null,arguments)}

function calcMinio(){
  var capTB=+document.getElementById('m-capacity').value||0
  var driveTB=+document.getElementById('m-driveSize').value||22
  var ecStr=document.getElementById('m-ec').value
  var ecParts=ecStr.split(':')
  var ecData=+ecParts[0],ecParity=+ecParts[1]
  var ecFactor=1+ecParity/ecData
  var redundancy=document.getElementById('m-redundancy').value
  var compress=+document.getElementById('m-compress').value||0.6
  var grossTB=capTB*ecFactor
  var drives=Math.ceil(grossTB/driveTB)
  var nodes=Math.ceil(drives/2)
  var usableTB=grossTB/ecFactor
  var effectiveTB=usableTB/compress
  var minNodes=ecData+ecParity
  if(redundancy==='rack')nodes=Math.max(nodes,Math.ceil(minNodes/3)*3)
  if(redundancy==='region')nodes=Math.max(nodes,minNodes*2)
  document.getElementById('m-drives').textContent=drives
  document.getElementById('m-nodes').textContent=nodes
  document.getElementById('m-gross').textContent=grossTB.toFixed(1)+' TB'
  document.getElementById('m-ecFactor').textContent=ecFactor.toFixed(2)+'x'
  document.getElementById('m-usable').textContent=usableTB.toFixed(1)+' TB'
  document.getElementById('m-effective').textContent=effectiveTB.toFixed(1)+' TB'
  document.getElementById('m-minNodes').textContent=minNodes+' (EC:'+ecData+'+'+ecParity+')'
  document.getElementById('m-clusterRec').textContent=nodes+' nodes × '+Math.ceil(drives/nodes)+' drives × '+driveTB+'TB ('+Math.round(grossTB)+'TB gross)'
}

function calcHana(){
  var module=document.getElementById('h-module').value
  var users=+document.getElementById('h-users').value||0
  var dataGB=+document.getElementById('h-data').value||0
  var growth=+document.getElementById('h-growth').value||0
  var ha=document.getElementById('h-ha').value==='1'
  var dr=document.getElementById('h-dr').value==='1'
  var ratio=module==='bw'?0.25:module==='bpc'?0.15:module==='slt'?0.05:0.02
  var dataFP=Math.round(dataGB*ratio*100)/100
  var ram=dataFP*(1+growth/100)+users*0.25
  var overhead=ram-dataFP
  var cpu=Math.max(8,Math.round(ram/32))
  var storage=(dataGB+ram*2)*1.2
  var nodeType=ram<=256?'1x HPE ProLiant DL380 (256GB)':'2x HPE ProLiant DL380 (512GB)'
  if(ram>1024)nodeType='4x HPE ProLiant DL380 (1TB+) — Scale-out'
  if(ha)ram*=1.5
  document.getElementById('h-ram').textContent=Math.round(ram)+' GB'
  document.getElementById('h-dataFP').textContent=Math.round(dataFP)+' GB'
  document.getElementById('h-overhead').textContent=Math.round(overhead)+' GB'
  document.getElementById('h-cpu').textContent=cpu+' cores'
  document.getElementById('h-storage').textContent=Math.round(storage)+' GB'
  document.getElementById('h-nodeType').textContent=nodeType
  document.getElementById('h-clusterRec').textContent=Math.round(ram)+'GB RAM, '+cpu+' cores, '+(ha?'+ standby (HA) ':'')+(dr?'+ async replicatie (DR)':'')+' — totaal ~'+Math.round(storage/1000)+'TB opslag'
}

function calcWarehouse(){
  var vol=+document.getElementById('w-volume').value||0
  var ingest=+document.getElementById('w-ingest').value||0
  var queries=+document.getElementById('w-queries').value||20
  var complexity=document.getElementById('w-complexity').value
  var arch=document.getElementById('w-arch').value
  var compressRatio=5
  var compressed=vol/compressRatio
  var totalTB=compressed*1.5
  var complexityFactor=complexity==='simple'?0.5:complexity==='complex'?2:1
  var computeUnits=Math.ceil(queries*complexityFactor*0.5)
  var ram=computeUnits*32
  var vcores=computeUnits*8
  var nodes=Math.max(2,Math.ceil(computeUnits/4))
  document.getElementById('w-compressed').textContent=compressed.toFixed(1)+' TB'
  document.getElementById('w-total').textContent=totalTB.toFixed(1)+' TB'
  document.getElementById('w-compute').textContent=computeUnits
  document.getElementById('w-ram').textContent=ram+' GB'
  document.getElementById('w-vcores').textContent=vcores
  document.getElementById('w-nodes').textContent=nodes
  document.getElementById('w-clusterRec').textContent=nodes+' nodes, '+ram+'GB RAM, '+vcores+' vCores, '+arch+' — '+(arch==='lakehouse'?'Trino + Iceberg':'Snowflake')+' voor '+queries+' concurrent queries'
}

function calcVector(){
  var vecM=+document.getElementById('v-vectors').value||0
  var dims=+document.getElementById('v-dims').value||768
  var idx=document.getElementById('v-index').value
  var replicas=+document.getElementById('v-replicas').value||2
  var rawGB=vecM*dims*4/1e9
  var idxOverhead=idx==='flat'?rawGB*0.5:idx==='ivf'?rawGB*0.8:rawGB*1.3
  var totalRam=rawGB+idxOverhead
  var totalRep=totalRam*replicas
  var nodes=Math.ceil(totalRep/128)
  var nodeType=totalRep<=128?'64GB':totalRep<=256?'128GB':totalRep<=512?'256GB':'512GB+ cluster'
  document.getElementById('v-raw').textContent=rawGB.toFixed(1)+' GB'
  document.getElementById('v-indexOverhead').textContent=idxOverhead.toFixed(1)+' GB'
  document.getElementById('v-ram').textContent=totalRam.toFixed(1)+' GB'
  document.getElementById('v-total').textContent=totalRep.toFixed(1)+' GB'
  document.getElementById('v-nodes').textContent=nodes
  document.getElementById('v-nodeType').textContent=nodeType
  document.getElementById('v-clusterRec').textContent=nodes+' nodes × '+nodeType+' (HNSW, '+(vecM*replicas).toFixed(1)+'M vectors)'
}

function calcK8s(){
  var pods=+document.getElementById('k8-pods').value||0
  var cpuReq=+document.getElementById('k8-cpu').value||1
  var memReq=+document.getElementById('k8-mem').value||4
  var nodeSel=document.getElementById('k8-nodeType').value
  var overcommit=+document.getElementById('k8-overcommit').value||1.5
  var nodeSpecs={small:{cores:16,ram:64},medium:{cores:32,ram:128},large:{cores:64,ram:256},gpu:{cores:32,ram:256}}
  var ns=nodeSpecs[nodeSel]
  var totalCpu=Math.ceil(pods*cpuReq/overcommit)
  var totalMem=Math.ceil(pods*memReq/overcommit)
  var maxPodsPerNode=110
  var podCpuCap=Math.floor(ns.cores/cpuReq*overcommit)
  var podMemCap=Math.floor(ns.ram/memReq*overcommit)
  var nodeCap=Math.min(maxPodsPerNode,podCpuCap,podMemCap)
  var nodes=Math.ceil(pods/nodeCap)
  var usage=Math.round(pods/(nodes*nodeCap)*100)
  var nodesHA=nodes+1
  document.getElementById('k8-totalCpu').textContent=totalCpu+' cores ('+(pods*cpuReq)+' actual)'
  document.getElementById('k8-totalMem').textContent=totalMem+' GB ('+(pods*memReq)+' actual)'
  document.getElementById('k8-nodeCap').textContent=nodeCap+' pods'
  document.getElementById('k8-nodes').textContent=nodes
  document.getElementById('k8-usage').textContent=usage+'%'
  document.getElementById('k8-nodesHA').textContent=nodesHA+' (N+1)'
  document.getElementById('k8-clusterRec').textContent=nodes+'× '+nodeSel+' ('+ns.cores+'c/'+ns.ram+'GB) — '+(nodes*ns.ram)+'GB RAM, '+(nodes*ns.cores)+' cores — capacity: '+usage+'%'
}

function calcHadoop(){
  var vol=+document.getElementById('hd-volume').value||0
  var replicas=+document.getElementById('hd-replicas').value||3
  var block=+document.getElementById('hd-block').value||256
  var disk=+document.getElementById('hd-disk').value||16
  var compress=+document.getElementById('hd-compress').value||0.5
  var effectiveTB=vol*compress
  var totalRepTB=effectiveTB*replicas
  var perNodeTB=disk*0.85
  var nodes=Math.ceil(totalRepTB/perNodeTB)
  var blocks=Math.ceil(effectiveTB*1024*1024/block)
  var mrCap=nodes*Math.floor(disk*0.1)
  document.getElementById('hd-effective').textContent=effectiveTB.toFixed(1)+' TB'
  document.getElementById('hd-totalRep').textContent=totalRepTB.toFixed(1)+' TB'
  document.getElementById('hd-perNode').textContent=Math.round(perNodeTB*100)/100+' TB'
  document.getElementById('hd-nodes').textContent=nodes
  document.getElementById('hd-blocks').textContent=blocks.toLocaleString()
  document.getElementById('hd-mr').textContent=mrCap+' GB input slot'
  document.getElementById('hd-clusterRec').textContent=nodes+' nodes × '+disk+'TB ('+Math.round(nodes*disk*0.85)+'TB usable) — replicatie '+replicas+'x — '+block+'MB blocks'
}

function switchPlatform(p){
  document.querySelectorAll('.sb-item').forEach(function(b){b.classList.remove('active')})
  document.querySelectorAll('.calc-panel').forEach(function(p2){p2.style.display='none'})
  var btn=document.querySelector('.sb-item[data-platform="'+p+'"]')
  if(btn)btn.classList.add('active')
  var panel=document.getElementById('panel-'+p)
  if(panel)panel.style.display='block'
  document.getElementById('platformSelect').value=p
  var fns={kafka:calcKafka,spark:calcSpark,minio:calcMinio,'sap-hana':calcHana,warehouse:calcWarehouse,vector:calcVector,k8s:calcK8s,hadoop:calcHadoop}
  if(fns[p])setTimeout(fns[p],50)
}

document.querySelectorAll('.sb-item').forEach(function(btn){
  btn.addEventListener('click',function(){switchPlatform(this.dataset.platform)})
})

calcKafka()
</script>
<script src="/js/theme.js"></script><script>lucide.createIcons()</script></body>
</html>
