<svg width="100%" viewBox="0 0 1000 540" role="img" xmlns="http://www.w3.org/2000/svg">
  <title>Telemetry funnel — every source converges on one table and one log store</title>
  <desc>Edge, voice-bridge, hermes plugins, and the LiveKit webhook all POST to ingest endpoints on sudo-api; sudo-api also writes directly. All rows land in public.telemetry_events; container logs go to Loki; Grafana reads both.</desc>
  <style>
    text{font-family:"Anthropic Sans",-apple-system,system-ui,"Segoe UI",sans-serif}
    .t{font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:central}
    .s{font-size:12px;text-anchor:middle;dominant-baseline:central}
    .lbl{font-size:11px;fill:#9c9a92;text-anchor:middle}
    .hdr{font-size:13px;font-weight:500;fill:#c2c0b6}
    rect{stroke-width:.5}
    .zone{fill:none;stroke:#5a5852;stroke-width:.5;stroke-dasharray:5 4;opacity:.6}
    .green{fill:#27500a;stroke:#97c459}   .gt{fill:#c0dd97} .gs{fill:#97c459}
    .blue{fill:#1f3b7a;stroke:#8aaef0}    .bt{fill:#cfdcf4} .bs{fill:#8aaef0}
    .orange{fill:#712b13;stroke:#f0997b}  .ot{fill:#f5c4b3} .os{fill:#f0997b}
    .teal{fill:#085041;stroke:#5dcaa5}    .tt{fill:#9fe1cb} .ts{fill:#5dcaa5}
    .purple{fill:#3c3489;stroke:#afa9ec}  .pt{fill:#ceccf6} .ps{fill:#afa9ec}
    .arrow{fill:none;stroke:#9c9a92;stroke-width:1.5}
    .arrow-ok{fill:none;stroke:#1d9e75;stroke-width:1.5}
  </style>
  <defs>
    <marker id="a" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
    </marker>
  </defs>

  <rect class="zone" x="20" y="40" width="280" height="460" rx="12"/>
  <text class="hdr" x="40" y="62">Sources</text>

  <rect class="green"  x="40"  y="80"  width="240" height="50" rx="8"/>
  <text class="t gt" x="160" y="106">Pi (sudoedge)</text>

  <rect class="blue"   x="40"  y="150" width="240" height="50" rx="8"/>
  <text class="t bt" x="160" y="176">voice-bridge</text>

  <rect class="orange" x="40"  y="220" width="240" height="50" rx="8"/>
  <text class="t ot" x="160" y="246">hermes plugins</text>

  <rect class="blue"   x="40"  y="290" width="240" height="50" rx="8"/>
  <text class="t bt" x="160" y="316">livekit webhook</text>

  <rect class="blue"   x="40"  y="360" width="240" height="50" rx="8"/>
  <text class="t bt" x="160" y="386">sudo-api (direct)</text>

  <rect class="blue"   x="40"  y="430" width="240" height="50" rx="8"/>
  <text class="t bt" x="160" y="456">all container stdouts</text>

  <rect class="zone" x="340" y="40" width="320" height="460" rx="12"/>
  <text class="hdr" x="360" y="62">Ingest</text>

  <rect class="blue" x="360" y="100" width="280" height="80" rx="8"/>
  <text class="t bt" x="500" y="124">/v1/internal/telemetry</text>
  <text class="s bs" x="500" y="146">bearer-gated</text>
  <text class="s bs" x="500" y="164">voice-bridge · plugins · LiveKit</text>

  <rect class="blue" x="360" y="210" width="280" height="80" rx="8"/>
  <text class="t bt" x="500" y="234">/v1/me/telemetry</text>
  <text class="s bs" x="500" y="256">device-JWT-gated</text>
  <text class="s bs" x="500" y="274">user_id/device_id forced from token</text>

  <rect class="blue" x="360" y="320" width="280" height="60" rx="8"/>
  <text class="t bt" x="500" y="344">record_event · record_bg</text>
  <text class="s bs" x="500" y="362">direct DB write</text>

  <rect class="blue" x="360" y="410" width="280" height="60" rx="8"/>
  <text class="t bt" x="500" y="434">promtail (docker socket)</text>
  <text class="s bs" x="500" y="452">ships stdouts to Loki</text>

  <rect class="zone" x="700" y="40" width="280" height="460" rx="12"/>
  <text class="hdr" x="720" y="62">Storage  +  dashboards</text>

  <rect class="teal" x="720" y="100" width="240" height="120" rx="8"/>
  <text class="t tt" x="840" y="128">public.telemetry_events</text>
  <text class="s ts" x="840" y="154">one row per stage</text>
  <text class="s ts" x="840" y="172">turn_id · surface · source</text>
  <text class="s ts" x="840" y="190">stage · latency_ms · meta</text>

  <rect class="teal" x="720" y="240" width="240" height="80" rx="8"/>
  <text class="t tt" x="840" y="264">Loki</text>
  <text class="s ts" x="840" y="286">container logs</text>
  <text class="s ts" x="840" y="304">7-day retention</text>

  <rect class="purple" x="720" y="350" width="240" height="120" rx="8"/>
  <text class="t pt" x="840" y="378">Grafana</text>
  <text class="s ps" x="840" y="404">grafana.sudohomes.com</text>
  <text class="s ps" x="840" y="424">turn-funnel dashboard</text>
  <text class="s ps" x="840" y="442">fleet-health dashboard</text>
  <text class="s ps" x="840" y="460">+ Sentry on crashes</text>

  <path class="arrow" d="M 280 105 L 358 140" marker-end="url(#a)"/>
  <path class="arrow" d="M 280 175 L 358 150" marker-end="url(#a)"/>
  <path class="arrow" d="M 280 245 L 358 160" marker-end="url(#a)"/>
  <path class="arrow" d="M 280 315 L 358 170" marker-end="url(#a)"/>
  <path class="arrow" d="M 280  95 L 358 240" marker-end="url(#a)"/>
  <path class="arrow" d="M 280 385 L 358 350" marker-end="url(#a)"/>
  <path class="arrow" d="M 280 455 L 358 440" marker-end="url(#a)"/>

  <path class="arrow-ok" d="M 640 140 L 718 150" marker-end="url(#a)"/>
  <path class="arrow-ok" d="M 640 250 L 718 165" marker-end="url(#a)"/>
  <path class="arrow-ok" d="M 640 350 L 718 180" marker-end="url(#a)"/>
  <path class="arrow-ok" d="M 640 440 L 718 280" marker-end="url(#a)"/>

  <path class="arrow"    d="M 840 220 L 840 348" marker-end="url(#a)"/>
  <path class="arrow"    d="M 840 320 L 840 348" marker-end="url(#a)"/>
</svg>
