[object Object]

← back to Wallco Ai

needs-tif admin: count disk truth (findTifOnDisk), not PG tif_path

d6068de1611681a20184a8e142e82cab74b2ab36 · 2026-06-02 09:22:27 -0700 · Steve Abrams

pilot-build-tifs.py writes TIF files without setting all_designs.tif_path, and
the hires route resolves by disk — so 'tif_path IS NULL' over-reported the
backlog by thousands. /api/admin/needs-tif now iterates the in-memory catalog
and counts published designs with no TIF file on disk. by_group + newest-first
items computed in JS.

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

Files touched

Diff

commit d6068de1611681a20184a8e142e82cab74b2ab36
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jun 2 09:22:27 2026 -0700

    needs-tif admin: count disk truth (findTifOnDisk), not PG tif_path
    
    pilot-build-tifs.py writes TIF files without setting all_designs.tif_path, and
    the hires route resolves by disk — so 'tif_path IS NULL' over-reported the
    backlog by thousands. /api/admin/needs-tif now iterates the in-memory catalog
    and counts published designs with no TIF file on disk. by_group + newest-first
    items computed in JS.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 server.js | 36 ++++++++++++++++++++++++------------
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/server.js b/server.js
index c568dcb..c98585a 100644
--- a/server.js
+++ b/server.js
@@ -1927,18 +1927,30 @@ app.get('/api/admin/needs-tif', requireAdmin, (req, res) => {
   const limit = Math.min(2000, Math.max(1, parseInt(req.query.limit, 10) || 500));
   const offset = Math.max(0, parseInt(req.query.offset, 10) || 0);
   try {
-    const total = parseInt(String(psqlQuery(
-      "SELECT COUNT(*) FROM all_designs WHERE is_published AND tif_path IS NULL")).trim(), 10) || 0;
-    const groups = JSON.parse(String(psqlQuery(
-      `SELECT COALESCE(json_agg(json_build_object('grp', grp, 'n', n) ORDER BY n DESC), '[]')
-         FROM (SELECT split_part(category, ' · ', 1) AS grp, COUNT(*) AS n
-                 FROM all_designs WHERE is_published AND tif_path IS NULL GROUP BY 1) t`)) || '[]');
-    const items = JSON.parse(String(psqlQuery(
-      `SELECT COALESCE(json_agg(row_to_json(t)), '[]') FROM (
-         SELECT id, category, created_at, dominant_hex, image_url
-           FROM all_designs WHERE is_published AND tif_path IS NULL
-          ORDER BY created_at DESC NULLS LAST, id DESC LIMIT ${limit} OFFSET ${offset}) t`)) || '[]');
-    res.json({ ok: true, total, limit, offset, by_group: groups, items });
+    // DISK TRUTH (2026-06-02): the old query was `all_designs WHERE tif_path IS
+    // NULL`, but the disk-based builder (pilot-build-tifs.py) writes TIF FILES
+    // without setting the PG tif_path column — and the /designs/hires/:id route
+    // resolves TIFs by DISK (findTifOnDisk), not PG. So the PG query massively
+    // over-reported. A published design "needs a TIF" iff no TIF file is on disk.
+    const pub = DESIGNS.filter(d => d && d.is_published !== false);
+    const missing = pub.filter(d => !findTifOnDisk(d.id));
+    const total = missing.length;
+    const groupMap = new Map();
+    for (const d of missing) {
+      const grp = String(d.category || '?').split(' · ')[0];
+      groupMap.set(grp, (groupMap.get(grp) || 0) + 1);
+    }
+    const by_group = [...groupMap.entries()].map(([grp, n]) => ({ grp, n })).sort((a, b) => b.n - a.n);
+    const sorted = missing.slice().sort((a, b) => {
+      const ca = a.created_at || '', cb = b.created_at || '';
+      if (ca !== cb) return ca < cb ? 1 : -1;   // newest first
+      return (b.id || 0) - (a.id || 0);
+    });
+    const items = sorted.slice(offset, offset + limit).map(d => ({
+      id: d.id, category: d.category, created_at: d.created_at || null,
+      dominant_hex: d.dominant_hex, image_url: d.image_url || ('/designs/img/by-id/' + d.id)
+    }));
+    res.json({ ok: true, total, limit, offset, by_group, items });
   } catch (e) {
     res.status(500).json({ ok: false, error: e.message });
   }

← 1044ed0 PDP theme switcher: fix dropdown on bare /design/:id — treat  ·  back to Wallco Ai  ·  draft_corey_letter.py: env-first George auth (GMAIL_BASIC_AU 546e9b4 →