[object Object]

← back to Wallco Ai

/api/designs/random: ETag + 304 on seeded calls (deterministic given seed+state) — unseeded stays no-store

4f0ff5ec812eb781463afd5430c469eeb77a3255 · 2026-05-12 19:57:44 -0700 · SteveStudio2

Files touched

Diff

commit 4f0ff5ec812eb781463afd5430c469eeb77a3255
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date:   Tue May 12 19:57:44 2026 -0700

    /api/designs/random: ETag + 304 on seeded calls (deterministic given seed+state) — unseeded stays no-store
---
 server.js | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/server.js b/server.js
index f249181..2bf03a7 100644
--- a/server.js
+++ b/server.js
@@ -483,7 +483,18 @@ app.get('/api/designs/random', (req, res) => {
       url: `/design/${d.id}`,
     });
   }
-  res.setHeader('Cache-Control', 'no-store');
+  // Seeded calls are deterministic given (n, category, seed, DESIGNS state) — make them
+  // cacheable via ETag so a trade-user rail can poll without paying the shuffle cost.
+  // Unseeded calls stay no-store because the whole point is fresh randomness.
+  if (seedRaw !== undefined && seedRaw !== '') {
+    const etag = `"rand-${CATALOG_LAST_MODIFIED.getTime()}-${k}-${category || 'all'}-${parseInt(seedRaw,10)}-${pool.length}"`;
+    res.setHeader('ETag', etag);
+    res.setHeader('Cache-Control', 'private, max-age=0, must-revalidate');
+    const inm = req.headers['if-none-match'];
+    if (inm && inm === etag) return res.status(304).end();
+  } else {
+    res.setHeader('Cache-Control', 'no-store');
+  }
   res.json({
     n: k,
     pool_size: pool.length,

← 01a41fa /admin/health: extended JSON w/ by-color cache stats (hits/m  ·  back to Wallco Ai  ·  drunk-animals: hero block on /designs?cat=drunk-animals + gh 69c2529 →