[object Object]

← back to Macstudio1 Dashboard

feat: self-healing version check — dashboard auto-reloads on new build

729b4e14d315cd0300d18b1cc06cb2749fe5bc5d · 2026-05-08 00:04:06 -0700 · SteveStudio2

Server hashes public/index.html on boot + on file change (fs.watch).
Front-end polls /api/version every 5s; when the hash changes from
its loaded version, shows a brass-colored "New build deployed —
reloading..." banner and force-reloads after 2s.

Removes the constant "browser cached the old page" friction. Now
when I deploy a feature, the dashboard self-refreshes within 5 seconds
and Steve sees the new sections immediately without manual reload.

API:
  GET /api/version    {version: <sha1[0:10]>, ts}

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 729b4e14d315cd0300d18b1cc06cb2749fe5bc5d
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date:   Fri May 8 00:04:06 2026 -0700

    feat: self-healing version check — dashboard auto-reloads on new build
    
    Server hashes public/index.html on boot + on file change (fs.watch).
    Front-end polls /api/version every 5s; when the hash changes from
    its loaded version, shows a brass-colored "New build deployed —
    reloading..." banner and force-reloads after 2s.
    
    Removes the constant "browser cached the old page" friction. Now
    when I deploy a feature, the dashboard self-refreshes within 5 seconds
    and Steve sees the new sections immediately without manual reload.
    
    API:
      GET /api/version    {version: <sha1[0:10]>, ts}
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 public/index.html | 24 ++++++++++++++++++++++++
 server.js         | 15 +++++++++++++++
 2 files changed, 39 insertions(+)

diff --git a/public/index.html b/public/index.html
index 5bb3cf8..5e9c9b1 100644
--- a/public/index.html
+++ b/public/index.html
@@ -980,6 +980,30 @@ async function tickLog() {
 }
 tickLog();
 setInterval(tickLog, 3000);
+
+// ─── Self-healing version watch — auto-reload if server has new HTML ────
+let LOADED_VERSION = null;
+async function checkVersion() {
+  try {
+    const r = await fetch('/api/version').then(r => r.json());
+    if (LOADED_VERSION === null) {
+      LOADED_VERSION = r.version;
+      console.log('[dashboard] loaded version', LOADED_VERSION);
+      return;
+    }
+    if (r.version && r.version !== LOADED_VERSION) {
+      console.log('[dashboard] new version', r.version, '— reloading in 2s');
+      // Brief flash so Steve sees a deploy happened
+      const banner = document.createElement('div');
+      banner.textContent = 'New build deployed · reloading…';
+      banner.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:9999;background:#d4b683;color:#0a0a0c;font-family:JetBrains Mono,monospace;font-weight:600;font-size:13px;letter-spacing:.18em;text-align:center;padding:14px;box-shadow:0 4px 12px rgba(0,0,0,0.6);text-transform:uppercase';
+      document.body.appendChild(banner);
+      setTimeout(() => { location.reload(true); }, 2000);
+    }
+  } catch (e) { /* network blip */ }
+}
+checkVersion();
+setInterval(checkVersion, 5000);
 </script>
 
 </body>
diff --git a/server.js b/server.js
index a268dfb..7cc2fe6 100644
--- a/server.js
+++ b/server.js
@@ -288,6 +288,21 @@ app.get('/api/ollama/log', async (req, res) => {
   }
 });
 
+// Server-side build version — hash of public/index.html. Polling clients
+// compare to their loaded copy and force-reload when it changes.
+const crypto = require('node:crypto');
+let _buildVersion = '';
+function computeBuildVersion() {
+  try {
+    const html = fs.readFileSync(path.join(__dirname, 'public', 'index.html'), 'utf8');
+    _buildVersion = crypto.createHash('sha1').update(html).digest('hex').slice(0, 10);
+  } catch { _buildVersion = 'unknown'; }
+  return _buildVersion;
+}
+computeBuildVersion();
+fs.watch(path.join(__dirname, 'public'), { recursive: true }, () => computeBuildVersion());
+app.get('/api/version', (_req, res) => res.json({ version: _buildVersion, ts: Date.now() }));
+
 app.get('/api/health', (_req, res) => res.json({ ok: true, ts: Date.now() }));
 
 app.listen(PORT, '0.0.0.0', () => {

← 29b1797 chore: build version stamp + scroll hint at top of dashboard  ·  back to Macstudio1 Dashboard  ·  feat: viewer counter on dashboard odometer — see if browser 19f97af →