[object Object]

← back to Homesonspec

feat: live V8 'engine room' dashboard (:9798) — pistons/crank/belt driven by real DB throughput

70807442b6f32278bcb1f069bef64479871e6b15 · 2026-07-28 09:03:25 -0700 · Steve

Files touched

Diff

commit 70807442b6f32278bcb1f069bef64479871e6b15
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Jul 28 09:03:25 2026 -0700

    feat: live V8 'engine room' dashboard (:9798) — pistons/crank/belt driven by real DB throughput
---
 scripts/engine-dashboard.mjs | 156 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 156 insertions(+)

diff --git a/scripts/engine-dashboard.mjs b/scripts/engine-dashboard.mjs
new file mode 100644
index 0000000..8f2f1e1
--- /dev/null
+++ b/scripts/engine-dashboard.mjs
@@ -0,0 +1,156 @@
+// HomesOnSpec "engine room" — a live Corvette V8 whose moving parts are driven by
+// REAL data throughput (homes + permits landing, geocoding, enrichment). Zero-dep
+// (Node http + psql + pgrep). Run: node scripts/engine-dashboard.mjs  (PORT, default 9797)
+import { createServer } from "node:http";
+import { execFile } from "node:child_process";
+
+const DBURL = "postgresql://macstudio3@localhost/homesonspec?host=/tmp";
+const PORT = Number(process.env.PORT || 9797);
+const sh = (cmd, args) => new Promise((r) => execFile(cmd, args, { maxBuffer: 8 << 20 }, (e, o) => r(e ? "" : o.trim())));
+const q = (sql) => sh("psql", [DBURL, "-tAc", sql]);
+
+let prev = null, prevT = 0, smooth = 0;
+
+async function stats() {
+  const row = await q(`select json_build_object(
+    'homes',(select count(*) from "InventoryHome" where status='PUBLISHED'),
+    'builders',(select count(distinct "builderId") from "InventoryHome" where status='PUBLISHED'),
+    'communities',(select count(*) from "Community"),
+    'enriched',(select count(*) from "Community" where amenities is not null),
+    'permits',(select count(*) from building_permits),
+    'permits_geo',(select count(*) from building_permits where lat is not null)
+  )`);
+  let s; try { s = JSON.parse(row); } catch { s = { homes:0,builders:0,communities:0,enriched:0,permits:0,permits_geo:0 }; }
+  const now = Date.now();
+  const dt = prev ? Math.max(1, (now - prevT) / 1000) : 1;
+  const d = (k) => prev ? Math.max(0, (s[k] - prev[k]) / dt) : 0; // per-second
+  const rates = { homes: d("homes"), permits: d("permits"), geo: d("permits_geo") + Math.max(0,(prev?d("permits_geo"):0)), enrich: d("enriched") };
+  const geoRate = prev ? Math.max(0, (s.permits_geo - prev.permits_geo) / dt) : 0;
+  const totalRate = rates.homes + rates.permits + geoRate + rates.enrich;
+  prev = s; prevT = now;
+  // procs
+  const procs = await sh("bash", ["-lc", "pgrep -fl 'build-loop.sh|ingest-permits|geocode-permits|enrich-nearby' 2>/dev/null | wc -l"]);
+  const workers = Number(procs) || 0;
+  // smooth throughput so a burst sustains the revs (decays ~40%/poll) — an engine
+  // with active workers idles high (running), and pulses up on each commit burst.
+  smooth = Math.max(totalRate, smooth * 0.62);
+  const rpm = Math.min(7200, Math.round(750 + (workers > 0 ? 720 : 0) + smooth * 210));
+  return { ...s, rates: { homes: rates.homes, permits: rates.permits, geo: geoRate, enrich: rates.enrich }, totalRate: smooth, rpm, workers };
+}
+
+const PAGE = `<!doctype html><html><head><meta charset=utf8><title>HomesOnSpec · V8</title>
+<meta name=viewport content="width=device-width,initial-scale=1">
+<style>
+:root{--red:#e01b1b;--amber:#ffb020;--grn:#2dd4bf;--ink:#e9eef2;--stroke:.5s}
+*{box-sizing:border-box}html,body{margin:0;height:100%;background:radial-gradient(1200px 700px at 50% -10%,#141a20,#080a0c);color:var(--ink);font:13px/1.4 ui-monospace,Menlo,monospace;overflow:hidden}
+.hd{display:flex;justify-content:space-between;align-items:center;padding:12px 20px;border-bottom:1px solid #1c262e}
+.hd h1{margin:0;font:700 17px system-ui;letter-spacing:.5px}.hd .sub{color:#7f97a3;font-size:11px}
+.badge{color:var(--red);font-weight:700}
+.stage{display:grid;grid-template-columns:1fr 320px;gap:18px;padding:16px 20px;height:calc(100% - 52px)}
+.enginewrap{display:flex;align-items:center;justify-content:center}
+svg{width:100%;height:100%;max-height:78vh}
+.cyl{fill:#0e151a;stroke:#28343d}
+.piston{fill:url(#pist);}
+.rod{stroke:#5a6b76;stroke-width:5}
+.bank{}
+@keyframes stroke{0%{transform:translateY(0)}50%{transform:translateY(58px)}100%{transform:translateY(0)}}
+@keyframes spin{to{transform:rotate(360deg)}}
+@keyframes belt{to{stroke-dashoffset:-40}}
+.pg{animation:stroke var(--stroke) linear infinite}
+.crank{transform-origin:center;animation:spin var(--stroke) linear infinite}
+.belt{stroke-dasharray:6 6;animation:belt var(--stroke) linear infinite}
+.spark{opacity:.15}
+.panel{display:flex;flex-direction:column;gap:12px}
+.gauge{background:#0d141a;border:1px solid #1e2a32;border-radius:12px;padding:12px 14px}
+.gauge .k{color:#7f97a3;font-size:10px;text-transform:uppercase;letter-spacing:1px}
+.gauge .v{font:800 26px system-ui;margin-top:2px}
+.gauge .d{color:var(--grn);font-size:11px}
+.tach{position:relative;text-align:center}
+.rpmv{font:900 40px system-ui;color:var(--red);text-shadow:0 0 18px rgba(224,27,27,.5)}
+.rpml{color:#7f97a3;font-size:10px;letter-spacing:2px}
+.leds{display:flex;gap:8px;margin-top:6px;flex-wrap:wrap}
+.led{display:flex;align-items:center;gap:5px;font-size:10px;color:#8aa}
+.dot{width:9px;height:9px;border-radius:50%;background:#33424c;box-shadow:0 0 0 rgba(45,212,191,0)}
+.dot.on{background:var(--grn);box-shadow:0 0 10px var(--grn)}
+.dot.hot{background:var(--amber);box-shadow:0 0 10px var(--amber)}
+.foot{color:#5f7684;font-size:10px;text-align:center;margin-top:2px}
+</style></head><body>
+<div class=hd><div><h1>HOMESONSPEC <span class=badge>V8</span> ENGINE ROOM</h1><div class=sub>pistons fire at the real rate data lands · corvette-spec</div></div>
+<div class=sub id=work>workers: –</div></div>
+<div class=stage>
+ <div class=enginewrap>
+  <svg viewBox="0 0 620 520" id=eng>
+   <defs>
+     <linearGradient id=pist x1=0 y1=0 x2=0 y2=1><stop offset=0 stop-color=#cfd8de /><stop offset=1 stop-color=#8996a0 /></linearGradient>
+     <radialGradient id=pulley><stop offset=0 stop-color=#3a4650 /><stop offset=1 stop-color=#141a1f /></radialGradient>
+   </defs>
+   <!-- block -->
+   <rect x=70 y=70 width=480 height=300 rx=14 fill=#0c1216 stroke=#222d35 />
+   <text x=310 y=58 fill=#5f7684 font-size=12 text-anchor=middle letter-spacing=3>V8 · 8 LIVE DATA STREAMS</text>
+   <g id=cyls></g>
+   <!-- crank pulley -->
+   <g class=crank id=crank><circle cx=310 cy=430 r=52 fill=url(#pulley) stroke=#2a353d stroke-width=4 />
+     <circle cx=310 cy=430 r=8 fill=#e01b1b /><rect x=305 y=380 width=10 height=48 fill=#3a4650 /></g>
+   <!-- serpentine belt -->
+   <path class=belt d="M258 430 A52 52 0 1 1 362 430" fill=none stroke=#556 stroke-width=4 />
+   <circle class=crank cx=470 cy=430 r=26 fill=url(#pulley) stroke=#2a353d stroke-width=3 />
+   <path class=belt d="M362 430 A52 52 0 0 0 258 430 M258 430 L444 430" fill=none stroke=#4a5a64 stroke-width=3 opacity=.6 />
+  </svg>
+ </div>
+ <div class=panel>
+  <div class=gauge tach><div class=rpml>ENGINE RPM · THROUGHPUT</div><div class=rpmv id=rpm>—</div><div class=d id=rate></div></div>
+  <div class=gauge><div class=k>Listed homes</div><div class=v id=homes>—</div><div class=d id=hd></div></div>
+  <div class=gauge><div class=k>Building permits</div><div class=v id=permits>—</div><div class=d id=pd></div></div>
+  <div class=gauge><div class=k>Permits geocoded</div><div class=v id=geo>—</div><div class=d id=gd></div></div>
+  <div class=gauge><div class=k>Builders · communities enriched</div><div class=v id=misc>—</div></div>
+  <div class=leds id=leds></div>
+  <div class=foot id=stamp></div>
+ </div>
+</div>
+<script>
+// 8 cylinders in a V (4 per bank), each = a data stream
+const STREAMS=["Lennar","DR Horton","Pulte","Tri Pointe","Permits","Geocode","Enrich","Discovery"];
+const cyls=document.getElementById('cyls');let g='';
+for(let i=0;i<8;i++){const bank=i<4?0:1;const idx=i%4;const x=120+idx*105;const yTop=bank?250:95;const skew=bank?18:-18;
+ g+='<g transform="translate('+x+','+yTop+') skewX('+skew/6+')">'
+  +'<rect class=cyl x=-26 y=0 width=52 height=90 rx=6 />'
+  +'<rect class="piston pg" id="p'+i+'" x=-22 y=6 width=44 height=30 rx=4 style="animation-delay:'+(i*0.09)+'s"/>'
+  +'<text x=0 y=-8 fill=#6c828e font-size=9 text-anchor=middle>'+STREAMS[i]+'</text>'
+  +'<circle class=spark cx=0 cy=2 r=6 fill=#ffcf5a id="s'+i+'"/></g>';
+}
+cyls.innerHTML=g;
+const fmt=n=>Number(n).toLocaleString();
+function setDur(rpm){const dur=Math.max(0.09,60/Math.max(300,rpm)).toFixed(3)+'s';document.documentElement.style.setProperty('--stroke',dur);}
+async function tick(){
+ let s;try{s=await fetch('/api/stats').then(r=>r.json())}catch(e){return}
+ document.getElementById('rpm').textContent=fmt(s.rpm);
+ setDur(s.rpm);
+ document.getElementById('rate').textContent=(s.totalRate>0?('▲ '+s.totalRate.toFixed(1)+' records/sec'):'idle');
+ document.getElementById('homes').textContent=fmt(s.homes);
+ document.getElementById('permits').textContent=fmt(s.permits);
+ document.getElementById('geo').textContent=fmt(s.permits_geo);
+ document.getElementById('misc').textContent=fmt(s.builders)+' · '+fmt(s.enriched);
+ const d=(x)=>x>0?('+'+x.toFixed(1)+'/s'):'';
+ document.getElementById('hd').textContent=d(s.rates.homes);
+ document.getElementById('pd').textContent=d(s.rates.permits);
+ document.getElementById('gd').textContent=d(s.rates.geo);
+ document.getElementById('work').textContent='workers: '+s.workers;
+ // spark flashes scale with rpm
+ for(let i=0;i<8;i++){const sp=document.getElementById('s'+i);sp.style.opacity=s.rpm>1400?0.9:0.12;}
+ // leds
+ const active=s.totalRate>0.2;
+ document.getElementById('leds').innerHTML=
+  '<div class=led><span class="dot '+(active?'on':'')+'"></span>INGEST</div>'
+ +'<div class=led><span class="dot '+(s.rates.geo>0?'on':'')+'"></span>GEOCODE</div>'
+ +'<div class=led><span class="dot '+(s.workers>0?'on':'hot')+'"></span>WORKERS '+s.workers+'</div>'
+ +'<div class=led><span class="dot '+(s.rpm>1200?'hot':'on')+'"></span>'+(s.rpm>1200?'REDLINE':'CRUISE')+'</div>';
+ document.getElementById('stamp').textContent=new Date().toLocaleTimeString()+' · '+fmt(s.homes+s.permits)+' total records under the hood';
+}
+tick();setInterval(tick,2500);
+</script></body></html>`;
+
+const server = createServer(async (req, res) => {
+  if (req.url === "/api/stats") { res.setHeader("content-type", "application/json"); return res.end(JSON.stringify(await stats())); }
+  res.setHeader("content-type", "text/html"); res.end(PAGE);
+});
+server.listen(PORT, () => console.log(`engine-dashboard on http://127.0.0.1:${PORT}`));

← c9a3fdf admin/ingestion: guard sparkline last-value (TS strict index  ·  back to Homesonspec  ·  engine: per-stream liveness — each cylinder fires only when 5aea788 →