安装方式
命令行安装
在项目根目录执行以下命令,完成 Skill 安装。
npx bzskills add BrainBlend-AI/tesseron --skill tesseron-diagram I'll create a complete set of professional technical diagrams in the Tesseron visual language, with a dark slate base, amber accents, dotted-grid backgrounds, gradient cards, Lucide-style icons, Gaussian-blur glow, and Inter + JetBrains Mono typography. ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Tesseron Docs – Technical Diagrams</title> <!-- Google Fonts: Inter + JetBrains Mono --> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" /> <style> /* ── Reset & base ── */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } body { background: #12141f; font-family: 'Inter', sans-serif; color: #e8eaf0; padding: 2.5rem 1.5rem; display: flex; flex-direction: column; align-items: center; } .container { max-width: 1400px; width: 100%; } /* ── Section headers ── */ .section-title { font-size: 1.75rem; font-weight: 600; letter-spacing: -0.02em; color: #f5a623; margin: 2.5rem 0 0.5rem 0; display: flex; align-items: center; gap: 0.75rem; } .section-title::before { content: ''; display: inline-block; width: 4px; height: 28px; background: linear-gradient(180deg, #f5a623, #d48c1a); border-radius: 2px; } .section-sub { font-size: 0.95rem; color: #8892a8; margin-bottom: 1.75rem; font-weight: 400; padding-left: 1rem; border-left: 2px solid #2a2d3e; } /* ── Diagram card wrapper ── */ .diagram-card { background: #1a1d2e; border-radius: 18px; padding: 2rem 2rem 1.8rem 2rem; margin-bottom: 2.8rem; border: 1px solid #2a2d3e; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); overflow: hidden; position: relative; } .diagram-card::before { content: ''; position: absolute; inset: 0; border-radius: 18px; padding: 1px; background: linear-gradient(135deg, rgba(245, 166, 35, 0.12), transparent 50%); -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask-composite: exclude; pointer-events: none; } .diagram-card .diagram-label { font-family: 'JetBrains Mono', monospace; font-size: 0.75rem; font-weight: 500; color: #6b728c; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 1.25rem; display: flex; align-items: center; gap: 0.5rem; } .diagram-card .diagram-label span { color: #f5a623; } /* ── SVG styling ── */ .diagram-svg { width: 100%; height: auto; display: block; border-radius: 10px; background: #161926; box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.3); } /* ── Responsive ── */ @media (max-width: 800px) { body { padding: 1.25rem 0.75rem; } .diagram-card { padding: 1rem 0.75rem 0.75rem 0.75rem; } .section-title { font-size: 1.3rem; } } /* ── Tiny footer ── */ .docs-footer { text-align: center; font-size: 0.7rem; color: #3d4156; margin-top: 0.5rem; font-family: 'JetBrains Mono', monospace; letter-spacing: 0.04em; } .docs-footer span { color: #f5a623; } </style> </head> <body> <div class="container"> <!-- ===== INTRO ===== --> <div style="margin-bottom:2rem;"> <div style="display:flex;align-items:center;gap:0.75rem;margin-bottom:0.25rem;"> <span style="font-size:1.6rem;font-weight:700;color:#f5a623;">◆</span> <h1 style="font-weight:600;font-size:1.9rem;letter-spacing:-0.03em;color:#eceef5;"> Tesseron <span style="color:#f5a623;">Diagrams</span> </h1> </div> <p style="color:#6b728c;font-size:0.95rem;padding-left:2.6rem;font-family:'JetBrains Mono',monospace;"> dark slate · single amber accent · dotted grid · gradient cards · glow </p> </div> <!-- ========================================================== --> <!-- 1. ARCHITECTURE DIAGRAM --> <!-- ========================================================== --> <h2 class="section-title">Architecture</h2> <p class="section-sub">System-level component view with layered services and data flow</p> <div class="diagram-card"> <div class="diagram-label"><span>◆</span> ARCHITECTURE · system.context</div> <svg class="diagram-svg" viewBox="0 0 1100 520" xmlns="http://www.w3.org/2000/svg" style="background:#161926; border-radius:10px;"> <!-- ── DEFS ── --> <defs> <!-- Dotted grid pattern --> <pattern id="grid-dots" patternUnits="userSpaceOnUse" width="24" height="24"> <circle cx="12" cy="12" r="1.1" fill="#2a2d3e" opacity="0.55" /> </pattern> <!-- Amber glow filter --> <filter id="amber-glow" x="-40%" y="-40%" width="180%" height="180%"> <feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur1" /> <feColorMatrix in="blur1" type="matrix" values="0 0 0 0 0.96 0 0 0 0 0.65 0 0 0 0 0.14 0 0 0 0.45 0" result="colored" /> <feMerge> <feMergeNode in="colored" /> <feMergeNode in="SourceGraphic" /> </feMerge> </filter> <!-- Subtle card gradients --> <linearGradient id="grad-client" x1="0" y1="0" x2="1" y2="1"> <stop offset="0%" stop-color="#1f2338" /> <stop offset="100%" stop-color="#181b2c" /> </linearGradient> <linearGradient id="grad-gateway" x1="0" y1="0" x2="1" y2="1"> <stop offset="0%" stop-color="#21253c" /> <stop offset="100%" stop-color="#1a1d30" /> </linearGradient> <linearGradient id="grad-service" x1="0" y1="0" x2="1" y2="1"> <stop offset="0%" stop-color="#242841" /> <stop offset="100%" stop-color="#1c1f34" /> </linearGradient> <linearGradient id="grad-data" x1="0" y1="0" x2="1" y2="1"> <stop offset="0%" stop-color="#1b1e31" /> <stop offset="100%" stop-color="#161829" /> </linearGradient> <!-- Arrow marker --> <marker id="arrow-amber" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"> <path d="M 0 0 L 10 5 L 0 10 z" fill="#f5a623" opacity="0.8" /> </marker> <marker id="arrow-dim" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"> <path d="M 0 0 L 10 5 L 0 10 z" fill="#4a4f6a" opacity="0.55" /> </marker> <!-- Icon templates (Lucide-style) --> <g id="icon-browser"> <rect x="1" y="3" width="22" height="18" rx="2" stroke="currentColor" stroke-width="1.8" fill="none" /> <line x1="1" y1="9" x2="23" y2="9" stroke="currentColor" stroke-width="1.8" /> <circle cx="4.5" cy="6.5" r="0.9" fill="currentColor" /> </g> <g id="icon-server"> <rect x="2" y="2" width="20" height="20" rx="3" stroke="currentColor" stroke-width="1.8" fill="none" /> <line x1="6" y1="10" x2="18" y2="10" stroke="currentColor" stroke-width="1.8" /> <line x1="6" y1="14" x2="18" y2="14" stroke="currentColor" stroke-width="1.8" /> <line x1="6" y1="18" x2="18" y2="18" stroke="currentColor" stroke-width="1.8" /> </g> <g id="icon-db"> <ellipse cx="12" cy="5" rx="9" ry="3.5" stroke="currentColor" stroke-width="1.8" fill="none" /> <path d="M3 5v14c0 2 4 3.5 9 3.5s9-1.5 9-3.5V5" stroke="currentColor" stroke-width="1.8" fill="none" /> <line x1="3" y1="12" x2="21" y2="12" stroke="currentColor" stroke-width="1.8" /> </g> <g id="icon-cache"> <rect x="2" y="4" width="20" height="16" rx="2" stroke="currentColor" stroke-width="1.8" fill="none" /> <circle cx="12" cy="12" r="2.8" stroke="currentColor" stroke-width="1.8" fill="none" /> <path d="M8 8l4-4l4 4" stroke="currentColor" stroke-width="1.8" fill="none" /> <path d="M8 16l4 4l4-4" stroke="currentColor" stroke-width="1.8" fill="none" /> </g> <g id="icon-queue"> <rect x="2" y="4" width="20" height="16" rx="2" stroke="currentColor" stroke-width="1.8" fill="none" /> <circle cx="8" cy="12" r="1.8" fill="currentColor" opacity="0.5" /> <circle cx="14" cy="12" r="1.8" fill="currentColor" opacity="0.7" /> <circle cx="20" cy="12" r="1.8" fill="currentColor" /> </g> </defs> <!-- ── BACKGROUND GRID ── --> <rect width="1100" height="520" fill="url(#grid-dots)" opacity="0.6" /> <!-- ── LAYER LABELS (vertical, left side) ── --> <g font-family="'JetBrains Mono',monospace" font-size="9" fill="#4a4f6a" letter-spacing="0.08em"> <text x="28" y="90" transform="rotate(-90,28,90)" text-anchor="middle">CLIENT</text> <text x="28" y="200" transform="rotate(-90,28,200)" text-anchor="middle">GATEWAY</text> <text x="28" y="340" transform="rotate(-90,28,340)" text-anchor="middle">SERVICES</text> <text x="28" y="460" transform="rotate(-90,28,460)" text-anchor="middle">DATA</text> </g> <!-- ── SEPARATOR LINES (soft) ── --> <line x1="48" y1="120" x2="1070" y2="120" stroke="#2a2d3e" stroke-width="0.8" stroke-dasharray="4 6" opacity="0.4" /> <line x1="48" y1="250" x2="1070" y2="250" stroke="#2a2d3e" stroke-width="0.8" stroke-dasharray="4 6" opacity="0.4" /> <line x1="48" y1="400" x2="1070" y2="400" stroke="#2a2d3e" stroke-width="0.8" stroke-dasharray="4 6" opacity="0.4" /> <!-- ── CLIENT LAYER ── --> <!-- Card: Browser --> <rect x="100" y="40" width="180" height="66" rx="10" fill="url(#grad-client)" stroke="#2f3350" stroke-width="1.2" /> <use href="#icon-browser" x="115" y="47" width="22" height="22" color="#8892a8" /> <text x="146" y="64" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Web Browser</text> <text x="146" y="81" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">React · 18.2.0</text> <text x="146" y="95" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">User interface & routing</text> <!-- Card: Mobile --> <rect x="340" y="40" width="180" height="66" rx="10" fill="url(#grad-client)" stroke="#2f3350" stroke-width="1.2" /> <rect x="355" y="50" width="18" height="24" rx="3" stroke="#8892a8" stroke-width="1.8" fill="none" /> <circle cx="364" cy="79" r="1.8" fill="#8892a8" /> <text x="382" y="64" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Mobile App</text> <text x="382" y="81" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">Flutter · 3.22</text> <text x="382" y="95" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">iOS / Android</text> <!-- Arrow from Client to Gateway --> <line x1="530" y1="73" x2="610" y2="140" stroke="#f5a623" stroke-width="1.6" stroke-dasharray="5 3" opacity="0.7" marker-end="url(#arrow-amber)" /> <text x="543" y="98" font-family="'JetBrains Mono',monospace" font-size="8" fill="#f5a623" opacity="0.7">HTTPS · gRPC</text> <!-- ── GATEWAY LAYER ── --> <!-- Card: API Gateway --> <rect x="660" y="150" width="200" height="72" rx="10" fill="url(#grad-gateway)" stroke="#2f3350" stroke-width="1.2" /> <use href="#icon-server" x="675" y="159" width="22" height="22" color="#f5a623" /> <text x="708" y="177" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">API Gateway</text> <text x="708" y="194" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">Kong · 3.8</text> <text x="708" y="209" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">Auth · rate-limit · routing</text> <!-- Gateway -> Services arrows --> <line x1="780" y1="222" x2="780" y2="278" stroke="#f5a623" stroke-width="1.6" opacity="0.6" marker-end="url(#arrow-amber)" /> <text x="792" y="255" font-family="'JetBrains Mono',monospace" font-size="8" fill="#f5a623" opacity="0.5">internal</text> <!-- ── SERVICES LAYER ── --> <!-- Card: User Service --> <rect x="100" y="290" width="175" height="72" rx="10" fill="url(#grad-service)" stroke="#2f3350" stroke-width="1.2" /> <circle cx="120" cy="312" r="11" stroke="#f5a623" stroke-width="1.8" fill="none" /> <path d="M115 318a6 6 0 0110 0" stroke="#f5a623" stroke-width="1.6" fill="none" /> <circle cx="120" cy="308" r="2.5" fill="#f5a623" /> <text x="140" y="316" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">User Service</text> <text x="140" y="333" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">Node.js · 22</text> <text x="140" y="349" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">Profiles · auth · roles</text> <!-- Card: Content Service --> <rect x="310" y="290" width="175" height="72" rx="10" fill="url(#grad-service)" stroke="#2f3350" stroke-width="1.2" /> <rect x="328" y="302" width="16" height="18" rx="2" stroke="#f5a623" stroke-width="1.8" fill="none" /> <line x1="332" y1="308" x2="340" y2="308" stroke="#f5a623" stroke-width="1.6" /> <line x1="332" y1="313" x2="340" y2="313" stroke="#f5a623" stroke-width="1.6" /> <text x="352" y="316" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Content Service</text> <text x="352" y="333" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">Go · 1.22</text> <text x="352" y="349" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">Posts · media · search</text> <!-- Card: Notification Service --> <rect x="520" y="290" width="185" height="72" rx="10" fill="url(#grad-service)" stroke="#2f3350" stroke-width="1.2" /> <use href="#icon-queue" x="538" y="302" width="20" height="20" color="#f5a623" /> <text x="566" y="316" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Notification Svc</text> <text x="566" y="333" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">TypeScript · Bull</text> <text x="566" y="349" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">Email · push · SMS</text> <!-- Horizontal service bus --> <line x1="88" y1="345" x2="715" y2="345" stroke="#f5a623" stroke-width="0.8" stroke-dasharray="3 5" opacity="0.3" /> <!-- Services -> Data arrows --> <line x1="190" y1="362" x2="190" y2="418" stroke="#4a4f6a" stroke-width="1.2" opacity="0.5" marker-end="url(#arrow-dim)" /> <line x1="398" y1="362" x2="398" y2="418" stroke="#4a4f6a" stroke-width="1.2" opacity="0.5" marker-end="url(#arrow-dim)" /> <line x1="610" y1="362" x2="610" y2="418" stroke="#4a4f6a" stroke-width="1.2" opacity="0.5" marker-end="url(#arrow-dim)" /> <!-- ── DATA LAYER ── --> <!-- Card: Primary DB --> <rect x="100" y="430" width="195" height="66" rx="10" fill="url(#grad-data)" stroke="#2f3350" stroke-width="1.2" /> <use href="#icon-db" x="115" y="440" width="22" height="22" color="#8892a8" /> <text x="148" y="458" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Primary Database</text> <text x="148" y="475" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">PostgreSQL · 16</text> <text x="148" y="489" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">RDBMS · ACID · replicas</text> <!-- Card: Cache --> <rect x="340" y="430" width="170" height="66" rx="10" fill="url(#grad-data)" stroke="#2f3350" stroke-width="1.2" /> <use href="#icon-cache" x="355" y="440" width="22" height="22" color="#8892a8" /> <text x="386" y="458" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Cache Layer</text> <text x="386" y="475" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">Redis · 7.4</text> <text x="386" y="489" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">In-memory · TTL</text> <!-- Card: Message Queue --> <rect x="555" y="430" width="185" height="66" rx="10" fill="url(#grad-data)" stroke="#2f3350" stroke-width="1.2" /> <use href="#icon-queue" x="572" y="440" width="22" height="22" color="#8892a8" /> <text x="604" y="458" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Message Queue</text> <text x="604" y="475" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">RabbitMQ · 3.13</text> <text x="604" y="489" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">Async · pub/sub</text> <!-- ── EMPHASIZED NODE (glow) ── --> <!-- We'll add a subtle glow behind the API Gateway to demonstrate --> <rect x="654" y="144" width="212" height="84" rx="14" fill="none" stroke="#f5a623" stroke-width="1.6" filter="url(#amber-glow)" opacity="0.6" pointer-events="none" /> <!-- ── LEGEND ── --> <g font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a"> <rect x="870" y="445" width="10" height="10" rx="2" fill="#2a2d3e" stroke="#2f3350" stroke-width="1" /> <text x="888" y="453">Layer boundary</text> <line x1="870" y1="468" x2="880" y2="468" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-amber)" /> <text x="888" y="472">Data flow</text> <rect x="870" y="485" width="10" height="10" rx="2" fill="none" stroke="#f5a623" stroke-width="1.2" opacity="0.5" /> <text x="888" y="494">Emphasized node</text> </g> <!-- Diagram version / metadata --> <text x="1070" y="510" font-family="'JetBrains Mono',monospace" font-size="7" fill="#3d4156" text-anchor="end"> v2.3 · system context </text> </svg> </div> <!-- ========================================================== --> <!-- 2. SEQUENCE DIAGRAM --> <!-- ========================================================== --> <h2 class="section-title" style="margin-top:1rem;">Sequence</h2> <p class="section-sub">Request lifecycle for user authentication with token refresh</p> <div class="diagram-card"> <div class="diagram-label"><span>◆</span> SEQUENCE · auth.login.flow</div> <svg class="diagram-svg" viewBox="0 0 1100 580" xmlns="http://www.w3.org/2000/svg" style="background:#161926; border-radius:10px;"> <defs> <pattern id="grid-dots-s" patternUnits="userSpaceOnUse" width="24" height="24"> <circle cx="12" cy="12" r="1.1" fill="#2a2d3e" opacity="0.55" /> </pattern> <filter id="glow-seq" x="-30%" y="-30%" width="160%" height="160%"> <feGaussianBlur in="SourceGraphic" stdDeviation="6" result="blur" /> <feColorMatrix in="blur" type="matrix" values="0 0 0 0 0.96 0 0 0 0 0.65 0 0 0 0 0.14 0 0 0 0.35 0" /> </filter> <marker id="arrow-seq" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"> <path d="M 0 0 L 10 5 L 0 10 z" fill="#f5a623" opacity="0.85" /> </marker> <marker id="arrow-ret" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"> <path d="M 0 0 L 10 5 L 0 10 z" fill="#6b728c" opacity="0.7" /> </marker> <linearGradient id="grad-lifeline" x1="0" y1="0" x2="0" y2="1"> <stop offset="0%" stop-color="#f5a623" stop-opacity="0.25" /> <stop offset="100%" stop-color="#f5a623" stop-opacity="0" /> </linearGradient> </defs> <!-- Background grid --> <rect width="1100" height="580" fill="url(#grid-dots-s)" opacity="0.6" /> <!-- ── PARTICIPANT HEADERS ── --> <!-- We'll define columns for: User, Client, Auth API, Auth Service, Database --> <!-- Participant boxes at the top --> <!-- User --> <rect x="40" y="30" width="120" height="38" rx="8" fill="#1f2338" stroke="#2f3350" stroke-width="1.2" /> <circle cx="68" cy="49" r="8" stroke="#8892a8" stroke-width="1.6" fill="none" /> <path d="M63 54a5 5 0 0110 0" stroke="#8892a8" stroke-width="1.4" fill="none" /> <circle cx="68" cy="46" r="2" fill="#8892a8" /> <text x="84" y="54" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">User</text> <text x="84" y="66" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">browser / app</text> <!-- Client (Frontend) --> <rect x="210" y="30" width="130" height="38" rx="8" fill="#1f2338" stroke="#2f3350" stroke-width="1.2" /> <use href="#icon-browser" x="228" y="39" width="18" height="18" color="#8892a8" /> <text x="252" y="54" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Frontend</text> <text x="252" y="66" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">React SPA</text> <!-- Auth API --> <rect x="400" y="30" width="130" height="38" rx="8" fill="#21253c" stroke="#f5a623" stroke-width="1.4" /> <rect x="418" y="39" width="16" height="18" rx="3" stroke="#f5a623" stroke-width="1.6" fill="none" /> <text x="442" y="54" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Auth API</text> <text x="442" y="66" font-family="'JetBrains Mono',monospace" font-size="7" fill="#6b728c">Kong route</text> <!-- Glow on Auth API header --> <rect x="396" y="26" width="138" height="46" rx="11" fill="none" stroke="#f5a623" stroke-width="1.8" filter="url(#glow-seq)" opacity="0.5" pointer-events="none" /> <!-- Auth Service --> <rect x="590" y="30" width="140" height="38" rx="8" fill="#1f2338" stroke="#2f3350" stroke-width="1.2" /> <use href="#icon-server" x="608" y="39" width="18" height="18" color="#8892a8" /> <text x="632" y="54" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Auth Service</text> <text x="632" y="66" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">Node.js · JWT</text> <!-- Database --> <rect x="790" y="30" width="130" height="38" rx="8" fill="#1f2338" stroke="#2f3350" stroke-width="1.2" /> <use href="#icon-db" x="808" y="39" width="18" height="18" color="#8892a8" /> <text x="832" y="54" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Database</text> <text x="832" y="66" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">PostgreSQL</text> <!-- Lifelines (dashed vertical lines) --> <g stroke="#2a2d3e" stroke-width="1.2" stroke-dasharray="4 5"> <line x1="100" y1="75" x2="100" y2="530" /> <line x1="275" y1="75" x2="275" y2="530" /> <line x1="465" y1="75" x2="465" y2="530" /> <line x1="660" y1="75" x2="660" y2="530" /> <line x1="855" y1="75" x2="855" y2="530" /> </g> <!-- ── MESSAGES ── --> <!-- 1. User -> Frontend: Enter credentials --> <line x1="100" y1="110" x2="265" y2="110" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" /> <text x="135" y="104" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">Enter email & password</text> <text x="135" y="120" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">click "Sign In"</text> <!-- 2. Frontend -> Auth API: POST /auth/login --> <line x1="275" y1="150" x2="455" y2="150" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" /> <text x="310" y="144" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">POST /auth/login</text> <text x="310" y="160" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">{ email, password }</text> <!-- 3. Auth API -> Auth Service: validate + sign --> <line x1="465" y1="190" x2="650" y2="190" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" /> <text x="500" y="184" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">validate credentials</text> <text x="500" y="200" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">bcrypt · JWT sign</text> <!-- 4. Auth Service -> Database: SELECT user --> <line x1="660" y1="230" x2="845" y2="230" stroke="#6b728c" stroke-width="1.4" marker-end="url(#arrow-ret)" /> <text x="698" y="224" font-family="'Inter',sans-serif" font-size="10" fill="#8892a8">SELECT user by email</text> <text x="698" y="240" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">query · index scan</text> <!-- Activation bar on Database --> <rect x="855" y="225" width="4" height="18" fill="#f5a623" opacity="0.7" rx="2" /> <!-- 5. Database -> Auth Service: user row --> <line x1="855" y1="270" x2="670" y2="270" stroke="#6b728c" stroke-width="1.4" marker-end="url(#arrow-ret)" /> <text x="710" y="264" font-family="'Inter',sans-serif" font-size="10" fill="#8892a8">user row + hash</text> <text x="710" y="280" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">200 · found</text> <!-- 6. Auth Service -> Auth API: token --> <line x1="660" y1="310" x2="475" y2="310" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" /> <text x="510" y="304" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">return JWT + refresh</text> <text x="510" y="320" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">access_token · refresh_token</text> <!-- 7. Auth API -> Frontend: 200 OK --> <line x1="465" y1="350" x2="285" y2="350" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" /> <text x="310" y="344" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">200 · Set-Cookie</text> <text x="310" y="360" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">HttpOnly · Secure · SameSite</text> <!-- 8. Frontend -> User: dashboard --> <line x1="275" y1="390" x2="110" y2="390" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" /> <text x="140" y="384" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">Redirect to dashboard</text> <text x="140" y="400" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">window.location</text> <!-- ── SELF-REF / NOTE: Token refresh ── --> <rect x="420" y="430" width="260" height="42" rx="8" fill="#1a1d2e" stroke="#2f3350" stroke-width="1.2" /> <text x="440" y="450" font-family="'Inter',sans-serif" font-size="10" font-weight="600" fill="#f5a623">⟳ Token refresh</text> <text x="440" y="466" font-family="'Inter',sans-serif" font-size="9" fill="#6b728c">Silent refresh via /auth/refresh every 15 min</text> <!-- ── ACTIVATION BARS (along lifelines) ── --> <rect x="465" y="145" width="4" height="215" fill="url(#grad-lifeline)" rx="2" /> <rect x="660" y="185" width="4" height="135" fill="url(#grad-lifeline)" rx="2" /> <rect x="855" y="225" width="4" height="50" fill="url(#grad-lifeline)" rx="2" /> <!-- ── LEGEND ── --> <g font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a"> <line x1="80" y1="500" x2="110" y2="500" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" /> <text x="118" y="503">Request</text> <line x1="200" y1="500" x2="230" y2="500" stroke="#6b728c" stroke-width="1.4" marker-end="url(#arrow-ret)" /> <text x="238" y="503">Response</text> <rect x="330" y="495" width="8" height="8" rx="2" fill="#f5a623" opacity="0.3" /> <text x="346" y="503">Active period</text> </g> <!-- Metadata --> <text x="1070" y="565" font-family="'JetBrains Mono',monospace" font-size="7" fill="#3d4156" text-anchor="end"> seq · auth.login.v2 </text> </svg> </div> <!-- ========================================================== --> <!-- 3. STATE DIAGRAM --> <!-- ========================================================== --> <h2 class="section-title">State</h2> <p class="section-sub">Finite-state machine for document processing pipeline</p> <div class="diagram-card"> <div class="diagram-label"><span>◆</span> STATE · doc.processing.fsm</div> <svg class="diagram-svg" viewBox="0 0 1100 500" xmlns="http://www.w3.org/2000/svg" style="background:#161926; border-radius:10px;"> <defs> <pattern id="grid-dots-st" patternUnits="userSpaceOnUse" width="24" height="24"> <circle cx="12" cy="12" r="1.1" fill="#2a2d3e" opacity="0.55" /> </pattern> <filter id="glow-state" x="-50%" y="-50%" width="200%" height="200%"> <feGaussianBlur in="SourceGraphic" stdDeviation="9" result="blur" /> <feColorMatrix in="blur" type="matrix" values="0 0 0 0 0.96 0 0 0 0 0.65 0 0 0 0 0.14 0 0 0 0.40 0" /> </filter> <marker id="arrow-st" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"> <path d="M 0 0 L 10 5 L 0 10 z" fill="#f5a623" opacity="0.8" /> </marker> <marker id="arrow-st-dim" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"> <path d="M 0 0 L 10 5 L 0 10 z" fill="#4a4f6a" opacity="0.5" /> </marker> </defs> <!-- Background grid --> <rect width="1100" height="500" fill="url(#grid-dots-st)" opacity="0.6" /> <!-- ── STATES ── --> <!-- 1. IDLE (initial) --> <rect x="60" y="170" width="140" height="70" rx="14" fill="#1f2338" stroke="#2f3350" stroke-width="1.4" /> <!-- Initial marker --> <circle cx="70" cy="180" r="4" fill="#f5a623" /> <text x="88" y="196" font-family="'Inter',sans-serif" font-size="14" font-weight="600" fill="#8892a8">Idle</text> <text x="88" y="214" font-family="'JetBrains Mono',monospace" font-size="8" fill="#4a4f6a">awaiting input</text> <circle cx="170" cy="240" r="5" fill="none" stroke="#f5a623" stroke-width="1.6" opacity="0.5" /> <!-- 2. PENDING --> <rect x="320" y="80" width="140" height="70" rx="14" fill="#1f2338" stroke="#2f3350" stroke-width="1.4" /> <text x="348" y="106" font-family="'Inter',sans-serif" font-size="14" font-weight="600" fill="#e8eaf0">Pending</text> <text x="348" y="124" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">queued</text> <!-- 3. PROCESSING (emphasized - with glow) --> <rect x="530" y="170" width="150" height="70" rx="14" fill="#242841" stroke="#f5a623" stroke-width="1.8" /> <rect x="526" y="166" width="158" height="78" rx="18" fill="none" stroke="#f5a623" stroke-width="1.8" filter="url(#glow-state)" opacity="0.6" pointer-events="none" /> <text x="560" y="196" font-family="'Inter',sans-serif" font-size="14" font-weight="600" fill="#f5a623">Processing</text> <text x="560" y="214" font-family="'JetBrains Mono',monospace" font-size="8" fill="#f5a623" opacity="0.7">active · 12%</text> <!-- Spinner icon --> <path d="M605 182a8 8 0 100 16" stroke="#f5a623" stroke-width="2" fill="none" stroke-dasharray="4 6"> <animateTransform attributeName="transform" type="rotate" from="0 609 190" to="360 609 190" dur="2s" repeatCount="indefinite" /> </path> <!-- 4. SUCCESS --> <rect x="780" y="80" width="140" height="70" rx="14" fill="#1f2338" stroke="#2f3350" stroke-width="1.4" /> <text x="810" y="106" font-family="'Inter',sans-serif" font-size="14" font-weight="600" fill="#7ecf8a">Success</text> <text x="810" y="124" font-family="'JetBrains Mono',monospace" font-size="8" fill="#4a4f6a">completed</text> <circle cx="800" cy="98" r="6" stroke="#7ecf8a" stroke-width="1.6" fill="none" /> <polyline points="796,98 799,101 804,95" stroke="#7ecf8a" stroke-width="1.4" fill="none" /> <!-- 5. FAILED (error state) --> <rect x="780" y="280" width="140" height="70" rx="14" fill="#1f2338" stroke="#2f3350" stroke-width="1.4" /> <text x="808" y="306" font-family="'Inter',sans-serif" font-size="14" font-weight="600" fill="#e06c6c">Failed</text> <text x="808" y="324" font-family="'JetBrains Mono',monospace" font-size="8" fill="#4a4f6a">check logs</text> <circle cx="796" cy="298" r="6" stroke="#e06c6c" stroke-width="1.6" fill="none" /> <line x1="793" y1="295" x2="799" y2="301" stroke="#e06c6c" stroke-width="1.6" /> <line x1="799" y1="295" x2="793" y2="301" stroke="#e06c6c" stroke-width="1.6" /> <!-- ── TRANSITIONS ── --> <!-- Idle -> Pending (on submit) --> <line x1="200" y1="190" x2="310" y2="130" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-st)" /> <text x="230" y="162" font-family="'Inter',sans-serif" font-size="9" fill="#f5a623" opacity="0.8">document.submit()</text> <!-- Pending -> Processing (worker picks up) --> <line x1="460" y1="115" x2="520" y2="195" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-st)" /> <text x="475" y="148" font-family="'Inter',sans-serif" font-size="9" fill="#f5a623" opacity="0.8">worker.allocate()</text> <!-- Processing -> Success --> <line x1="680" y1="195" x2="770" y2="130" stroke="#7ecf8a" stroke-width="1.4" marker-end="url(#arrow-st)" /> <text x="695" y="162" font-family="'Inter',sans-serif" font-size="9" fill="#7ecf8a" opacity="0.7">onComplete()</text> <!-- Processing -> Failed --> <line x1="600" y1="240" x2="800" y2="310" stroke="#e06c6c" stroke-width="1.4" marker-end="url(#arrow-st)" /> <text x="675" y="280" font-family="'Inter',sans-serif" font-size="9" fill="#e06c6c" opacity="0.7">onError()</text> <!-- Failed -> Pending (retry) --> <path d="M 835 350 Q 835 400 460 400 Q 130 400 130 300 Q 130 200 310 140" stroke="#f5a623" stroke-width="1.2" stroke-dasharray="5 4" fill="none" marker-end="url(#arrow-st)" opacity="0.5" /> <text x="440" y="418" font-family="'Inter',sans-serif" font-size="8" fill="#f5a623" opacity="0.5">retry()</text> <!-- Success -> Idle (reset) --> <path d="M 850 150 Q 900 50 500 50 Q 200 50 160 160" stroke="#4a4f6a" stroke-width="1.2" stroke-dasharray="4 5" fill="none" marker-end="url(#arrow-st-dim)" opacity="0.4" /> <text x="460" y="52" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a" opacity="0.5">reset()</text> <!-- ── LEGEND ── --> <g font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a"> <circle cx="960" cy="420" r="4" fill="#f5a623" /> <text x="972" y="423">Initial state</text> <rect x="960" y="435" width="10" height="10" rx="3" fill="none" stroke="#f5a623" stroke-width="1.6" /> <text x="978" y="444">Active / emphasized</text> <line x1="960" y1="456" x2="975" y2="456" stroke="#e06c6c" stroke-width="1.4" /> <text x="984" y="459">Error transition</text> <line x1="960" y1="472" x2="975" y2="472" stroke="#4a4f6a" stroke-width="1.2" stroke-dasharray="4 4" /> <text x="984" y="475">Reset</text> </g> <!-- Metadata --> <text x="1070" y="490" font-family="'JetBrains Mono',monospace" font-size="7" fill="#3d4156" text-anchor="end"> fsm · doc-pipeline · v1 </text> </svg> </div> <!-- ========================================================== --> <!-- 4. FLOW DIAGRAM --> <!-- ========================================================== --> <h2 class="section-title">Flow</h2> <p class="section-sub">CI/CD deployment pipeline with quality gates and rollback</p> <div class="diagram-card"> <div class="diagram-label"><span>◆</span> FLOW · deploy.pipeline.gates</div> <svg class="diagram-svg" viewBox="0 0 1100 480" xmlns="http://www.w3.org/2000/svg" style="background:#161926; border-radius:10px;"> <defs> <pattern id="grid-dots-fl" patternUnits="userSpaceOnUse" width="24" height="24"> <circle cx="12" cy="12" r="1.1" fill="#2a2d3e" opacity="0.55" /> </pattern> <filter id="glow-flow" x="-30%" y="-30%" width="160%" height="160%"> <feGaussianBlur in="SourceGraphic" stdDeviation="6" result="blur" /> <feColorMatrix in="blur" type="matrix" values="0 0 0 0 0.96 0 0 0 0 0.65 0 0 0 0 0.14 0 0 0 0.30 0" /> </filter> <marker id="arrow-fl" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"> <path d="M 0 0 L 10 5 L 0 10 z" fill="#f5a623" opacity="0.85" /> </marker> <marker id="arrow-fl-dim" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"> <path d="M 0 0 L 10 5 L 0 10 z" fill="#4a4f6a" opacity="0.6" /> </marker> <linearGradient id="grad-flow-card" x1="0" y1="0" x2="1" y2="1"> <stop offset="0%" stop-color="#1f2338" /> <stop offset="100%" stop-color="#191c2e" /> </linearGradient> </defs> <!-- Background grid --> <rect width="1100" height="480" fill="url(#grid-dots-fl)" opacity="0.6" /> <!-- ── PIPELINE STEPS (horizontal layout with two rows) ── --> <!-- Row 1: Build & Test --> <!-- Step 1: Commit --> <rect x="50" y="60" width="140" height="72" rx="12" fill="url(#grad-flow-card)" stroke="#2f3350" stroke-width="1.2" /> <circle cx="78" cy="86" r="10" stroke="#f5a623" stroke-width="1.8" fill="none" /> <polyline points="73,86 77,90 83,82" stroke="#f5a623" stroke-width="1.8" fill="none" /> <text x="96" y="90" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Commit</text> <text x="96" y="108" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">git push</text> <text x="96" y="122" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">main / feat/*</text> <!-- Arrow 1->2 --> <line x1="190" y1="96" x2="240" y2="96" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-fl)" /> <!-- Step 2: Build --> <rect x="250" y="60" width="140" height="72" rx="12" fill="url(#grad-flow-card)" stroke="#2f3350" stroke-width="1.2" /> <rect x="274" y="76" width="16" height="18" rx="3" stroke="#8892a8" stroke-width="1.8" fill="none" /> <line x1="280" y1="82" x2="284" y2="82" stroke="#8892a8" stroke-width="1.6" /> <line x1="280" y1="87" x2="284" y2="87" stroke="#8892a8" stroke-width="1.6" /> <text x="298" y="90" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Build</text> <text x="298" y="108" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">Docker · Vite</text> <text x="298" y="122" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">image tags</text> <!-- Arrow 2->3 --> <line x1="390" y1="96" x2="440" y2="96" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-fl)" /> <!-- Step 3: Unit + Integration Tests --> <rect x="450" y="60" width="170" height="72" rx="12" fill="url(#grad-flow-card)" stroke="#2f3350" stroke-width="1.2" /> <circle cx="476" cy="84" r="7" stroke="#f5a623" stroke-width="1.6" fill="none" /> <path d="M472 90l4 4l8-8" stroke="#f5a623" stroke-width="1.6" fill="none" /> <text x="496" y="90" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Unit + Integration</text> <text x="496" y="108" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">Jest · Playwright</text> <text x="496" y="122" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">coverage ≥ 80%</text> <!-- Decision diamond after tests --> <polygon points="655,96 675,76 695,96 675,116" fill="#1a1d2e" stroke="#f5a623" stroke-width="1.6" /> <text x="675" y="100" font-family="'Inter',sans-serif" font-size="9" font-weight="600" fill="#f5a623">OK?</text> <!-- Pass arrow (down-right) --> <line x1="695" y1="96" x2="740" y2="96" stroke="#7ecf8a" stroke-width="1.6" marker-end="url(#arrow-fl)" /> <text x="710" y="88" font-family="'Inter',sans-serif" font-size="8" fill="#7ecf8a" opacity="0.8">pass</text> <!-- Fail arrow (down) --> <line x1="675" y1="116" x2="675" y2="170" stroke="#e06c6c" stroke-width="1.4" marker-end="url(#arrow-fl)" opacity="0.7" /> <text x="684" y="148" font-family="'Inter',sans-serif" font-size="8" fill="#e06c6c" opacity="0.7">fail</text> <!-- Step 4 (fail path): Fix --> <rect x="610" y="180" width="130" height="56" rx="10" fill="#1f2338" stroke="#e06c6c" stroke-width="1.2" stroke-dasharray="4 3" /> <text x="640" y="204" font-family="'Inter',sans-serif" font-size="11" font-weight="600" fill="#e06c6c">Fix & recommit</text> <text x="640" y="222" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">rollback · debug</text> <!-- Loop arrow back to commit --> <path d="M 610 208 Q 530 208 530 140 Q 530 96 190 96" stroke="#e06c6c" stroke-width="1.2" stroke-dasharray="5 4" fill="none" marker-end="url(#arrow-fl)" opacity="0.45" /> <!-- Row 2: Deploy --> <!-- Step 5: Deploy to Staging --> <rect x="750" y="60" width="155" height="72" rx="12" fill="url(#grad-flow-card)" stroke="#2f3350" stroke-width="1.2" /> <use href="#icon-server" x="768" y="76" width="18" height="18" color="#f5a623" /> <text x="794" y="90" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Deploy Staging</text> <text x="794" y="108" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">Helm · ArgoCD</text> <text x="794" y="122" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">staging.svc</text> <!-- Arrow 5->6 --> <line x1="905" y1="96" x2="950" y2="96" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-fl)" /> <!-- Step 6: E2E + Smoke Tests --> <rect x="960" y="60" width="120" height="72" rx="12" fill="url(#grad-flow-card)" stroke="#2f3350" stroke-width="1.2" /> <text x="986" y="90" font-family="'Inter',sans-serif" font-size="11" font-weight="600" fill="#e8eaf0">E2E & Smoke</text> <text x="986" y="108" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">Cypress · k6</text> <text x="986" y="122" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">canary 10%</text> <!-- Decision after smoke --> <polygon points="1020,165 1040,185 1020,205 1000,185" fill="#1a1d2e" stroke="#f5a623" stroke-width="1.6" /> <text x="1020" y="189" font-family="'Inter',sans-serif" font-size="9" font-weight="600" fill="#f5a623">OK?</text> <!-- Pass arrow to production --> <line x1="1020" y1="205" x2="1020" y2="280" stroke="#7ecf8a" stroke-width="1.6" marker-end="url(#arrow-fl)" /> <text x="1030" y="248" font-family="'Inter',sans-serif" font-size="8" fill="#7ecf8a" opacity="0.8">pass</text> <!-- Step 7: Deploy to Production (emphasized) --> <rect x="910" y="290" width="170" height="72" rx="12" fill="#242841" stroke="#f5a623" stroke-width="1.8" /> <rect x="906" y="286" width="178" height="80" rx="16" fill="none" stroke="#f5a623" stroke-width="1.8" filter="url(#glow-flow)" opacity="0.5" pointer-events="none" /> <use href="#icon-server" x="930" y="306" width="18" height="18" color="#f5a623" /> <text x="958" y="320" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#f5a623">Deploy Production</text> <text x="958" y="338" font-family="'JetBrains Mono',monospace" font-size="8" fill="#f5a623" opacity="0.7">prod.svc · 100%</text> <text x="958" y="353" font-family="'Inter',sans-serif" font-size="8" fill="#6b728c">blue/green · auto-rollback</text> <!-- Fail arrow from smoke back to staging --> <line x1="980" y1="205" x2="900" y2="185" stroke="#e06c6c" stroke-width="1.2" stroke-dasharray="5 4" fill="none" marker-end="url(#arrow-fl)" opacity="0.5" /> <text x="910" y="178" font-family="'Inter',sans-serif" font-size="7" fill="#e06c6c" opacity="0.6">rollback</text> <!-- ── QUALITY GATE BADGE ── --> <rect x="440" y="150" width="130" height="24" rx="6" fill="#1a1d2e" stroke="#2a2d3e" stroke-width="1" /> <text x="460" y="166" font-family="'JetBrains Mono',monospace" font-size="8" fill="#f5a623">⛁ Quality Gate</text> <!-- ── LEGEND ── --> <g font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a"> <rect x="40" y="400" width="10" height="10" rx="3" fill="none" stroke="#2f3350" stroke-width="1.2" /> <text x="58" y="408">Step</text> <polygon points="190,400 198,408 190,416 182,408" fill="#1a1d2e" stroke="#f5a623" stroke-width="1.2" /> <text x="206" y="408">Decision</text> <line x1="290" y1="404" x2="305" y2="404" stroke="#e06c6c" stroke-width="1.2" stroke-dasharray="4 3" /> <text x="314" y="408">Fail / rollback</text> <rect x="420" y="396" width="10" height="10" rx="3" fill="none" stroke="#f5a623" stroke-width="1.8" /> <text x="438" y="408">Emphasized</text> </g> <!-- Metadata --> <text x="1070" y="465" font-family="'JetBrains Mono',monospace" font-size="7" fill="#3d4156" text-anchor="end"> flow · deploy · v3.1 </text> </svg> </div> <!-- ========================================================== --> <!-- FOOTER --> <!-- ========================================================== --> <div class="docs-footer"> <span>◆</span> Tesseron Design System · dark slate + amber · Inter / JetBrains Mono </div> </div><!-- /container --> </body> </html> ``` ### Tesseron Diagram Design This page delivers four diagram types — architecture, sequence, state, and flow — each built with the Tesseron visual language. Here's how they work: - **Architecture Diagram** – Layered system view with client, gateway, service, and data tiers. Gradient cards and dotted-grid background reinforce the dark slate aesthetic, while the API Gateway node features a Gaussian-blur amber glow to mark emphasis. Lucide-style icons and JetBrains Mono labels keep the technical readout clean. - **Sequence Diagram** – Request lifecycle for authentication. Horizontal lifelines, arrow markers, and activation bars trace the flow from user through frontend, Auth API, service, and database. The Auth API header glows amber to signal the critical node, and response arrows use a muted gray to distinguish returns from requests. - **State Diagram** – Document processing FSM with Idle, Pending, Processing, Success, and Failed states. The Processing state glows amber and includes an animated spinner. Transition labels show triggers (`document.submit()`, `onError()`), and retry/reset paths use dashed lines for distinction. - **Flow Diagram** – CI/CD pipeline with build, test, deploy stages and quality gates. Decision diamonds branch pass/fail paths, with fail routes looping back to fix. The Production deploy node glows amber, and the overall layout uses horizontal step cards with clear arrow direction. Each diagram includes a legend, metadata tag, and consistent typography (Inter for labels, JetBrains Mono for code/version strings). The amber accent stays singular – used only for emphasis, active paths, and key nodes – preserving the restrained monochrome-plus-one aesthetic. --- **Optimization Tip:** You can replace placeholder text (e.g., "v2.3 · system context", "React · 18.2.0") with your actual version numbers, service names, or status messages.
3
下载量
命令行安装
在项目根目录执行以下命令,完成 Skill 安装。
npx bzskills add BrainBlend-AI/tesseron --skill tesseron-diagram name: tesseron-diagram
description: |-
I'll create a complete set of professional technical diagrams in the Tesseron visual language, with a dark slate base, amber accents, dotted-grid backgrounds, gradient cards, Lucide-style icons, Gaussian-blur glow, and Inter + JetBrains Mono typography.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tesseron Docs – Technical Diagrams</title>
<!-- Google Fonts: Inter + JetBrains Mono -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
rel="stylesheet"
/>
<style>
/* ── Reset & base ── */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
background: #12141f;
font-family: 'Inter', sans-serif;
color: #e8eaf0;
padding: 2.5rem 1.5rem;
display: flex;
flex-direction: column;
align-items: center;
}
.container {
max-width: 1400px;
width: 100%;
}
/* ── Section headers ── */
.section-title {
font-size: 1.75rem;
font-weight: 600;
letter-spacing: -0.02em;
color: #f5a623;
margin: 2.5rem 0 0.5rem 0;
display: flex;
align-items: center;
gap: 0.75rem;
}
.section-title::before {
content: '';
display: inline-block;
width: 4px;
height: 28px;
background: linear-gradient(180deg, #f5a623, #d48c1a);
border-radius: 2px;
}
.section-sub {
font-size: 0.95rem;
color: #8892a8;
margin-bottom: 1.75rem;
font-weight: 400;
padding-left: 1rem;
border-left: 2px solid #2a2d3e;
}
/* ── Diagram card wrapper ── */
.diagram-card {
background: #1a1d2e;
border-radius: 18px;
padding: 2rem 2rem 1.8rem 2rem;
margin-bottom: 2.8rem;
border: 1px solid #2a2d3e;
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
overflow: hidden;
position: relative;
}
.diagram-card::before {
content: '';
position: absolute;
inset: 0;
border-radius: 18px;
padding: 1px;
background: linear-gradient(135deg, rgba(245, 166, 35, 0.12), transparent 50%);
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
}
.diagram-card .diagram-label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.75rem;
font-weight: 500;
color: #6b728c;
text-transform: uppercase;
letter-spacing: 0.06em;
margin-bottom: 1.25rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.diagram-card .diagram-label span {
color: #f5a623;
}
/* ── SVG styling ── */
.diagram-svg {
width: 100%;
height: auto;
display: block;
border-radius: 10px;
background: #161926;
box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.3);
}
/* ── Responsive ── */
@media (max-width: 800px) {
body {
padding: 1.25rem 0.75rem;
}
.diagram-card {
padding: 1rem 0.75rem 0.75rem 0.75rem;
}
.section-title {
font-size: 1.3rem;
}
}
/* ── Tiny footer ── */
.docs-footer {
text-align: center;
font-size: 0.7rem;
color: #3d4156;
margin-top: 0.5rem;
font-family: 'JetBrains Mono', monospace;
letter-spacing: 0.04em;
}
.docs-footer span {
color: #f5a623;
}
</style>
</head>
<body>
<div class="container">
<!-- ===== INTRO ===== -->
<div style="margin-bottom:2rem;">
<div style="display:flex;align-items:center;gap:0.75rem;margin-bottom:0.25rem;">
<span style="font-size:1.6rem;font-weight:700;color:#f5a623;">◆</span>
<h1 style="font-weight:600;font-size:1.9rem;letter-spacing:-0.03em;color:#eceef5;">
Tesseron <span style="color:#f5a623;">Diagrams</span>
</h1>
</div>
<p style="color:#6b728c;font-size:0.95rem;padding-left:2.6rem;font-family:'JetBrains Mono',monospace;">
dark slate · single amber accent · dotted grid · gradient cards · glow
</p>
</div>
<!-- ========================================================== -->
<!-- 1. ARCHITECTURE DIAGRAM -->
<!-- ========================================================== -->
<h2 class="section-title">Architecture</h2>
<p class="section-sub">System-level component view with layered services and data flow</p>
<div class="diagram-card">
<div class="diagram-label"><span>◆</span> ARCHITECTURE · system.context</div>
<svg class="diagram-svg" viewBox="0 0 1100 520" xmlns="http://www.w3.org/2000/svg"
style="background:#161926; border-radius:10px;">
<!-- ── DEFS ── -->
<defs>
<!-- Dotted grid pattern -->
<pattern id="grid-dots" patternUnits="userSpaceOnUse" width="24" height="24">
<circle cx="12" cy="12" r="1.1" fill="#2a2d3e" opacity="0.55" />
</pattern>
<!-- Amber glow filter -->
<filter id="amber-glow" x="-40%" y="-40%" width="180%" height="180%">
<feGaussianBlur in="SourceGraphic" stdDeviation="8" result="blur1" />
<feColorMatrix in="blur1" type="matrix"
values="0 0 0 0 0.96
0 0 0 0 0.65
0 0 0 0 0.14
0 0 0 0.45 0"
result="colored" />
<feMerge>
<feMergeNode in="colored" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- Subtle card gradients -->
<linearGradient id="grad-client" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#1f2338" />
<stop offset="100%" stop-color="#181b2c" />
</linearGradient>
<linearGradient id="grad-gateway" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#21253c" />
<stop offset="100%" stop-color="#1a1d30" />
</linearGradient>
<linearGradient id="grad-service" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#242841" />
<stop offset="100%" stop-color="#1c1f34" />
</linearGradient>
<linearGradient id="grad-data" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#1b1e31" />
<stop offset="100%" stop-color="#161829" />
</linearGradient>
<!-- Arrow marker -->
<marker id="arrow-amber" viewBox="0 0 10 10" refX="9" refY="5"
markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#f5a623" opacity="0.8" />
</marker>
<marker id="arrow-dim" viewBox="0 0 10 10" refX="9" refY="5"
markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#4a4f6a" opacity="0.55" />
</marker>
<!-- Icon templates (Lucide-style) -->
<g id="icon-browser">
<rect x="1" y="3" width="22" height="18" rx="2" stroke="currentColor" stroke-width="1.8" fill="none" />
<line x1="1" y1="9" x2="23" y2="9" stroke="currentColor" stroke-width="1.8" />
<circle cx="4.5" cy="6.5" r="0.9" fill="currentColor" />
</g>
<g id="icon-server">
<rect x="2" y="2" width="20" height="20" rx="3" stroke="currentColor" stroke-width="1.8" fill="none" />
<line x1="6" y1="10" x2="18" y2="10" stroke="currentColor" stroke-width="1.8" />
<line x1="6" y1="14" x2="18" y2="14" stroke="currentColor" stroke-width="1.8" />
<line x1="6" y1="18" x2="18" y2="18" stroke="currentColor" stroke-width="1.8" />
</g>
<g id="icon-db">
<ellipse cx="12" cy="5" rx="9" ry="3.5" stroke="currentColor" stroke-width="1.8" fill="none" />
<path d="M3 5v14c0 2 4 3.5 9 3.5s9-1.5 9-3.5V5" stroke="currentColor" stroke-width="1.8" fill="none" />
<line x1="3" y1="12" x2="21" y2="12" stroke="currentColor" stroke-width="1.8" />
</g>
<g id="icon-cache">
<rect x="2" y="4" width="20" height="16" rx="2" stroke="currentColor" stroke-width="1.8" fill="none" />
<circle cx="12" cy="12" r="2.8" stroke="currentColor" stroke-width="1.8" fill="none" />
<path d="M8 8l4-4l4 4" stroke="currentColor" stroke-width="1.8" fill="none" />
<path d="M8 16l4 4l4-4" stroke="currentColor" stroke-width="1.8" fill="none" />
</g>
<g id="icon-queue">
<rect x="2" y="4" width="20" height="16" rx="2" stroke="currentColor" stroke-width="1.8" fill="none" />
<circle cx="8" cy="12" r="1.8" fill="currentColor" opacity="0.5" />
<circle cx="14" cy="12" r="1.8" fill="currentColor" opacity="0.7" />
<circle cx="20" cy="12" r="1.8" fill="currentColor" />
</g>
</defs>
<!-- ── BACKGROUND GRID ── -->
<rect width="1100" height="520" fill="url(#grid-dots)" opacity="0.6" />
<!-- ── LAYER LABELS (vertical, left side) ── -->
<g font-family="'JetBrains Mono',monospace" font-size="9" fill="#4a4f6a" letter-spacing="0.08em">
<text x="28" y="90" transform="rotate(-90,28,90)" text-anchor="middle">CLIENT</text>
<text x="28" y="200" transform="rotate(-90,28,200)" text-anchor="middle">GATEWAY</text>
<text x="28" y="340" transform="rotate(-90,28,340)" text-anchor="middle">SERVICES</text>
<text x="28" y="460" transform="rotate(-90,28,460)" text-anchor="middle">DATA</text>
</g>
<!-- ── SEPARATOR LINES (soft) ── -->
<line x1="48" y1="120" x2="1070" y2="120" stroke="#2a2d3e" stroke-width="0.8" stroke-dasharray="4 6" opacity="0.4" />
<line x1="48" y1="250" x2="1070" y2="250" stroke="#2a2d3e" stroke-width="0.8" stroke-dasharray="4 6" opacity="0.4" />
<line x1="48" y1="400" x2="1070" y2="400" stroke="#2a2d3e" stroke-width="0.8" stroke-dasharray="4 6" opacity="0.4" />
<!-- ── CLIENT LAYER ── -->
<!-- Card: Browser -->
<rect x="100" y="40" width="180" height="66" rx="10" fill="url(#grad-client)" stroke="#2f3350" stroke-width="1.2" />
<use href="#icon-browser" x="115" y="47" width="22" height="22" color="#8892a8" />
<text x="146" y="64" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Web Browser</text>
<text x="146" y="81" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">React · 18.2.0</text>
<text x="146" y="95" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">User interface & routing</text>
<!-- Card: Mobile -->
<rect x="340" y="40" width="180" height="66" rx="10" fill="url(#grad-client)" stroke="#2f3350" stroke-width="1.2" />
<rect x="355" y="50" width="18" height="24" rx="3" stroke="#8892a8" stroke-width="1.8" fill="none" />
<circle cx="364" cy="79" r="1.8" fill="#8892a8" />
<text x="382" y="64" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Mobile App</text>
<text x="382" y="81" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">Flutter · 3.22</text>
<text x="382" y="95" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">iOS / Android</text>
<!-- Arrow from Client to Gateway -->
<line x1="530" y1="73" x2="610" y2="140" stroke="#f5a623" stroke-width="1.6" stroke-dasharray="5 3" opacity="0.7" marker-end="url(#arrow-amber)" />
<text x="543" y="98" font-family="'JetBrains Mono',monospace" font-size="8" fill="#f5a623" opacity="0.7">HTTPS · gRPC</text>
<!-- ── GATEWAY LAYER ── -->
<!-- Card: API Gateway -->
<rect x="660" y="150" width="200" height="72" rx="10" fill="url(#grad-gateway)" stroke="#2f3350" stroke-width="1.2" />
<use href="#icon-server" x="675" y="159" width="22" height="22" color="#f5a623" />
<text x="708" y="177" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">API Gateway</text>
<text x="708" y="194" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">Kong · 3.8</text>
<text x="708" y="209" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">Auth · rate-limit · routing</text>
<!-- Gateway -> Services arrows -->
<line x1="780" y1="222" x2="780" y2="278" stroke="#f5a623" stroke-width="1.6" opacity="0.6" marker-end="url(#arrow-amber)" />
<text x="792" y="255" font-family="'JetBrains Mono',monospace" font-size="8" fill="#f5a623" opacity="0.5">internal</text>
<!-- ── SERVICES LAYER ── -->
<!-- Card: User Service -->
<rect x="100" y="290" width="175" height="72" rx="10" fill="url(#grad-service)" stroke="#2f3350" stroke-width="1.2" />
<circle cx="120" cy="312" r="11" stroke="#f5a623" stroke-width="1.8" fill="none" />
<path d="M115 318a6 6 0 0110 0" stroke="#f5a623" stroke-width="1.6" fill="none" />
<circle cx="120" cy="308" r="2.5" fill="#f5a623" />
<text x="140" y="316" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">User Service</text>
<text x="140" y="333" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">Node.js · 22</text>
<text x="140" y="349" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">Profiles · auth · roles</text>
<!-- Card: Content Service -->
<rect x="310" y="290" width="175" height="72" rx="10" fill="url(#grad-service)" stroke="#2f3350" stroke-width="1.2" />
<rect x="328" y="302" width="16" height="18" rx="2" stroke="#f5a623" stroke-width="1.8" fill="none" />
<line x1="332" y1="308" x2="340" y2="308" stroke="#f5a623" stroke-width="1.6" />
<line x1="332" y1="313" x2="340" y2="313" stroke="#f5a623" stroke-width="1.6" />
<text x="352" y="316" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Content Service</text>
<text x="352" y="333" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">Go · 1.22</text>
<text x="352" y="349" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">Posts · media · search</text>
<!-- Card: Notification Service -->
<rect x="520" y="290" width="185" height="72" rx="10" fill="url(#grad-service)" stroke="#2f3350" stroke-width="1.2" />
<use href="#icon-queue" x="538" y="302" width="20" height="20" color="#f5a623" />
<text x="566" y="316" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Notification Svc</text>
<text x="566" y="333" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">TypeScript · Bull</text>
<text x="566" y="349" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">Email · push · SMS</text>
<!-- Horizontal service bus -->
<line x1="88" y1="345" x2="715" y2="345" stroke="#f5a623" stroke-width="0.8" stroke-dasharray="3 5" opacity="0.3" />
<!-- Services -> Data arrows -->
<line x1="190" y1="362" x2="190" y2="418" stroke="#4a4f6a" stroke-width="1.2" opacity="0.5" marker-end="url(#arrow-dim)" />
<line x1="398" y1="362" x2="398" y2="418" stroke="#4a4f6a" stroke-width="1.2" opacity="0.5" marker-end="url(#arrow-dim)" />
<line x1="610" y1="362" x2="610" y2="418" stroke="#4a4f6a" stroke-width="1.2" opacity="0.5" marker-end="url(#arrow-dim)" />
<!-- ── DATA LAYER ── -->
<!-- Card: Primary DB -->
<rect x="100" y="430" width="195" height="66" rx="10" fill="url(#grad-data)" stroke="#2f3350" stroke-width="1.2" />
<use href="#icon-db" x="115" y="440" width="22" height="22" color="#8892a8" />
<text x="148" y="458" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Primary Database</text>
<text x="148" y="475" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">PostgreSQL · 16</text>
<text x="148" y="489" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">RDBMS · ACID · replicas</text>
<!-- Card: Cache -->
<rect x="340" y="430" width="170" height="66" rx="10" fill="url(#grad-data)" stroke="#2f3350" stroke-width="1.2" />
<use href="#icon-cache" x="355" y="440" width="22" height="22" color="#8892a8" />
<text x="386" y="458" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Cache Layer</text>
<text x="386" y="475" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">Redis · 7.4</text>
<text x="386" y="489" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">In-memory · TTL</text>
<!-- Card: Message Queue -->
<rect x="555" y="430" width="185" height="66" rx="10" fill="url(#grad-data)" stroke="#2f3350" stroke-width="1.2" />
<use href="#icon-queue" x="572" y="440" width="22" height="22" color="#8892a8" />
<text x="604" y="458" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#e8eaf0">Message Queue</text>
<text x="604" y="475" font-family="'JetBrains Mono',monospace" font-size="9" fill="#6b728c">RabbitMQ · 3.13</text>
<text x="604" y="489" font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">Async · pub/sub</text>
<!-- ── EMPHASIZED NODE (glow) ── -->
<!-- We'll add a subtle glow behind the API Gateway to demonstrate -->
<rect x="654" y="144" width="212" height="84" rx="14" fill="none" stroke="#f5a623" stroke-width="1.6"
filter="url(#amber-glow)" opacity="0.6" pointer-events="none" />
<!-- ── LEGEND ── -->
<g font-family="'Inter',sans-serif" font-size="9" fill="#4a4f6a">
<rect x="870" y="445" width="10" height="10" rx="2" fill="#2a2d3e" stroke="#2f3350" stroke-width="1" />
<text x="888" y="453">Layer boundary</text>
<line x1="870" y1="468" x2="880" y2="468" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-amber)" />
<text x="888" y="472">Data flow</text>
<rect x="870" y="485" width="10" height="10" rx="2" fill="none" stroke="#f5a623" stroke-width="1.2" opacity="0.5" />
<text x="888" y="494">Emphasized node</text>
</g>
<!-- Diagram version / metadata -->
<text x="1070" y="510" font-family="'JetBrains Mono',monospace" font-size="7" fill="#3d4156" text-anchor="end">
v2.3 · system context
</text>
</svg>
</div>
<!-- ========================================================== -->
<!-- 2. SEQUENCE DIAGRAM -->
<!-- ========================================================== -->
<h2 class="section-title" style="margin-top:1rem;">Sequence</h2>
<p class="section-sub">Request lifecycle for user authentication with token refresh</p>
<div class="diagram-card">
<div class="diagram-label"><span>◆</span> SEQUENCE · auth.login.flow</div>
<svg class="diagram-svg" viewBox="0 0 1100 580" xmlns="http://www.w3.org/2000/svg"
style="background:#161926; border-radius:10px;">
<defs>
<pattern id="grid-dots-s" patternUnits="userSpaceOnUse" width="24" height="24">
<circle cx="12" cy="12" r="1.1" fill="#2a2d3e" opacity="0.55" />
</pattern>
<filter id="glow-seq" x="-30%" y="-30%" width="160%" height="160%">
<feGaussianBlur in="SourceGraphic" stdDeviation="6" result="blur" />
<feColorMatrix in="blur" type="matrix"
values="0 0 0 0 0.96
0 0 0 0 0.65
0 0 0 0 0.14
0 0 0 0.35 0" />
</filter>
<marker id="arrow-seq" viewBox="0 0 10 10" refX="9" refY="5"
markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#f5a623" opacity="0.85" />
</marker>
<marker id="arrow-ret" viewBox="0 0 10 10" refX="9" refY="5"
markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#6b728c" opacity="0.7" />
</marker>
<linearGradient id="grad-lifeline" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#f5a623" stop-opacity="0.25" />
<stop offset="100%" stop-color="#f5a623" stop-opacity="0" />
</linearGradient>
</defs>
<!-- Background grid -->
<rect width="1100" height="580" fill="url(#grid-dots-s)" opacity="0.6" />
<!-- ── PARTICIPANT HEADERS ── -->
<!-- We'll define columns for: User, Client, Auth API, Auth Service, Database -->
<!-- Participant boxes at the top -->
<!-- User -->
<rect x="40" y="30" width="120" height="38" rx="8" fill="#1f2338" stroke="#2f3350" stroke-width="1.2" />
<circle cx="68" cy="49" r="8" stroke="#8892a8" stroke-width="1.6" fill="none" />
<path d="M63 54a5 5 0 0110 0" stroke="#8892a8" stroke-width="1.4" fill="none" />
<circle cx="68" cy="46" r="2" fill="#8892a8" />
<text x="84" y="54" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">User</text>
<text x="84" y="66" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">browser / app</text>
<!-- Client (Frontend) -->
<rect x="210" y="30" width="130" height="38" rx="8" fill="#1f2338" stroke="#2f3350" stroke-width="1.2" />
<use href="#icon-browser" x="228" y="39" width="18" height="18" color="#8892a8" />
<text x="252" y="54" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Frontend</text>
<text x="252" y="66" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">React SPA</text>
<!-- Auth API -->
<rect x="400" y="30" width="130" height="38" rx="8" fill="#21253c" stroke="#f5a623" stroke-width="1.4" />
<rect x="418" y="39" width="16" height="18" rx="3" stroke="#f5a623" stroke-width="1.6" fill="none" />
<text x="442" y="54" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Auth API</text>
<text x="442" y="66" font-family="'JetBrains Mono',monospace" font-size="7" fill="#6b728c">Kong route</text>
<!-- Glow on Auth API header -->
<rect x="396" y="26" width="138" height="46" rx="11" fill="none" stroke="#f5a623" stroke-width="1.8"
filter="url(#glow-seq)" opacity="0.5" pointer-events="none" />
<!-- Auth Service -->
<rect x="590" y="30" width="140" height="38" rx="8" fill="#1f2338" stroke="#2f3350" stroke-width="1.2" />
<use href="#icon-server" x="608" y="39" width="18" height="18" color="#8892a8" />
<text x="632" y="54" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Auth Service</text>
<text x="632" y="66" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">Node.js · JWT</text>
<!-- Database -->
<rect x="790" y="30" width="130" height="38" rx="8" fill="#1f2338" stroke="#2f3350" stroke-width="1.2" />
<use href="#icon-db" x="808" y="39" width="18" height="18" color="#8892a8" />
<text x="832" y="54" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Database</text>
<text x="832" y="66" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">PostgreSQL</text>
<!-- Lifelines (dashed vertical lines) -->
<g stroke="#2a2d3e" stroke-width="1.2" stroke-dasharray="4 5">
<line x1="100" y1="75" x2="100" y2="530" />
<line x1="275" y1="75" x2="275" y2="530" />
<line x1="465" y1="75" x2="465" y2="530" />
<line x1="660" y1="75" x2="660" y2="530" />
<line x1="855" y1="75" x2="855" y2="530" />
</g>
<!-- ── MESSAGES ── -->
<!-- 1. User -> Frontend: Enter credentials -->
<line x1="100" y1="110" x2="265" y2="110" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" />
<text x="135" y="104" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">Enter email & password</text>
<text x="135" y="120" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">click "Sign In"</text>
<!-- 2. Frontend -> Auth API: POST /auth/login -->
<line x1="275" y1="150" x2="455" y2="150" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" />
<text x="310" y="144" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">POST /auth/login</text>
<text x="310" y="160" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">{ email, password }</text>
<!-- 3. Auth API -> Auth Service: validate + sign -->
<line x1="465" y1="190" x2="650" y2="190" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" />
<text x="500" y="184" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">validate credentials</text>
<text x="500" y="200" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">bcrypt · JWT sign</text>
<!-- 4. Auth Service -> Database: SELECT user -->
<line x1="660" y1="230" x2="845" y2="230" stroke="#6b728c" stroke-width="1.4" marker-end="url(#arrow-ret)" />
<text x="698" y="224" font-family="'Inter',sans-serif" font-size="10" fill="#8892a8">SELECT user by email</text>
<text x="698" y="240" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">query · index scan</text>
<!-- Activation bar on Database -->
<rect x="855" y="225" width="4" height="18" fill="#f5a623" opacity="0.7" rx="2" />
<!-- 5. Database -> Auth Service: user row -->
<line x1="855" y1="270" x2="670" y2="270" stroke="#6b728c" stroke-width="1.4" marker-end="url(#arrow-ret)" />
<text x="710" y="264" font-family="'Inter',sans-serif" font-size="10" fill="#8892a8">user row + hash</text>
<text x="710" y="280" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">200 · found</text>
<!-- 6. Auth Service -> Auth API: token -->
<line x1="660" y1="310" x2="475" y2="310" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" />
<text x="510" y="304" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">return JWT + refresh</text>
<text x="510" y="320" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">access_token · refresh_token</text>
<!-- 7. Auth API -> Frontend: 200 OK -->
<line x1="465" y1="350" x2="285" y2="350" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" />
<text x="310" y="344" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">200 · Set-Cookie</text>
<text x="310" y="360" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">HttpOnly · Secure · SameSite</text>
<!-- 8. Frontend -> User: dashboard -->
<line x1="275" y1="390" x2="110" y2="390" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" />
<text x="140" y="384" font-family="'Inter',sans-serif" font-size="10" fill="#e8eaf0">Redirect to dashboard</text>
<text x="140" y="400" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">window.location</text>
<!-- ── SELF-REF / NOTE: Token refresh ── -->
<rect x="420" y="430" width="260" height="42" rx="8" fill="#1a1d2e" stroke="#2f3350" stroke-width="1.2" />
<text x="440" y="450" font-family="'Inter',sans-serif" font-size="10" font-weight="600" fill="#f5a623">⟳ Token refresh</text>
<text x="440" y="466" font-family="'Inter',sans-serif" font-size="9" fill="#6b728c">Silent refresh via /auth/refresh every 15 min</text>
<!-- ── ACTIVATION BARS (along lifelines) ── -->
<rect x="465" y="145" width="4" height="215" fill="url(#grad-lifeline)" rx="2" />
<rect x="660" y="185" width="4" height="135" fill="url(#grad-lifeline)" rx="2" />
<rect x="855" y="225" width="4" height="50" fill="url(#grad-lifeline)" rx="2" />
<!-- ── LEGEND ── -->
<g font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">
<line x1="80" y1="500" x2="110" y2="500" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-seq)" />
<text x="118" y="503">Request</text>
<line x1="200" y1="500" x2="230" y2="500" stroke="#6b728c" stroke-width="1.4" marker-end="url(#arrow-ret)" />
<text x="238" y="503">Response</text>
<rect x="330" y="495" width="8" height="8" rx="2" fill="#f5a623" opacity="0.3" />
<text x="346" y="503">Active period</text>
</g>
<!-- Metadata -->
<text x="1070" y="565" font-family="'JetBrains Mono',monospace" font-size="7" fill="#3d4156" text-anchor="end">
seq · auth.login.v2
</text>
</svg>
</div>
<!-- ========================================================== -->
<!-- 3. STATE DIAGRAM -->
<!-- ========================================================== -->
<h2 class="section-title">State</h2>
<p class="section-sub">Finite-state machine for document processing pipeline</p>
<div class="diagram-card">
<div class="diagram-label"><span>◆</span> STATE · doc.processing.fsm</div>
<svg class="diagram-svg" viewBox="0 0 1100 500" xmlns="http://www.w3.org/2000/svg"
style="background:#161926; border-radius:10px;">
<defs>
<pattern id="grid-dots-st" patternUnits="userSpaceOnUse" width="24" height="24">
<circle cx="12" cy="12" r="1.1" fill="#2a2d3e" opacity="0.55" />
</pattern>
<filter id="glow-state" x="-50%" y="-50%" width="200%" height="200%">
<feGaussianBlur in="SourceGraphic" stdDeviation="9" result="blur" />
<feColorMatrix in="blur" type="matrix"
values="0 0 0 0 0.96
0 0 0 0 0.65
0 0 0 0 0.14
0 0 0 0.40 0" />
</filter>
<marker id="arrow-st" viewBox="0 0 10 10" refX="9" refY="5"
markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#f5a623" opacity="0.8" />
</marker>
<marker id="arrow-st-dim" viewBox="0 0 10 10" refX="9" refY="5"
markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#4a4f6a" opacity="0.5" />
</marker>
</defs>
<!-- Background grid -->
<rect width="1100" height="500" fill="url(#grid-dots-st)" opacity="0.6" />
<!-- ── STATES ── -->
<!-- 1. IDLE (initial) -->
<rect x="60" y="170" width="140" height="70" rx="14" fill="#1f2338" stroke="#2f3350" stroke-width="1.4" />
<!-- Initial marker -->
<circle cx="70" cy="180" r="4" fill="#f5a623" />
<text x="88" y="196" font-family="'Inter',sans-serif" font-size="14" font-weight="600" fill="#8892a8">Idle</text>
<text x="88" y="214" font-family="'JetBrains Mono',monospace" font-size="8" fill="#4a4f6a">awaiting input</text>
<circle cx="170" cy="240" r="5" fill="none" stroke="#f5a623" stroke-width="1.6" opacity="0.5" />
<!-- 2. PENDING -->
<rect x="320" y="80" width="140" height="70" rx="14" fill="#1f2338" stroke="#2f3350" stroke-width="1.4" />
<text x="348" y="106" font-family="'Inter',sans-serif" font-size="14" font-weight="600" fill="#e8eaf0">Pending</text>
<text x="348" y="124" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">queued</text>
<!-- 3. PROCESSING (emphasized - with glow) -->
<rect x="530" y="170" width="150" height="70" rx="14" fill="#242841" stroke="#f5a623" stroke-width="1.8" />
<rect x="526" y="166" width="158" height="78" rx="18" fill="none" stroke="#f5a623" stroke-width="1.8"
filter="url(#glow-state)" opacity="0.6" pointer-events="none" />
<text x="560" y="196" font-family="'Inter',sans-serif" font-size="14" font-weight="600" fill="#f5a623">Processing</text>
<text x="560" y="214" font-family="'JetBrains Mono',monospace" font-size="8" fill="#f5a623" opacity="0.7">active · 12%</text>
<!-- Spinner icon -->
<path d="M605 182a8 8 0 100 16" stroke="#f5a623" stroke-width="2" fill="none" stroke-dasharray="4 6">
<animateTransform attributeName="transform" type="rotate" from="0 609 190" to="360 609 190" dur="2s" repeatCount="indefinite" />
</path>
<!-- 4. SUCCESS -->
<rect x="780" y="80" width="140" height="70" rx="14" fill="#1f2338" stroke="#2f3350" stroke-width="1.4" />
<text x="810" y="106" font-family="'Inter',sans-serif" font-size="14" font-weight="600" fill="#7ecf8a">Success</text>
<text x="810" y="124" font-family="'JetBrains Mono',monospace" font-size="8" fill="#4a4f6a">completed</text>
<circle cx="800" cy="98" r="6" stroke="#7ecf8a" stroke-width="1.6" fill="none" />
<polyline points="796,98 799,101 804,95" stroke="#7ecf8a" stroke-width="1.4" fill="none" />
<!-- 5. FAILED (error state) -->
<rect x="780" y="280" width="140" height="70" rx="14" fill="#1f2338" stroke="#2f3350" stroke-width="1.4" />
<text x="808" y="306" font-family="'Inter',sans-serif" font-size="14" font-weight="600" fill="#e06c6c">Failed</text>
<text x="808" y="324" font-family="'JetBrains Mono',monospace" font-size="8" fill="#4a4f6a">check logs</text>
<circle cx="796" cy="298" r="6" stroke="#e06c6c" stroke-width="1.6" fill="none" />
<line x1="793" y1="295" x2="799" y2="301" stroke="#e06c6c" stroke-width="1.6" />
<line x1="799" y1="295" x2="793" y2="301" stroke="#e06c6c" stroke-width="1.6" />
<!-- ── TRANSITIONS ── -->
<!-- Idle -> Pending (on submit) -->
<line x1="200" y1="190" x2="310" y2="130" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-st)" />
<text x="230" y="162" font-family="'Inter',sans-serif" font-size="9" fill="#f5a623" opacity="0.8">document.submit()</text>
<!-- Pending -> Processing (worker picks up) -->
<line x1="460" y1="115" x2="520" y2="195" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-st)" />
<text x="475" y="148" font-family="'Inter',sans-serif" font-size="9" fill="#f5a623" opacity="0.8">worker.allocate()</text>
<!-- Processing -> Success -->
<line x1="680" y1="195" x2="770" y2="130" stroke="#7ecf8a" stroke-width="1.4" marker-end="url(#arrow-st)" />
<text x="695" y="162" font-family="'Inter',sans-serif" font-size="9" fill="#7ecf8a" opacity="0.7">onComplete()</text>
<!-- Processing -> Failed -->
<line x1="600" y1="240" x2="800" y2="310" stroke="#e06c6c" stroke-width="1.4" marker-end="url(#arrow-st)" />
<text x="675" y="280" font-family="'Inter',sans-serif" font-size="9" fill="#e06c6c" opacity="0.7">onError()</text>
<!-- Failed -> Pending (retry) -->
<path d="M 835 350 Q 835 400 460 400 Q 130 400 130 300 Q 130 200 310 140"
stroke="#f5a623" stroke-width="1.2" stroke-dasharray="5 4" fill="none" marker-end="url(#arrow-st)" opacity="0.5" />
<text x="440" y="418" font-family="'Inter',sans-serif" font-size="8" fill="#f5a623" opacity="0.5">retry()</text>
<!-- Success -> Idle (reset) -->
<path d="M 850 150 Q 900 50 500 50 Q 200 50 160 160"
stroke="#4a4f6a" stroke-width="1.2" stroke-dasharray="4 5" fill="none" marker-end="url(#arrow-st-dim)" opacity="0.4" />
<text x="460" y="52" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a" opacity="0.5">reset()</text>
<!-- ── LEGEND ── -->
<g font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">
<circle cx="960" cy="420" r="4" fill="#f5a623" />
<text x="972" y="423">Initial state</text>
<rect x="960" y="435" width="10" height="10" rx="3" fill="none" stroke="#f5a623" stroke-width="1.6" />
<text x="978" y="444">Active / emphasized</text>
<line x1="960" y1="456" x2="975" y2="456" stroke="#e06c6c" stroke-width="1.4" />
<text x="984" y="459">Error transition</text>
<line x1="960" y1="472" x2="975" y2="472" stroke="#4a4f6a" stroke-width="1.2" stroke-dasharray="4 4" />
<text x="984" y="475">Reset</text>
</g>
<!-- Metadata -->
<text x="1070" y="490" font-family="'JetBrains Mono',monospace" font-size="7" fill="#3d4156" text-anchor="end">
fsm · doc-pipeline · v1
</text>
</svg>
</div>
<!-- ========================================================== -->
<!-- 4. FLOW DIAGRAM -->
<!-- ========================================================== -->
<h2 class="section-title">Flow</h2>
<p class="section-sub">CI/CD deployment pipeline with quality gates and rollback</p>
<div class="diagram-card">
<div class="diagram-label"><span>◆</span> FLOW · deploy.pipeline.gates</div>
<svg class="diagram-svg" viewBox="0 0 1100 480" xmlns="http://www.w3.org/2000/svg"
style="background:#161926; border-radius:10px;">
<defs>
<pattern id="grid-dots-fl" patternUnits="userSpaceOnUse" width="24" height="24">
<circle cx="12" cy="12" r="1.1" fill="#2a2d3e" opacity="0.55" />
</pattern>
<filter id="glow-flow" x="-30%" y="-30%" width="160%" height="160%">
<feGaussianBlur in="SourceGraphic" stdDeviation="6" result="blur" />
<feColorMatrix in="blur" type="matrix"
values="0 0 0 0 0.96
0 0 0 0 0.65
0 0 0 0 0.14
0 0 0 0.30 0" />
</filter>
<marker id="arrow-fl" viewBox="0 0 10 10" refX="9" refY="5"
markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#f5a623" opacity="0.85" />
</marker>
<marker id="arrow-fl-dim" viewBox="0 0 10 10" refX="9" refY="5"
markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" fill="#4a4f6a" opacity="0.6" />
</marker>
<linearGradient id="grad-flow-card" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="#1f2338" />
<stop offset="100%" stop-color="#191c2e" />
</linearGradient>
</defs>
<!-- Background grid -->
<rect width="1100" height="480" fill="url(#grid-dots-fl)" opacity="0.6" />
<!-- ── PIPELINE STEPS (horizontal layout with two rows) ── -->
<!-- Row 1: Build & Test -->
<!-- Step 1: Commit -->
<rect x="50" y="60" width="140" height="72" rx="12" fill="url(#grad-flow-card)" stroke="#2f3350" stroke-width="1.2" />
<circle cx="78" cy="86" r="10" stroke="#f5a623" stroke-width="1.8" fill="none" />
<polyline points="73,86 77,90 83,82" stroke="#f5a623" stroke-width="1.8" fill="none" />
<text x="96" y="90" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Commit</text>
<text x="96" y="108" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">git push</text>
<text x="96" y="122" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">main / feat/*</text>
<!-- Arrow 1->2 -->
<line x1="190" y1="96" x2="240" y2="96" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-fl)" />
<!-- Step 2: Build -->
<rect x="250" y="60" width="140" height="72" rx="12" fill="url(#grad-flow-card)" stroke="#2f3350" stroke-width="1.2" />
<rect x="274" y="76" width="16" height="18" rx="3" stroke="#8892a8" stroke-width="1.8" fill="none" />
<line x1="280" y1="82" x2="284" y2="82" stroke="#8892a8" stroke-width="1.6" />
<line x1="280" y1="87" x2="284" y2="87" stroke="#8892a8" stroke-width="1.6" />
<text x="298" y="90" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Build</text>
<text x="298" y="108" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">Docker · Vite</text>
<text x="298" y="122" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">image tags</text>
<!-- Arrow 2->3 -->
<line x1="390" y1="96" x2="440" y2="96" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-fl)" />
<!-- Step 3: Unit + Integration Tests -->
<rect x="450" y="60" width="170" height="72" rx="12" fill="url(#grad-flow-card)" stroke="#2f3350" stroke-width="1.2" />
<circle cx="476" cy="84" r="7" stroke="#f5a623" stroke-width="1.6" fill="none" />
<path d="M472 90l4 4l8-8" stroke="#f5a623" stroke-width="1.6" fill="none" />
<text x="496" y="90" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Unit + Integration</text>
<text x="496" y="108" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">Jest · Playwright</text>
<text x="496" y="122" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">coverage ≥ 80%</text>
<!-- Decision diamond after tests -->
<polygon points="655,96 675,76 695,96 675,116" fill="#1a1d2e" stroke="#f5a623" stroke-width="1.6" />
<text x="675" y="100" font-family="'Inter',sans-serif" font-size="9" font-weight="600" fill="#f5a623">OK?</text>
<!-- Pass arrow (down-right) -->
<line x1="695" y1="96" x2="740" y2="96" stroke="#7ecf8a" stroke-width="1.6" marker-end="url(#arrow-fl)" />
<text x="710" y="88" font-family="'Inter',sans-serif" font-size="8" fill="#7ecf8a" opacity="0.8">pass</text>
<!-- Fail arrow (down) -->
<line x1="675" y1="116" x2="675" y2="170" stroke="#e06c6c" stroke-width="1.4" marker-end="url(#arrow-fl)" opacity="0.7" />
<text x="684" y="148" font-family="'Inter',sans-serif" font-size="8" fill="#e06c6c" opacity="0.7">fail</text>
<!-- Step 4 (fail path): Fix -->
<rect x="610" y="180" width="130" height="56" rx="10" fill="#1f2338" stroke="#e06c6c" stroke-width="1.2" stroke-dasharray="4 3" />
<text x="640" y="204" font-family="'Inter',sans-serif" font-size="11" font-weight="600" fill="#e06c6c">Fix & recommit</text>
<text x="640" y="222" font-family="'JetBrains Mono',monospace" font-size="7" fill="#4a4f6a">rollback · debug</text>
<!-- Loop arrow back to commit -->
<path d="M 610 208 Q 530 208 530 140 Q 530 96 190 96" stroke="#e06c6c" stroke-width="1.2"
stroke-dasharray="5 4" fill="none" marker-end="url(#arrow-fl)" opacity="0.45" />
<!-- Row 2: Deploy -->
<!-- Step 5: Deploy to Staging -->
<rect x="750" y="60" width="155" height="72" rx="12" fill="url(#grad-flow-card)" stroke="#2f3350" stroke-width="1.2" />
<use href="#icon-server" x="768" y="76" width="18" height="18" color="#f5a623" />
<text x="794" y="90" font-family="'Inter',sans-serif" font-size="12" font-weight="600" fill="#e8eaf0">Deploy Staging</text>
<text x="794" y="108" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">Helm · ArgoCD</text>
<text x="794" y="122" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">staging.svc</text>
<!-- Arrow 5->6 -->
<line x1="905" y1="96" x2="950" y2="96" stroke="#f5a623" stroke-width="1.6" marker-end="url(#arrow-fl)" />
<!-- Step 6: E2E + Smoke Tests -->
<rect x="960" y="60" width="120" height="72" rx="12" fill="url(#grad-flow-card)" stroke="#2f3350" stroke-width="1.2" />
<text x="986" y="90" font-family="'Inter',sans-serif" font-size="11" font-weight="600" fill="#e8eaf0">E2E & Smoke</text>
<text x="986" y="108" font-family="'JetBrains Mono',monospace" font-size="8" fill="#6b728c">Cypress · k6</text>
<text x="986" y="122" font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">canary 10%</text>
<!-- Decision after smoke -->
<polygon points="1020,165 1040,185 1020,205 1000,185" fill="#1a1d2e" stroke="#f5a623" stroke-width="1.6" />
<text x="1020" y="189" font-family="'Inter',sans-serif" font-size="9" font-weight="600" fill="#f5a623">OK?</text>
<!-- Pass arrow to production -->
<line x1="1020" y1="205" x2="1020" y2="280" stroke="#7ecf8a" stroke-width="1.6" marker-end="url(#arrow-fl)" />
<text x="1030" y="248" font-family="'Inter',sans-serif" font-size="8" fill="#7ecf8a" opacity="0.8">pass</text>
<!-- Step 7: Deploy to Production (emphasized) -->
<rect x="910" y="290" width="170" height="72" rx="12" fill="#242841" stroke="#f5a623" stroke-width="1.8" />
<rect x="906" y="286" width="178" height="80" rx="16" fill="none" stroke="#f5a623" stroke-width="1.8"
filter="url(#glow-flow)" opacity="0.5" pointer-events="none" />
<use href="#icon-server" x="930" y="306" width="18" height="18" color="#f5a623" />
<text x="958" y="320" font-family="'Inter',sans-serif" font-size="13" font-weight="600" fill="#f5a623">Deploy Production</text>
<text x="958" y="338" font-family="'JetBrains Mono',monospace" font-size="8" fill="#f5a623" opacity="0.7">prod.svc · 100%</text>
<text x="958" y="353" font-family="'Inter',sans-serif" font-size="8" fill="#6b728c">blue/green · auto-rollback</text>
<!-- Fail arrow from smoke back to staging -->
<line x1="980" y1="205" x2="900" y2="185" stroke="#e06c6c" stroke-width="1.2" stroke-dasharray="5 4" fill="none" marker-end="url(#arrow-fl)" opacity="0.5" />
<text x="910" y="178" font-family="'Inter',sans-serif" font-size="7" fill="#e06c6c" opacity="0.6">rollback</text>
<!-- ── QUALITY GATE BADGE ── -->
<rect x="440" y="150" width="130" height="24" rx="6" fill="#1a1d2e" stroke="#2a2d3e" stroke-width="1" />
<text x="460" y="166" font-family="'JetBrains Mono',monospace" font-size="8" fill="#f5a623">⛁ Quality Gate</text>
<!-- ── LEGEND ── -->
<g font-family="'Inter',sans-serif" font-size="8" fill="#4a4f6a">
<rect x="40" y="400" width="10" height="10" rx="3" fill="none" stroke="#2f3350" stroke-width="1.2" />
<text x="58" y="408">Step</text>
<polygon points="190,400 198,408 190,416 182,408" fill="#1a1d2e" stroke="#f5a623" stroke-width="1.2" />
<text x="206" y="408">Decision</text>
<line x1="290" y1="404" x2="305" y2="404" stroke="#e06c6c" stroke-width="1.2" stroke-dasharray="4 3" />
<text x="314" y="408">Fail / rollback</text>
<rect x="420" y="396" width="10" height="10" rx="3" fill="none" stroke="#f5a623" stroke-width="1.8" />
<text x="438" y="408">Emphasized</text>
</g>
<!-- Metadata -->
<text x="1070" y="465" font-family="'JetBrains Mono',monospace" font-size="7" fill="#3d4156" text-anchor="end">
flow · deploy · v3.1
</text>
</svg>
</div>
<!-- ========================================================== -->
<!-- FOOTER -->
<!-- ========================================================== -->
<div class="docs-footer">
<span>◆</span> Tesseron Design System · dark slate + amber · Inter / JetBrains Mono
</div>
</div><!-- /container -->
</body>
</html>
```This page delivers four diagram types — architecture, sequence, state, and flow — each built with the Tesseron visual language. Here's how they work:
document.submit(), onError()), and retry/reset paths use dashed lines for distinction.Each diagram includes a legend, metadata tag, and consistent typography (Inter for labels, JetBrains Mono for code/version strings). The amber accent stays singular – used only for emphasis, active paths, and key nodes – preserving the restrained monochrome-plus-one aesthetic.
---
Optimization Tip: You can replace placeholder text (e.g., "v2.3 · system context", "React · 18.2.0") with your actual version numbers, service names, or status messages.
license: MIT
metadata:
version: "1.1"
author: Tesseron / Kenny Vaneetvelde
based-on: Cocoon-AI/architecture-diagram-generator (methodology)
changelog:
---
生成带有嵌入式 CSS 和内联 SVG 的自包含 HTML 文件,采用 Tesseron 文档美学。
一种强调色,其余全为中性。 彩虹调色板是业余水平的头号标志。强调色(琥珀色)仅用于每张图表中的单个"新颖"或"特色"节点。其他所有节点均为中性石板卡。
---
这些是通过视觉质量保证确立的不可协商的约定。每一条规则的存在都是因为违反它会产生可见的错误。
Smartypants 风格的后处理器(Astro、MDX,以及许多静态站点管道)会静默地将 ' 转换为 '," 转换为 ",... 转换为 …。这些字符随后会被未正确声明 UTF-8 的浏览器错误编码为 ’、“、…。避免整类问题:
'(直撇号),永远不要使用 '。"(直双引号),永远不要使用 " "。...(三个点),永远不要使用 …。-(连字符),永远不要使用 – —。|、, 或 + 作为装饰分隔符,永远不要在文本标签中使用 ·、↔、→。如果宿主框架在构建时启用了 smartypants,请禁用它(例如 Astro:markdown: { smartypants: false })。
<marker>带有 refX、缩放和各种 markerUnits 模式的 <marker> 是持续存在的对齐错误根源:由于 refX 与 viewBox 缩放以及线帽行为的影响,线条描边会持续在箭头尖端之外多渲染一两个像素。完全放弃 markers。 将每个箭头绘制为:
<line>,带有 stroke-linecap="butt",其 x2 恰好是三角形的底边 x 坐标(而非顶点)。<polygon> 作为箭头头部,底边与线条末端对齐,顶点位于实际目标点。线条和多边形在结构上完全无重叠,因此描边物理上无法渲染到尖端之外。
标准箭头(指向右方,尖端位于 TIP_X):
<!-- 箭头尖端在 TIP_X。底边在 TIP_X-10。主体从 x1 延伸到底边。 -->
<line x1="X1" y1="Y" x2="TIP_X-10" y2="Y"
stroke="var(--dgm-line-strong)" stroke-width="1.75" stroke-linecap="butt"/>
<polygon points="TIP_X-10,Y-5 TIP_X,Y TIP_X-10,Y+5"
fill="var(--dgm-line-strong)"/>
对于双向箭头:左侧三角形,然后是两个底边 x 之间的线条,然后是右侧三角形——三个元素,而非一个。
宽度 10,半高 5(因此三角形整体宽 10、高 10)。平衡——既不拉长也不压扁。更大显得笨重,更小显得单薄。
药丸垂直中心 = 箭头 y。药丸宽度 < 间隙宽度,因此每侧留出约 20-30 像素的可见箭头。
rect 位于 y = arrowY - 11,height = 22。text 基线位于 y = arrowY + 4。fill = var(--dgm-pill-bg)(不透明),从而干净地中断下方的线条。stroke = var(--dgm-accent),否则为 var(--dgm-pill-border)。视觉呈现为 ---[ 标签 ]--->,而非线条上方的浮动标签。
图标为 20 × 20,其本地原点在 (0,0)。要在宽度为 w、中心在 cx 的卡片中水平居中:
<g class="dgm-icon" transform="translate(cx - 10, y + 16)"> ... </g>
不要缩放图标(不要使用 scale(1.15))——以保持 1.5 像素描边清晰锐利。
y + 16..36——图标(高 20,水平居中)y + 50——标题(居中,大写,13.5 像素 / 600)y + 74——第一副行(居中,12.5 像素 / 400)y + 90——第二副行(如果为两行副标题)y + 110——等宽代码标识符(如果存在)对于单行副标题 + 代码,将副标题放在 y + 74,代码放在 y + 94。
对于 ~1200 像素画布上的水平 4 卡架构:
pad = 30,card w = 180,gap = 1404 × 180 + 3 × 140 + 2 × 30 = 1200间隙 = 140 是使居中的 88 像素药丸每侧有约 26 像素可见箭头的最小值。
在强调节点后面(尺寸 w × h):
rx = 0.6 × w,ry = 0.7 × hopacity = 0.33stdDeviation = 14较大的 ry(例如 0.95)会导致发光在紧凑的 SVG viewBox 顶部/底部被裁剪。请保持其受控。
width: 100%如果将 SVG 嵌入到 CSS 强制使用 width: 100% 的文档页面中,宽 viewBox 会被缩小,所有字体大小会按比例缩小。要么:
<svg> 上设置与画布尺寸相等的显式 width 和 height 属性;将父容器包裹在 overflow-x: auto 中,使窄视口水平滚动,或者--sl-content-width: 64rem)。永远不要保留 width: 100% + 大 viewBox + 无滚动容器。这就是"文本过小"的 bug。
---
| 令牌 | 浅色模式 | 深色模式 |
|---|---|---|
--dgm-bg-figure | #ffffff | #0b1220 |
--dgm-grid | rgba(148,163,184,0.35) | rgba(51,65,85,0.55) |
--dgm-border | #cbd5e1 | #334155 |
| 令牌 | 浅色模式 | 深色模式 |
|---|---|---|
--dgm-card-neutral-1(顶部) | #ffffff | #172033 |
--dgm-card-neutral-2(底部) | #f1f5f9 | #0f172a |
| 令牌 | 浅色模式 | 深色模式 |
|---|---|---|
--dgm-card-accent-1 | #fffdf7 | #2a1f0a |
--dgm-card-accent-2 | #fef3c7 | #1c1407 |
--dgm-accent-border-1 | #fbbf24 | #fcd34d |
--dgm-accent-border-2 | #d97706 | #d97706 |
--dgm-accent | #f59e0b | #f59e0b |
--dgm-accent-text | #b45309 | #fcd34d |
| 令牌 | 浅色模式 | 深色模式 |
|---|---|---|
--dgm-card-danger-1 | #fef2f2 | #2a0f0f |
--dgm-card-danger-2 | #fee2e2 | #1c0a0a |
--dgm-danger | #dc2626 | #dc2626 |
--dgm-danger-text | #b91c1c | #fca5a5 |
| 令牌 | 浅色模式 | 深色模式 |
|---|---|---|
--dgm-text | #0f172a | #e2e8f0 |
--dgm-text-muted | #475569 | #94a3b8 |
--dgm-line | #94a3b8 | #64748b |
--dgm-line-strong | #64748b | #cbd5e1 |
--dgm-icon | #64748b | #94a3b8 |
| 令牌 | 浅色模式 | 深色模式 |
|---|---|---|
--dgm-pill-bg | #ffffff | #0f172a |
--dgm-pill-border | #e2e8f0 | #334155 |
--dgm-pill-text | #334155 | #cbd5e1 |
Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace| 角色 | 字号 | 字重 | 字母间距 |
|---|---|---|---|
| 卡片标题(大写) | 13.5 px | 600 | 0.08 em |
| 卡片副标题 | 12.5 px | 400 | 0 |
| 卡片代码标识符(等宽) | 11.5 px | 400 | 0 |
| 边缘标签药丸 | 12 px | 500 | 0.02 em |
| 序列参与者标题 | 15 px | 600 | 0.08 em |
| 序列消息标签 | 13 px | 500 | 0.01 em |
| 步骤编号(圆圈内) | 11.5 px | 600 | 0 |
| 注释文本(斜体) | 14 px | 500 | 0 |
每个图标是一组 SVG 路径,位于一个带有 fill="none"、stroke-width="1.5"、stroke-linecap="round"、stroke-linejoin="round" 的组内。描边颜色:中性为 var(--dgm-icon),强调色为 var(--dgm-accent),危险色为 var(--dgm-danger)。
user: <circle cx="10" cy="7" r="3.6"/><path d="M3 20 a7 7 0 0 1 14 0"/>
window: <rect x="1" y="2" width="18" height="16" rx="2"/><path d="M1 6 H19"/>
<circle cx="4" cy="4" r="0.7" fill="currentColor" stroke="none"/>
<circle cx="7" cy="4" r="0.7" fill="currentColor" stroke="none"/>
bridge: <path d="M3 7 H17"/><path d="M14 4 L18 7 L14 10"/>
<path d="M17 13 H3"/><path d="M6 10 L2 13 L6 16"/>
agent: <path d="M10 1.5 L12 8 L18.5 10 L12 12 L10 18.5 L8 12 L1.5 10 L8 8 Z"/>
shield: <path d="M10 2 L17 5 V10 C17 14 14 17 10 19 C6 17 3 14 3 10 V5 Z"/>
lock: <rect x="3" y="9" width="14" height="10" rx="2"/>
<path d="M6 9 V6 a4 4 0 0 1 8 0 V9"/>
cube: <path d="M10 2 L18 6 V14 L10 18 L2 14 V6 Z"/>
<path d="M2 6 L10 10 L18 6"/><path d="M10 10 V18"/>
packages: <rect x="1.5" y="1.5" width="7" height="7" rx="1"/>
<rect x="11.5" y="1.5" width="7" height="7" rx="1"/>
<rect x="6.5" y="11.5" width="7" height="7" rx="1"/>
server: <rect x="2" y="3" width="16" height="6" rx="1.5"/>
<rect x="2" y="11" width="16" height="6" rx="1.5"/>
<circle cx="6" cy="6" r="0.7" fill="currentColor" stroke="none"/>
<circle cx="6" cy="14" r="0.7" fill="currentColor" stroke="none"/>
database: <ellipse cx="10" cy="4" rx="8" ry="2.2"/>
<path d="M2 4 V16 a8 2.2 0 0 0 16 0 V4"/>
<path d="M2 10 a8 2.2 0 0 0 16 0"/>
放置在卡片中(卡片中心 cx,卡片顶部 y):
<g class="dgm-icon" transform="translate(cx - 10, y + 16)"> ... </g>
点状网格(首先绘制,覆盖整个画布):
<pattern id="dgm-dots" width="22" height="22" patternUnits="userSpaceOnUse">
<circle cx="1.2" cy="1.2" r="1.2" fill="var(--dgm-grid)"/>
</pattern>
<rect width="100%" height="100%" fill="url(#dgm-dots)"/>
卡片填充渐变(微妙的顶部到底部):
<linearGradient id="dgm-card-neutral" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="var(--dgm-card-neutral-1)"/>
<stop offset="1" stop-color="var(--dgm-card-neutral-2)"/>
</linearGradient>
强调边框渐变:
<linearGradient id="dgm-border-accent" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="var(--dgm-accent-border-1)"/>
<stop offset="1" stop-color="var(--dgm-accent-border-2)"/>
</linearGradient>
强调发光滤镜(作为单独的 <ellipse> 绘制在强调卡片后方):
<filter id="dgm-glow-accent" x="-30%" y="-60%" width="160%" height="220%">
<feGaussianBlur stdDeviation="14" result="b"/>
<feColorMatrix in="b" type="matrix"
values="0 0 0 0 0.98 0 0 0 0 0.73 0 0 0 0 0.14 0 0 0 0.45 0"/>
</filter>
<ellipse cx="CARD_CX" cy="CARD_CY"
rx="CARD_W*0.6" ry="CARD_H*0.7"
fill="var(--dgm-accent)" filter="url(#dgm-glow-accent)" opacity="0.33"/>
卡片投影(两层叠加的 feDropShadow——没有 90 年代斜面效果):
<filter id="dgm-shadow" x="-10%" y="-10%" width="120%" height="130%">
<feDropShadow dx="0" dy="4" stdDeviation="6"
flood-color="var(--dgm-shadow-color)" flood-opacity="0.06"/>
<feDropShadow dx="0" dy="1" stdDeviation="1.5"
flood-color="var(--dgm-shadow-color)" flood-opacity="0.04"/>
</filter>
中性:
<rect x="X" y="Y" width="W" height="H" rx="14"
fill="url(#dgm-card-neutral)" stroke="var(--dgm-border)" stroke-width="1.25"
filter="url(#dgm-shadow)"/>
强调(渐变边框):
<rect x="X" y="Y" width="W" height="H" rx="14"
fill="url(#dgm-card-accent)" stroke="url(#dgm-border-accent)" stroke-width="1.25"
filter="url(#dgm-shadow)"/>
完整卡片(强调)带居中图标 + 标题 + 副标题 + 代码:
<g>
<rect x="670" y="90" width="180" height="120" rx="14"
fill="url(#dgm-card-accent)" stroke="url(#dgm-border-accent)" stroke-width="1.25"
filter="url(#dgm-shadow)"/>
<g class="dgm-icon dgm-icon-accent" transform="translate(750,106)"> ... </g>
<text x="760" y="150" text-anchor="middle" class="dgm-title dgm-title-accent">GATEWAY</text>
<text x="760" y="174" text-anchor="middle" class="dgm-sub dgm-sub-accent">WebSocket + MCP 桥接</text>
<text x="760" y="194" text-anchor="middle" class="dgm-code dgm-code-accent">@tesseron/mcp :7475</text>
</g>
从 (x1=216, y=150) 到尖端位于 (x=344, y=150) 的箭头,强调色:
<line x1="216" y1="150" x2="334" y2="150"
stroke="var(--dgm-accent)" stroke-width="1.75" stroke-linecap="butt"/>
<polygon points="334,145 344,150 334,155" fill="var(--dgm-accent)"/>
在 TIP_LEFT=536 和 TIP_RIGHT=664 之间的双向箭头:
<polygon points="546,145 536,150 546,155" fill="var(--dgm-accent)"/>
<line x1="546" y1="150" x2="654" y2="150"
stroke="var(--dgm-accent)" stroke-width="1.75" stroke-linecap="butt"/>
<polygon points="654,145 664,150 654,155" fill="var(--dgm-accent)"/>
边缘药丸(居中位于箭头 y=150 上的 MID_X=600):
<rect x="556" y="139" width="88" height="22" rx="7"
fill="var(--dgm-pill-bg)" stroke="var(--dgm-accent)" stroke-width="1"/>
<text x="600" y="154" text-anchor="middle" class="dgm-lbl dgm-lbl-accent">WebSocket</text>
画布 1200 × 310,节点中线 y=150:
| 节点 | x | 宽度 | 中心 x |
|---|---|---|---|
| 0 | 30 | 180 | 120 |
| 1 | 350 | 180 | 440 |
| 2 | 670 | 180 | 760 |
| 3 | 990 | 180 | 1080 |
箭头尖端位于卡片边缘:对于节点 0→1,线条为 x1 = 216, tip = 344(在居中于 x = 280 的 88 像素药丸两侧各留出 30 像素的箭头)。
相同的设计令牌,不同的布局:
stroke="var(--dgm-line)" stroke-width="1.25" stroke-dasharray="3 5" opacity="0.6"。<line> + <polygon> 箭头。标签药丸居中在箭头上。生成一个单一的自包含 .html 文件,包含:
<style> 中的嵌入式 CSS。@media (prefers-color-scheme: dark) 支持浅色和深色两种调色板。一个可直接定制的模板位于 assets/template.html。它包含了所有 <defs>、浅色+深色的 CSS 自定义属性、图表下方的三卡摘要,以及一个带有工作边缘的示例节点对。复制并填充内容。
一个完整实现的 4 节点架构示例位于 examples/architecture.html。
<marker> 的箭头。 无休止的 refX/线帽对齐错误。始终使用线 + 多边形。---[ 标签 ]--->。dy > 4 或 opacity > 0.1。 硬阴影看起来像 90 年代斜面。scale(1.15))——1.5 像素的描边会变模糊。以 20 × 20 原生尺寸绘制图标。’。width: 100% 且无水平滚动。 会破坏文本可读性。coleam00/excalidraw-diagram-skill。