[object Object]

← back to Wallco Ai

/admin/health: extended JSON w/ by-color cache stats (hits/misses/evictions/hit_rate) + uptime + rss

01a41fa031ef33615773b917ab60f02b0d893468 · 2026-05-12 19:53:03 -0700 · SteveStudio2

Files touched

Diff

commit 01a41fa031ef33615773b917ab60f02b0d893468
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date:   Tue May 12 19:53:03 2026 -0700

    /admin/health: extended JSON w/ by-color cache stats (hits/misses/evictions/hit_rate) + uptime + rss
---
 server.js | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/server.js b/server.js
index 5a7f882..f249181 100644
--- a/server.js
+++ b/server.js
@@ -394,6 +394,7 @@ const _BY_COLOR_TTL_MS = 300_000;
 const _BY_COLOR_MAX = 1000;
 const _byColorCache = new Map();   // key -> { body, expiresAt }
 let   _byColorCacheVer = 0;        // bump to invalidate
+const _byColorStats = { hits: 0, misses: 0, evictions: 0, since: Date.now() };
 app.get('/api/designs/by-color', (req, res) => {
   const hex = String(req.query.hex || '').trim();
   const n = Math.max(1, Math.min(50, parseInt(req.query.n || '12', 10)));
@@ -409,11 +410,13 @@ app.get('/api/designs/by-color', (req, res) => {
   const now = Date.now();
   const hit = _byColorCache.get(cacheKey);
   if (hit && hit.expiresAt > now) {
+    _byColorStats.hits++;
     res.setHeader('Cache-Control', 'public, max-age=300, must-revalidate');
     res.setHeader('X-Cache', 'HIT');
     return res.json(hit.body);
   }
   if (hit) _byColorCache.delete(cacheKey);   // expired — drop before recompute
+  _byColorStats.misses++;
   const ranked = [];
   for (const d of DESIGNS) {
     if (exclude.has(d.id)) continue;
@@ -428,7 +431,7 @@ app.get('/api/designs/by-color', (req, res) => {
   // FIFO evict if full. Map preserves insertion order, so the first key is the oldest.
   if (_byColorCache.size >= _BY_COLOR_MAX) {
     const firstKey = _byColorCache.keys().next().value;
-    if (firstKey !== undefined) _byColorCache.delete(firstKey);
+    if (firstKey !== undefined) { _byColorCache.delete(firstKey); _byColorStats.evictions++; }
   }
   _byColorCache.set(cacheKey, { body, expiresAt: now + _BY_COLOR_TTL_MS });
   res.setHeader('Cache-Control', 'public, max-age=300, must-revalidate');
@@ -10117,6 +10120,34 @@ app.get('/health', (_req, res) => {
   res.json({ ok: true, site: SITE, count: DESIGNS.length, port: PORT });
 });
 
+// ── /admin/health — admin-gated extended health + by-color cache stats. Useful to
+// confirm the in-process ΔE cache is actually serving HITs and that eviction is bounded.
+// 404 (not 401/403) on non-admin so we don't leak the endpoint's existence.
+app.get('/admin/health', (req, res) => {
+  if (!isAdmin(req)) return res.status(404).type('html').send('<h1>404</h1>');
+  const total = _byColorStats.hits + _byColorStats.misses;
+  res.setHeader('Cache-Control', 'no-store');
+  res.json({
+    ok: true,
+    site: SITE,
+    port: PORT,
+    designs: DESIGNS.length,
+    uptime_s: Math.round(process.uptime()),
+    rss_mb: Math.round(process.memoryUsage().rss / 1048576),
+    by_color_cache: {
+      size: _byColorCache.size,
+      max: _BY_COLOR_MAX,
+      ttl_ms: _BY_COLOR_TTL_MS,
+      ver: _byColorCacheVer,
+      hits: _byColorStats.hits,
+      misses: _byColorStats.misses,
+      evictions: _byColorStats.evictions,
+      hit_rate: total > 0 ? Math.round((_byColorStats.hits / total) * 1000) / 10 : null,
+      since: new Date(_byColorStats.since).toISOString(),
+    },
+  });
+});
+
 // ── DEV LOGIN — sets dw_auth HS256 cookie for admin layer + inline editor (dev mode only)
 const __crypto = require('crypto');
 function __b64u(s) { return Buffer.from(s).toString('base64').replace(/=+$/,'').replace(/\+/g,'-').replace(/\//g,'_'); }

← 1370963 drunk-animals: /drunk-animals friendly URL → 302 to /designs  ·  back to Wallco Ai  ·  /api/designs/random: ETag + 304 on seeded calls (determinist 4f0ff5e →