RYP / src /components /DenormalizationDiagram.tsx
Soumya79's picture
Upload 1361 files
f91a684 verified
import { motion } from 'motion/react';
export default function DenormalizationDiagram() {
return (
<motion.div
initial={{ opacity: 0, y: 24, scale: 0.97 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
transition={{ duration: 0.7, ease: [0.25, 0.1, 0.25, 1] as const, delay: 0.2 }}
className="mt-10 mb-4"
>
<div className="text-center mb-6">
<span className="text-lg font-bold uppercase tracking-widest text-indigo-400" style={{ filter: 'drop-shadow(0 0 10px rgba(99,102,241,0.5))' }}>
DENORMALIZATION
</span>
<p className="text-sm text-slate-400 mt-2">Deliberate act of adding redundant data to speed up reads and simplify queries</p>
</div>
<svg
viewBox="0 0 900 580"
className="w-full max-w-6xl mx-auto"
style={{ filter: 'drop-shadow(0 0 30px rgba(99,102,241,0.1))' }}
>
<defs>
<marker id="denormArrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
<polygon points="0 0,8 3,0 6" fill="#3b82f6" />
</marker>
<linearGradient id="headerGrad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stopColor="rgba(59,130,246,0.2)" />
<stop offset="100%" stopColor="rgba(59,130,246,0.05)" />
</linearGradient>
<linearGradient id="greenBoxGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stopColor="rgba(34,197,94,0.12)" />
<stop offset="100%" stopColor="rgba(34,197,94,0.04)" />
</linearGradient>
<linearGradient id="redBoxGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stopColor="rgba(239,68,68,0.12)" />
<stop offset="100%" stopColor="rgba(239,68,68,0.04)" />
</linearGradient>
</defs>
{/* === HEADER BOX === */}
<g transform="translate(20, 10)">
<rect x="0" y="0" width="860" height="55" rx="12" fill="url(#headerGrad)" stroke="rgba(59,130,246,0.4)" strokeWidth="2" />
{/* Database Icon */}
<rect x="15" y="10" width="35" height="35" rx="6" fill="rgba(59,130,246,0.2)" stroke="#3b82f6" strokeWidth="2" />
<line x1="15" y1="20" x2="50" y2="20" stroke="#3b82f6" strokeWidth="2" />
<line x1="15" y1="30" x2="50" y2="30" stroke="#3b82f6" strokeWidth="2" />
<line x1="15" y1="40" x2="50" y2="40" stroke="#3b82f6" strokeWidth="2" />
{/* Text */}
<text x="65" y="22" fill="#60a5fa" fontSize="9" fontFamily="'Inter',sans-serif">Denormalization is the deliberate act of adding redundant data to a previously normalized schema</text>
<text x="65" y="35" fill="#60a5fa" fontSize="9" fontFamily="'Inter',sans-serif">to speed up reads and simplify queries.</text>
<text x="65" y="48" fill="#93c5fd" fontSize="8" fontWeight="600" fontFamily="'Inter',sans-serif">It's a targeted performance optimization, not an excuse to skip good modelling.</text>
</g>
{/* === 1) NORMALIZED (Left) === */}
<g transform="translate(20, 80)">
<rect x="0" y="0" width="380" height="320" rx="12" fill="rgba(59,130,246,0.05)" stroke="rgba(59,130,246,0.3)" strokeWidth="1.5" />
{/* Title */}
<text x="20" y="25" fill="#3b82f6" fontSize="11" fontWeight="800" fontFamily="'Inter',sans-serif">1) NORMALIZED (SOURCE OF TRUTH)</text>
{/* Customers Icon */}
<g transform="translate(20, 40)">
<circle cx="10" cy="8" r="5" fill="rgba(59,130,246,0.3)" stroke="#3b82f6" strokeWidth="1.5" />
<ellipse cx="10" cy="20" rx="8" ry="5" fill="none" stroke="#3b82f6" strokeWidth="1.5" />
<circle cx="28" cy="8" r="5" fill="rgba(59,130,246,0.3)" stroke="#3b82f6" strokeWidth="1.5" />
<ellipse cx="28" cy="20" rx="8" ry="5" fill="none" stroke="#3b82f6" strokeWidth="1.5" />
</g>
{/* Customers Table */}
<text x="60" y="55" fill="#60a5fa" fontSize="9" fontWeight="700" fontFamily="'Inter',sans-serif">customers</text>
<rect x="60" y="60" width="300" height="70" rx="4" fill="rgba(15,23,42,0.4)" stroke="rgba(59,130,246,0.3)" strokeWidth="1" />
{/* Header */}
<rect x="60" y="60" width="70" height="20" fill="rgba(59,130,246,0.2)" stroke="rgba(59,130,246,0.3)" strokeWidth="1" />
<text x="95" y="73" textAnchor="middle" fill="#93c5fd" fontSize="7" fontFamily="'Inter',sans-serif">customer_id</text>
<text x="95" y="80" textAnchor="middle" fill="#3b82f6" fontSize="6" fontFamily="'Inter',sans-serif">(PK)</text>
<rect x="130" y="60" width="130" height="20" fill="rgba(59,130,246,0.2)" stroke="rgba(59,130,246,0.3)" strokeWidth="1" />
<text x="195" y="73" textAnchor="middle" fill="#93c5fd" fontSize="7" fontFamily="'Inter',sans-serif">name</text>
<text x="195" y="80" textAnchor="middle" fill="#ef4444" fontSize="6" fontFamily="'Inter',sans-serif">(NOT NULL)</text>
<rect x="260" y="60" width="100" height="20" fill="rgba(59,130,246,0.2)" stroke="rgba(59,130,246,0.3)" strokeWidth="1" />
<text x="310" y="73" textAnchor="middle" fill="#93c5fd" fontSize="7" fontFamily="'Inter',sans-serif">tier</text>
<text x="310" y="80" textAnchor="middle" fill="#ef4444" fontSize="6" fontFamily="'Inter',sans-serif">(PK)</text>
{/* Data */}
<text x="95" y="98" textAnchor="middle" fill="#e2e8f0" fontSize="8" fontFamily="'Inter',sans-serif">1</text>
<text x="195" y="98" textAnchor="middle" fill="#e2e8f0" fontSize="8" fontFamily="'Inter',sans-serif">Alice</text>
<text x="310" y="98" textAnchor="middle" fill="#e2e8f0" fontSize="8" fontFamily="'Inter',sans-serif">Gold</text>
<text x="95" y="113" textAnchor="middle" fill="#e2e8f0" fontSize="8" fontFamily="'Inter',sans-serif">2</text>
<text x="195" y="113" textAnchor="middle" fill="#e2e8f0" fontSize="8" fontFamily="'Inter',sans-serif">Bob</text>
<text x="310" y="113" textAnchor="middle" fill="#e2e8f0" fontSize="8" fontFamily="'Inter',sans-serif">Silver</text>
<text x="95" y="128" textAnchor="middle" fill="#e2e8f0" fontSize="8" fontFamily="'Inter',sans-serif">3</text>
<text x="195" y="128" textAnchor="middle" fill="#e2e8f0" fontSize="8" fontFamily="'Inter',sans-serif">Carol</text>
<text x="310" y="128" textAnchor="middle" fill="#e2e8f0" fontSize="8" fontFamily="'Inter',sans-serif">Bronze</text>
{/* Orders Icon */}
<g transform="translate(20, 145)">
<rect x="0" y="0" width="35" height="25" rx="3" fill="none" stroke="#3b82f6" strokeWidth="1.5" />
<line x1="0" y1="8" x2="35" y2="8" stroke="#3b82f6" strokeWidth="1.5" />
<line x1="0" y1="16" x2="35" y2="16" stroke="#3b82f6" strokeWidth="1.5" />
<circle cx="28" cy="22" r="6" fill="none" stroke="#3b82f6" strokeWidth="1.5" />
<line x1="25" y1="22" x2="31" y2="22" stroke="#3b82f6" strokeWidth="1" />
<line x1="28" y1="19" x2="28" y2="25" stroke="#3b82f6" strokeWidth="1" />
</g>
{/* Orders Table */}
<text x="60" y="160" fill="#60a5fa" fontSize="9" fontWeight="700" fontFamily="'Inter',sans-serif">orders</text>
<rect x="60" y="165" width="300" height="85" rx="4" fill="rgba(15,23,42,0.4)" stroke="rgba(59,130,246,0.3)" strokeWidth="1" />
{/* Header */}
<rect x="60" y="165" width="60" height="20" fill="rgba(59,130,246,0.2)" stroke="rgba(59,130,246,0.3)" strokeWidth="1" />
<text x="90" y="178" textAnchor="middle" fill="#93c5fd" fontSize="7" fontFamily="'Inter',sans-serif">order_id</text>
<text x="90" y="185" textAnchor="middle" fill="#3b82f6" fontSize="6" fontFamily="'Inter',sans-serif">(PK)</text>
<rect x="120" y="165" width="70" height="20" fill="rgba(59,130,246,0.2)" stroke="rgba(59,130,246,0.3)" strokeWidth="1" />
<text x="155" y="178" textAnchor="middle" fill="#93c5fd" fontSize="7" fontFamily="'Inter',sans-serif">customer_id</text>
<text x="155" y="185" textAnchor="middle" fill="#3b82f6" fontSize="6" fontFamily="'Inter',sans-serif">(FK)</text>
<rect x="190" y="165" width="85" height="20" fill="rgba(59,130,246,0.2)" stroke="rgba(59,130,246,0.3)" strokeWidth="1" />
<text x="232" y="178" textAnchor="middle" fill="#93c5fd" fontSize="7" fontFamily="'Inter',sans-serif">order_total</text>
<text x="232" y="185" textAnchor="middle" fill="#64748b" fontSize="6" fontFamily="'Inter',sans-serif">(NUMERIC(12,2))</text>
<rect x="275" y="165" width="85" height="20" fill="rgba(59,130,246,0.2)" stroke="rgba(59,130,246,0.3)" strokeWidth="1" />
<text x="317" y="178" textAnchor="middle" fill="#93c5fd" fontSize="7" fontFamily="'Inter',sans-serif">created_at</text>
{/* Data */}
<text x="90" y="203" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">101</text>
<text x="155" y="203" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">1</text>
<text x="232" y="203" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">120.00</text>
<text x="317" y="203" textAnchor="middle" fill="#e2e8f0" fontSize="6" fontFamily="'Inter',sans-serif">2025-05-01 10:15:00</text>
<text x="90" y="218" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">102</text>
<text x="155" y="218" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">2</text>
<text x="232" y="218" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">85.50</text>
<text x="317" y="218" textAnchor="middle" fill="#e2e8f0" fontSize="6" fontFamily="'Inter',sans-serif">2025-05-01 11:20:00</text>
<text x="90" y="233" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">103</text>
<text x="155" y="233" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">1</text>
<text x="232" y="233" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">230.00</text>
<text x="317" y="233" textAnchor="middle" fill="#e2e8f0" fontSize="6" fontFamily="'Inter',sans-serif">2025-05-02 09:30:00</text>
<text x="90" y="248" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">104</text>
<text x="155" y="248" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">3</text>
<text x="232" y="248" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">75.00</text>
<text x="317" y="248" textAnchor="middle" fill="#e2e8f0" fontSize="6" fontFamily="'Inter',sans-serif">2025-05-02 12:45:00</text>
</g>
{/* Arrow between sections */}
<line x1="410" y1="240" x2="430" y2="240" stroke="#3b82f6" strokeWidth="2" markerEnd="url(#denormArrow)" />
{/* === 2) TYPICAL REPORT (Bottom Left) === */}
<g transform="translate(20, 410)">
<rect x="0" y="0" width="380" height="70" rx="12" fill="rgba(34,197,94,0.08)" stroke="rgba(34,197,94,0.3)" strokeWidth="1.5" />
<text x="15" y="20" fill="#4ade80" fontSize="10" fontWeight="800" fontFamily="'Inter',sans-serif">2) TYPICAL REPORT NEEDS A JOIN</text>
<text x="15" y="38" fill="#86efac" fontSize="7" fontFamily="'monospace',sans-serif">SELECT c.name, c.tier, SUM(o.order_total) AS revenue</text>
<text x="15" y="50" fill="#86efac" fontSize="7" fontFamily="'monospace',sans-serif">FROM orders o</text>
<text x="15" y="62" fill="#86efac" fontSize="7" fontFamily="'monospace',sans-serif">JOIN customers c ON c.customer_id = o.customer_id GROUP BY c.name, c.tier;</text>
</g>
{/* === 3) DENORMALIZED (Right) === */}
<g transform="translate(440, 80)">
<rect x="0" y="0" width="440" height="320" rx="12" fill="rgba(34,197,94,0.05)" stroke="rgba(34,197,94,0.3)" strokeWidth="1.5" />
{/* Title */}
<text x="15" y="25" fill="#22c55e" fontSize="11" fontWeight="800" fontFamily="'Inter',sans-serif">3) DENORMALIZED (FOR READ PERFORMANCE)</text>
{/* Subtitle */}
<text x="15" y="42" fill="#4ade80" fontSize="8" fontFamily="'Inter',sans-serif">orders_enriched (with redundant customer data)</text>
{/* Enriched Table */}
<rect x="15" y="50" width="410" height="125" rx="4" fill="rgba(15,23,42,0.4)" stroke="rgba(34,197,94,0.3)" strokeWidth="1" />
{/* Header */}
<rect x="15" y="50" width="50" height="25" fill="rgba(34,197,94,0.2)" stroke="rgba(34,197,94,0.3)" strokeWidth="1" />
<text x="40" y="63" textAnchor="middle" fill="#86efac" fontSize="6" fontFamily="'Inter',sans-serif">order_id</text>
<text x="40" y="72" textAnchor="middle" fill="#22c55e" fontSize="5" fontFamily="'Inter',sans-serif">(PK)</text>
<rect x="65" y="50" width="60" height="25" fill="rgba(34,197,94,0.2)" stroke="rgba(34,197,94,0.3)" strokeWidth="1" />
<text x="95" y="67" textAnchor="middle" fill="#86efac" fontSize="6" fontFamily="'Inter',sans-serif">customer_id</text>
<text x="95" y="74" textAnchor="middle" fill="#3b82f6" fontSize="5" fontFamily="'Inter',sans-serif">(FK)</text>
<rect x="125" y="50" width="90" height="25" fill="rgba(245,158,11,0.15)" stroke="#f59e0b" strokeWidth="1" />
<text x="170" y="63" textAnchor="middle" fill="#fbbf24" fontSize="6" fontFamily="'Inter',sans-serif">customer_name</text>
<text x="170" y="72" textAnchor="middle" fill="#f59e0b" fontSize="5" fontFamily="'Inter',sans-serif">(DENORMALIZED)</text>
<rect x="215" y="50" width="70" height="25" fill="rgba(245,158,11,0.15)" stroke="#f59e0b" strokeWidth="1" />
<text x="250" y="63" textAnchor="middle" fill="#fbbf24" fontSize="6" fontFamily="'Inter',sans-serif">customer_tier</text>
<text x="250" y="72" textAnchor="middle" fill="#f59e0b" fontSize="5" fontFamily="'Inter',sans-serif">(DENORMALIZED)</text>
<rect x="285" y="50" width="70" height="25" fill="rgba(34,197,94,0.2)" stroke="rgba(34,197,94,0.3)" strokeWidth="1" />
<text x="320" y="63" textAnchor="middle" fill="#86efac" fontSize="6" fontFamily="'Inter',sans-serif">order_total</text>
<text x="320" y="72" textAnchor="middle" fill="#64748b" fontSize="5" fontFamily="'Inter',sans-serif">(NUMERIC(12,2))</text>
<rect x="355" y="50" width="70" height="25" fill="rgba(34,197,94,0.2)" stroke="rgba(34,197,94,0.3)" strokeWidth="1" />
<text x="390" y="67" textAnchor="middle" fill="#86efac" fontSize="6" fontFamily="'Inter',sans-serif">created_at</text>
{/* Data */}
<text x="40" y="93" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">101</text>
<text x="95" y="93" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">1</text>
<text x="170" y="93" textAnchor="middle" fill="#fbbf24" fontSize="7" fontFamily="'Inter',sans-serif">Alice</text>
<text x="250" y="93" textAnchor="middle" fill="#fbbf24" fontSize="7" fontFamily="'Inter',sans-serif">Gold</text>
<text x="320" y="93" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">120.00</text>
<text x="390" y="93" textAnchor="middle" fill="#e2e8f0" fontSize="6" fontFamily="'Inter',sans-serif">2025-05-01 10:15:00</text>
<text x="40" y="108" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">102</text>
<text x="95" y="108" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">2</text>
<text x="170" y="108" textAnchor="middle" fill="#fbbf24" fontSize="7" fontFamily="'Inter',sans-serif">Bob</text>
<text x="250" y="108" textAnchor="middle" fill="#fbbf24" fontSize="7" fontFamily="'Inter',sans-serif">Silver</text>
<text x="320" y="108" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">85.50</text>
<text x="390" y="108" textAnchor="middle" fill="#e2e8f0" fontSize="6" fontFamily="'Inter',sans-serif">2025-05-01 11:20:00</text>
<text x="40" y="123" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">103</text>
<text x="95" y="123" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">1</text>
<text x="170" y="123" textAnchor="middle" fill="#fbbf24" fontSize="7" fontFamily="'Inter',sans-serif">Alice</text>
<text x="250" y="123" textAnchor="middle" fill="#fbbf24" fontSize="7" fontFamily="'Inter',sans-serif">Gold</text>
<text x="320" y="123" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">230.00</text>
<text x="390" y="123" textAnchor="middle" fill="#e2e8f0" fontSize="6" fontFamily="'Inter',sans-serif">2025-05-02 09:30:00</text>
<text x="40" y="138" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">104</text>
<text x="95" y="138" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">3</text>
<text x="170" y="138" textAnchor="middle" fill="#fbbf24" fontSize="7" fontFamily="'Inter',sans-serif">Carol</text>
<text x="250" y="138" textAnchor="middle" fill="#fbbf24" fontSize="7" fontFamily="'Inter',sans-serif">Bronze</text>
<text x="320" y="138" textAnchor="middle" fill="#e2e8f0" fontSize="7" fontFamily="'Inter',sans-serif">75.00</text>
<text x="390" y="138" textAnchor="middle" fill="#e2e8f0" fontSize="6" fontFamily="'Inter',sans-serif">2025-05-02 12:45:00</text>
{/* Success message */}
<rect x="15" y="185" width="410" height="55" rx="6" fill="rgba(34,197,94,0.1)" stroke="#22c55e" strokeWidth="1" />
<text x="30" y="200" fill="#4ade80" fontSize="9"></text>
<text x="50" y="202" fill="#4ade80" fontSize="8" fontWeight="700" fontFamily="'Inter',sans-serif">Now the same report is simpler and faster (no join needed):</text>
<text x="50" y="218" fill="#86efac" fontSize="7" fontFamily="'monospace',sans-serif">SELECT customer_name, customer_tier, SUM(order_total) AS revenue</text>
<text x="50" y="230" fill="#86efac" fontSize="7" fontFamily="'monospace',sans-serif">FROM orders_enriched</text>
<text x="50" y="242" fill="#86efac" fontSize="7" fontFamily="'monospace',sans-serif">GROUP BY customer_name, customer_tier;</text>
{/* SQL Source of Truth */}
<text x="15" y="260" fill="#60a5fa" fontSize="8" fontWeight="700" fontFamily="'Inter',sans-serif">SQL: SOURCE OF TRUTH (NORMALIZED)</text>
<rect x="15" y="268" width="200" height="45" rx="4" fill="rgba(15,23,42,0.4)" stroke="rgba(59,130,246,0.3)" strokeWidth="1" />
<text x="25" y="280" fill="#60a5fa" fontSize="6" fontFamily="'monospace',sans-serif">-- Source of truth</text>
<text x="25" y="290" fill="#93c5fd" fontSize="6" fontFamily="'monospace',sans-serif">CREATE TABLE customers (</text>
<text x="35" y="300" fill="#fbbf24" fontSize="6" fontFamily="'monospace',sans-serif">customer_id BIGINT PRIMARY KEY,</text>
<text x="35" y="308" fill="#fbbf24" fontSize="6" fontFamily="'monospace',sans-serif">name TEXT NOT NULL,</text>
</g>
{/* === PROS (Bottom Left) === */}
<g transform="translate(20, 490)">
<rect x="0" y="0" width="260" height="80" rx="12" fill="url(#greenBoxGrad)" stroke="rgba(34,197,94,0.4)" strokeWidth="2" />
<rect x="0" y="0" width="260" height="22" rx="12" fill="#22c55e" />
<rect x="0" y="12" width="260" height="68" rx="0" fill="rgba(34,197,94,0.05)" />
<text x="130" y="15" textAnchor="middle" fill="white" fontSize="9" fontWeight="800" fontFamily="'Inter',sans-serif">PROS: WHAT YOU GAIN</text>
{/* Rocket Icon */}
<path d="M15 35 L20 30 L25 35 L22 35 L22 48 L18 48 L18 35 Z" fill="none" stroke="#4ade80" strokeWidth="1.5" />
<text x="35" y="40" fill="#4ade80" fontSize="8" fontWeight="700" fontFamily="'Inter',sans-serif">Faster reads</text>
<text x="35" y="52" fill="#86efac" fontSize="7" fontFamily="'Inter',sans-serif">sub-p99 latencies</text>
{/* Search Icon */}
<circle cx="20" cy="62" r="5" fill="none" stroke="#4ade80" strokeWidth="1.5" />
<line x1="24" y1="66" x2="28" y2="70" stroke="#4ade80" strokeWidth="1.5" strokeLinecap="round" />
<text x="35" y="67" fill="#4ade80" fontSize="8" fontWeight="700" fontFamily="'Inter',sans-serif">Simpler queries</text>
<text x="35" y="79" fill="#86efac" fontSize="7" fontFamily="'Inter',sans-serif">fewer joins/aggregations</text>
</g>
{/* === CONS (Bottom Center) === */}
<g transform="translate(300, 490)">
<rect x="0" y="0" width="280" height="80" rx="12" fill="url(#redBoxGrad)" stroke="rgba(239,68,68,0.4)" strokeWidth="2" />
<rect x="0" y="0" width="280" height="22" rx="12" fill="#ef4444" />
<rect x="0" y="12" width="280" height="68" rx="0" fill="rgba(239,68,68,0.05)" />
<text x="140" y="15" textAnchor="middle" fill="white" fontSize="9" fontWeight="800" fontFamily="'Inter',sans-serif">CONS: WHAT IT COSTS</text>
{/* Edit Icon */}
<path d="M15 35 L22 28 L25 31 L18 38 Z" fill="none" stroke="#f87171" strokeWidth="1.5" />
<line x1="12" y1="40" x2="18" y2="38" stroke="#f87171" strokeWidth="1.5" />
<text x="35" y="40" fill="#f87171" fontSize="8" fontWeight="700" fontFamily="'Inter',sans-serif">Write amplification</text>
<text x="35" y="52" fill="#fca5a5" fontSize="7" fontFamily="'Inter',sans-serif">extra updates/inserts</text>
{/* Warning Icon */}
<path d="M20 60 L25 70 L15 70 Z" fill="none" stroke="#f87171" strokeWidth="1.5" />
<text x="20" y="68" textAnchor="middle" fill="#f87171" fontSize="8">!</text>
<text x="35" y="67" fill="#f87171" fontSize="8" fontWeight="700" fontFamily="'Inter',sans-serif">Consistency risk</text>
<text x="35" y="79" fill="#fca5a5" fontSize="7" fontFamily="'Inter',sans-serif">stale/drifting data</text>
</g>
{/* === OPERATIONAL (Bottom Right) === */}
<g transform="translate(600, 490)">
<rect x="0" y="0" width="280" height="80" rx="12" fill="rgba(245,158,11,0.08)" stroke="rgba(245,158,11,0.4)" strokeWidth="2" />
{/* Gear Icon */}
<circle cx="20" cy="25" r="10" fill="none" stroke="#fbbf24" strokeWidth="1.5" />
<circle cx="20" cy="25" r="4" fill="none" stroke="#fbbf24" strokeWidth="1.5" />
<line x1="20" y1="10" x2="20" y2="14" stroke="#fbbf24" strokeWidth="1.5" />
<line x1="20" y1="36" x2="20" y2="40" stroke="#fbbf24" strokeWidth="1.5" />
<line x1="5" y1="25" x2="9" y2="25" stroke="#fbbf24" strokeWidth="1.5" />
<line x1="31" y1="25" x2="35" y2="25" stroke="#fbbf24" strokeWidth="1.5" />
<text x="40" y="28" fill="#fbbf24" fontSize="8" fontWeight="700" fontFamily="'Inter',sans-serif">Operational overhead</text>
<text x="40" y="40" fill="#fcd34d" fontSize="7" fontFamily="'Inter',sans-serif">(refreshes, backfills, monitoring)</text>
{/* Fan-out Icon */}
<path d="M15 58 L20 65 L25 58" fill="none" stroke="#fbbf24" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" />
<line x1="20" y1="52" x2="20" y2="58" stroke="#fbbf24" strokeWidth="1.5" />
<line x1="12" y1="55" x2="16" y2="58" stroke="#fbbf24" strokeWidth="1.5" />
<line x1="28" y1="55" x2="24" y2="58" stroke="#fbbf24" strokeWidth="1.5" />
<text x="35" y="62" fill="#fbbf24" fontSize="8" fontWeight="700" fontFamily="'Inter',sans-serif">Change fan-out</text>
<text x="35" y="74" fill="#fcd34d" fontSize="7" fontFamily="'Inter',sans-serif">schema/logic updates must be mirrored</text>
</g>
{/* === EXAMPLE Badge === */}
<rect x="180" y="75" width="60" height="18" rx="9" fill="#3b82f6" />
<text x="210" y="87" textAnchor="middle" fill="white" fontSize="8" fontWeight="700" fontFamily="'Inter',sans-serif">EXAMPLE</text>
</svg>
</motion.div>
);
}