my-homelab-configs/docs/architecture-diagram.html

222 lines
13 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Homelab Infrastructure Architecture</title>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'JetBrains Mono', monospace; background: #020617; min-height: 100vh; padding: 2rem; color: white; }
.container { max-width: 1200px; margin: 0 auto; }
.header { margin-bottom: 2rem; }
.header-row { display: flex; align-items: center; gap: 1rem; margin-bottom: 0.5rem; }
.pulse-dot { width: 12px; height: 12px; background: #22d3ee; border-radius: 50%; animation: pulse 2s infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
h1 { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.025em; }
.subtitle { color: #94a3b8; font-size: 0.875rem; margin-left: 1.75rem; }
.diagram-container { background: rgba(15, 23, 42, 0.5); border-radius: 1rem; border: 1px solid #1e293b; padding: 1.5rem; overflow-x: auto; }
svg { width: 100%; min-width: 1000px; display: block; }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1rem; margin-top: 2rem; }
.card { background: rgba(15, 23, 42, 0.5); border-radius: 0.75rem; border: 1px solid #1e293b; padding: 1.25rem; }
.card-header { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem; }
.card-dot { width: 8px; height: 8px; border-radius: 50%; }
.card-dot.cyan { background: #22d3ee; }
.card-dot.emerald { background: #34d399; }
.card-dot.violet { background: #a78bfa; }
.card-dot.amber { background: #fbbf24; }
.card-dot.rose { background: #fb7185; }
.card h3 { font-size: 0.875rem; font-weight: 600; }
.card ul { list-style: none; color: #94a3b8; font-size: 0.75rem; }
.card li { margin-bottom: 0.375rem; }
.footer { text-align: center; margin-top: 1.5rem; color: #475569; font-size: 0.75rem; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<div class="header-row">
<div class="pulse-dot"></div>
<h1>Homelab Infrastructure Architecture</h1>
</div>
<p class="subtitle">Hybrid K8s + Docker Compose + OCI Edge Bridge</p>
</div>
<div class="diagram-container">
<svg viewBox="0 0 1000 680">
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" fill="#64748b" />
</marker>
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="#1e293b" stroke-width="0.5"/>
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)" />
<!-- =================================================================
EXTERNAL & EDGE
================================================================= -->
<!-- Users -->
<rect x="30" y="280" width="100" height="50" rx="6" fill="rgba(30, 41, 59, 0.5)" stroke="#94a3b8" stroke-width="1.5"/>
<text x="80" y="300" fill="white" font-size="11" font-weight="600" text-anchor="middle">Users</text>
<text x="80" y="316" fill="#94a3b8" font-size="9" text-anchor="middle">Public Internet</text>
<!-- OCI Boundary -->
<rect x="160" y="180" width="160" height="320" rx="12" fill="rgba(251, 191, 36, 0.05)" stroke="#fbbf24" stroke-width="1" stroke-dasharray="8,4"/>
<text x="172" y="198" fill="#fbbf24" font-size="10" font-weight="600">OCI Edge (Jump Box)</text>
<rect x="200" y="220" width="110" height="50" rx="6" fill="rgba(120, 53, 15, 0.3)" stroke="#fbbf24" stroke-width="1.5"/>
<text x="255" y="240" fill="white" font-size="11" font-weight="600" text-anchor="middle">Nginx</text>
<text x="255" y="256" fill="#94a3b8" font-size="9" text-anchor="middle">TLS / Gzip / H2</text>
<rect x="200" y="300" width="110" height="50" rx="6" fill="rgba(120, 53, 15, 0.3)" stroke="#fbbf24" stroke-width="1.5"/>
<text x="255" y="320" fill="white" font-size="11" font-weight="600" text-anchor="middle">HAProxy</text>
<text x="255" y="336" fill="#94a3b8" font-size="9" text-anchor="middle">L7 Routing</text>
<rect x="200" y="380" width="110" height="50" rx="6" fill="rgba(120, 53, 15, 0.3)" stroke="#fbbf24" stroke-width="1.5"/>
<text x="255" y="400" fill="white" font-size="11" font-weight="600" text-anchor="middle">Varnish/Squid</text>
<text x="255" y="416" fill="#94a3b8" font-size="9" text-anchor="middle">Edge Cache</text>
<!-- =================================================================
TRANSPORT
================================================================= -->
<line x1="130" y1="305" x2="198" y2="305" stroke="#22d3ee" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<text x="164" y="299" fill="#94a3b8" font-size="9" text-anchor="middle">HTTPS</text>
<line x1="255" y1="270" x2="255" y2="298" stroke="#fbbf24" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<line x1="255" y1="350" x2="255" y2="378" stroke="#fbbf24" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<!-- Tailscale Tunnel -->
<path d="M 310 365 L 400 365" stroke="#94a3b8" stroke-width="2" stroke-dasharray="5,5" marker-end="url(#arrowhead)"/>
<text x="355" y="358" fill="#94a3b8" font-size="9" text-anchor="middle">Tailscale Mesh</text>
<!-- =================================================================
HOMELAB LAN
================================================================= -->
<rect x="400" y="50" width="550" height="600" rx="12" fill="rgba(15, 23, 42, 0.5)" stroke="#34d399" stroke-width="1" stroke-dasharray="8,4"/>
<text x="412" y="68" fill="#34d399" font-size="10" font-weight="600">Homelab LAN (192.168.100.0/24)</text>
<!-- Debian Host (Host Services) -->
<rect x="450" y="100" width="200" height="220" rx="8" fill="transparent" stroke="#94a3b8" stroke-width="1" stroke-dasharray="4,4"/>
<text x="458" y="118" fill="#94a3b8" font-size="9">debian:control-plane</text>
<rect x="480" y="130" width="140" height="45" rx="6" fill="rgba(6, 78, 59, 0.4)" stroke="#34d399" stroke-width="1.5"/>
<text x="550" y="150" fill="white" font-size="11" font-weight="600" text-anchor="middle">Gitea</text>
<text x="550" y="165" fill="#94a3b8" font-size="9" text-anchor="middle">GitOps Source</text>
<rect x="480" y="185" width="140" height="45" rx="6" fill="rgba(6, 78, 59, 0.4)" stroke="#34d399" stroke-width="1.5"/>
<text x="550" y="205" fill="white" font-size="11" font-weight="600" text-anchor="middle">Heimdall</text>
<text x="550" y="220" fill="#94a3b8" font-size="9" text-anchor="middle">App Dashboard</text>
<rect x="480" y="240" width="140" height="45" rx="6" fill="rgba(6, 78, 59, 0.4)" stroke="#34d399" stroke-width="1.5"/>
<text x="550" y="260" fill="white" font-size="11" font-weight="600" text-anchor="middle">Ollama</text>
<text x="550" y="275" fill="#94a3b8" font-size="9" text-anchor="middle">Local LLM API</text>
<!-- K8s Cluster -->
<rect x="450" y="350" width="450" height="260" rx="8" fill="rgba(6, 78, 59, 0.05)" stroke="#34d399" stroke-width="1" stroke-dasharray="4,4"/>
<text x="458" y="368" fill="#34d399" font-size="9">Kubernetes Cluster</text>
<rect x="480" y="380" width="110" height="50" rx="6" fill="rgba(6, 78, 59, 0.4)" stroke="#34d399" stroke-width="1.5"/>
<text x="535" y="400" fill="white" font-size="11" font-weight="600" text-anchor="middle">Traefik</text>
<text x="535" y="416" fill="#94a3b8" font-size="9" text-anchor="middle">Ingress (MetalLB)</text>
<!-- App Layer -->
<rect x="620" y="380" width="130" height="80" rx="6" fill="rgba(8, 51, 68, 0.4)" stroke="#22d3ee" stroke-width="1.5"/>
<text x="685" y="400" fill="white" font-size="11" font-weight="600" text-anchor="middle">Web Apps</text>
<text x="685" y="420" fill="#94a3b8" font-size="9" text-anchor="middle">• Website (PHP)</text>
<text x="685" y="435" fill="#94a3b8" font-size="9" text-anchor="middle">• Demos Static</text>
<text x="685" y="450" fill="#94a3b8" font-size="9" text-anchor="middle">• n8n</text>
<!-- Platform Layer -->
<rect x="620" y="480" width="130" height="70" rx="6" fill="rgba(6, 78, 59, 0.4)" stroke="#34d399" stroke-width="1.5"/>
<text x="685" y="500" fill="white" font-size="11" font-weight="600" text-anchor="middle">Platform</text>
<text x="685" y="520" fill="#94a3b8" font-size="9" text-anchor="middle">• Argo CD</text>
<text x="685" y="535" fill="#94a3b8" font-size="9" text-anchor="middle">• Prometheus/Grafana</text>
<!-- Worker Nodes -->
<rect x="780" y="410" width="110" height="80" rx="6" fill="rgba(30, 41, 59, 0.5)" stroke="#94a3b8" stroke-width="1.5"/>
<text x="835" y="430" fill="white" font-size="11" font-weight="600" text-anchor="middle">Workers</text>
<text x="835" y="450" fill="#94a3b8" font-size="9" text-anchor="middle">• Pimox VMs</text>
<text x="835" y="465" fill="#94a3b8" font-size="9" text-anchor="middle">• Raspberry Pi</text>
<!-- Storage -->
<rect x="780" y="520" width="110" height="60" rx="6" fill="rgba(76, 29, 149, 0.4)" stroke="#a78bfa" stroke-width="1.5"/>
<text x="835" y="540" fill="white" font-size="11" font-weight="600" text-anchor="middle">Storage</text>
<text x="835" y="560" fill="#94a3b8" font-size="9" text-anchor="middle">OpenEBS Hostpath</text>
<!-- K8s Internal Flows -->
<line x1="590" y1="405" x2="618" y2="405" stroke="#22d3ee" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<line x1="590" y1="415" x2="618" y2="515" stroke="#34d399" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<line x1="750" y1="420" x2="778" y2="440" stroke="#94a3b8" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<line x1="750" y1="440" x2="778" y2="530" stroke="#a78bfa" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<!-- Edge to Homelab Flows -->
<line x1="320" y1="405" x2="478" y2="405" stroke="#22d3ee" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<text x="390" y="398" fill="#94a3b8" font-size="9" text-anchor="middle">App Path</text>
<line x1="320" y1="330" x2="478" y2="150" stroke="#34d399" stroke-width="1.5" stroke-dasharray="5,5" marker-end="url(#arrowhead)"/>
<text x="390" y="320" fill="#94a3b8" font-size="9" text-anchor="middle">GitOps/SSH</text>
<!-- App to AI Flow -->
<path d="M 685 380 L 685 320 L 620 320 L 620 260 L 622 260" fill="none" stroke="#fb7185" stroke-width="1.5" stroke-dasharray="4,4" marker-end="url(#arrowhead)"/>
<text x="640" y="310" fill="#fb7185" font-size="8">Ollama API</text>
<!-- Legend -->
<text x="720" y="70" fill="white" font-size="10" font-weight="600">Legend</text>
<rect x="720" y="82" width="16" height="10" rx="2" fill="rgba(8, 51, 68, 0.4)" stroke="#22d3ee" stroke-width="1"/>
<text x="742" y="90" fill="#94a3b8" font-size="8">Frontend/App</text>
<rect x="720" y="98" width="16" height="10" rx="2" fill="rgba(6, 78, 59, 0.4)" stroke="#34d399" stroke-width="1"/>
<text x="742" y="106" fill="#94a3b8" font-size="8">Backend/Platform</text>
<rect x="720" y="114" width="16" height="10" rx="2" fill="rgba(120, 53, 15, 0.3)" stroke="#fbbf24" stroke-width="1"/>
<text x="742" y="122" fill="#94a3b8" font-size="8">OCI Cloud</text>
<rect x="720" y="130" width="16" height="10" rx="2" fill="rgba(76, 29, 149, 0.4)" stroke="#a78bfa" stroke-width="1"/>
<text x="742" y="138" fill="#94a3b8" font-size="8">Storage/DB</text>
<rect x="720" y="146" width="16" height="10" rx="2" fill="rgba(136, 19, 55, 0.4)" stroke="#fb7185" stroke-width="1"/>
<text x="742" y="154" fill="#94a3b8" font-size="8">AI/Security</text>
</svg>
</div>
<div class="cards">
<div class="card">
<div class="card-header">
<div class="card-dot amber"></div>
<h3>Edge Gateway</h3>
</div>
<ul>
<li>• TLS termination at OCI Edge</li>
<li>• Varnish cache for static HTML</li>
<li>• Tailscale tunnel to Homelab LAN</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<div class="card-dot emerald"></div>
<h3>K8s Core</h3>
</div>
<ul>
<li>• Traefik L7 Ingress via MetalLB</li>
<li>• Argo CD GitOps reconciliation</li>
<li>• Kyverno supply-chain enforcement</li>
</ul>
</div>
<div class="card">
<div class="card-header">
<div class="card-dot rose"></div>
<h3>AI & Data</h3>
</div>
<ul>
<li>• Ollama local LLM on Debian host</li>
<li>• Redis translation cache (Website)</li>
<li>• OpenEBS local PV retention</li>
</ul>
</div>
</div>
<p class="footer">
Homelab Infrastructure • v1.0.0 • Generated by Hermes Agent
</p>
</div>
</body>
</html>