[object Object]

← back to Hollywood Import

momentum feed-first refresh (Meilisearch redesign-colors): +788 new WC/Acoustic colorways, 10165 volatile-refreshed, non-clobbering

e5c026fd51f043d0c4d11da00a2b65af631379e9 · 2026-07-08 12:41:41 -0700 · steve@designerwallcoverings.com

Files touched

Diff

commit e5c026fd51f043d0c4d11da00a2b65af631379e9
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date:   Wed Jul 8 12:41:41 2026 -0700

    momentum feed-first refresh (Meilisearch redesign-colors): +788 new WC/Acoustic colorways, 10165 volatile-refreshed, non-clobbering
---
 momentum-feed/refresh.mjs | 93 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 93 insertions(+)

diff --git a/momentum-feed/refresh.mjs b/momentum-feed/refresh.mjs
new file mode 100644
index 0000000..6cd151d
--- /dev/null
+++ b/momentum-feed/refresh.mjs
@@ -0,0 +1,93 @@
+#!/usr/bin/env node
+// Momentum → Hollywood feed-first refresh (SAFE, non-clobbering).
+// Pages the storefront Meilisearch index `redesign-colors`, keeps only
+// Wallcovering + Acoustic colorways, and upserts into momentum_colorways:
+//   - INSERT new (pattern_name,color_name) rows (staging only; no dw_sku yet)
+//   - On existing rows, refresh ONLY volatile fields (price/width/image/new/closeout).
+//     NEVER overwrites dw_sku, ai_*, description, shopify_*, pl_* (curation is sacred).
+// $0 — plain HTTPS. Run:  NODE_PATH=.../AbramsOS/node_modules node refresh.mjs [--commit]
+import { createRequire } from 'module';
+const require = createRequire(import.meta.url);
+const { Pool } = require('pg');
+
+const HOST = 'https://ms-e886719d86e7-4256.sfo.meilisearch.io';
+// Search key is hardcoded in momentumco.com app.js (meta tag is a decoy). Re-grab if it rotates:
+//   curl -s .../build/assets/app-*.js | grep -oE 'initializeMeiliSearch\("https[^"]+","[0-9a-f]{64}"'
+const KEY = process.env.MOMENTUM_MS_KEY || '95fe8376edc78d49e787db49edda68426b21649f6271f49e2f1412118612fbd6';
+const INDEX = 'redesign-colors';
+const KEEP = new Set(['Wallcovering', 'Acoustic']);
+const COMMIT = process.argv.includes('--commit');
+const pool = new Pool({ connectionString: 'postgresql://dw_admin:DW2024SecurePass@127.0.0.1:5432/dw_unified' });
+
+async function fetchPage(offset, limit = 200) {
+  const r = await fetch(`${HOST}/indexes/${INDEX}/search`, {
+    method: 'POST',
+    headers: { Authorization: `Bearer ${KEY}`, 'Content-Type': 'application/json' },
+    body: JSON.stringify({ q: '', limit, offset,
+      attributesToRetrieve: ['id','number','pattern_name','preferred_color_name','preferred_color_number',
+        'category_name','product_line','price','base_width','medium_image_url','new','series','collections'] }),
+  });
+  if (!r.ok) throw new Error(`feed ${r.status} at offset ${offset}`);
+  return (await r.json()).hits || [];
+}
+
+async function main() {
+  const rows = [];
+  for (let off = 0; off < 20000; off += 200) {
+    const hits = await fetchPage(off);
+    if (!hits.length) break;
+    for (const h of hits) {
+      if (!KEEP.has(h.category_name)) continue;
+      if (!h.pattern_name || !h.preferred_color_name) continue;
+      rows.push({
+        pattern_name: h.pattern_name,
+        color_name: h.preferred_color_name,
+        color_number: h.preferred_color_number || null,
+        momentum_sku: h.number || null,
+        image_url: h.medium_image_url || null,
+        list_price: (h.price != null ? Number(h.price) : null),
+        width: (h.base_width != null ? String(h.base_width) : null),
+        category: h.category_name,
+        product_line: h.product_line?.code || null,
+        is_new: !!h.new,
+        collection_name: h.series || (Array.isArray(h.collections) ? h.collections[0]?.name : null) || null,
+      });
+    }
+    process.stdout.write(`\r  fetched offset ${off}  kept ${rows.length}   `);
+  }
+  console.log(`\nFeed kept ${rows.length} Wallcovering+Acoustic colorways.`);
+  const cats = rows.reduce((a, r) => (a[r.category] = (a[r.category] || 0) + 1, a), {});
+  console.log('  by category:', JSON.stringify(cats));
+
+  if (!COMMIT) { console.log('DRY-RUN (no DB writes). Re-run with --commit to apply.'); await pool.end(); return; }
+
+  const c = await pool.connect();
+  let inserted = 0, updated = 0;
+  try {
+    await c.query('BEGIN');
+    for (const r of rows) {
+      const res = await c.query(
+        `INSERT INTO momentum_colorways
+           (pattern_name,color_name,color_number,momentum_sku,image_url,list_price,width,category,product_line,is_new,collection_name,created_at,updated_at)
+         VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,now(),now())
+         ON CONFLICT (pattern_name,color_name) DO UPDATE SET
+           momentum_sku   = COALESCE(EXCLUDED.momentum_sku, momentum_colorways.momentum_sku),
+           image_url      = COALESCE(EXCLUDED.image_url,    momentum_colorways.image_url),
+           list_price     = COALESCE(EXCLUDED.list_price,   momentum_colorways.list_price),
+           width          = COALESCE(EXCLUDED.width,        momentum_colorways.width),
+           category       = COALESCE(EXCLUDED.category,     momentum_colorways.category),
+           product_line   = COALESCE(EXCLUDED.product_line, momentum_colorways.product_line),
+           is_new         = EXCLUDED.is_new,
+           collection_name= COALESCE(momentum_colorways.collection_name, EXCLUDED.collection_name),
+           updated_at     = now()
+         RETURNING (xmax = 0) AS is_insert`,
+        [r.pattern_name, r.color_name, r.color_number, r.momentum_sku, r.image_url,
+         r.list_price, r.width, r.category, r.product_line, r.is_new, r.collection_name]);
+      res.rows[0].is_insert ? inserted++ : updated++;
+    }
+    await c.query('COMMIT');
+    console.log(`COMMITTED — inserted ${inserted} new, refreshed ${updated} existing (volatile fields only).`);
+  } catch (e) { await c.query('ROLLBACK'); console.error('ROLLBACK:', e.message); process.exitCode = 1; }
+  finally { c.release(); await pool.end(); }
+}
+main().catch(e => { console.error(e); process.exit(1); });

← 4c006cb chore: macstudio3 migration — reconcile from mac2 + repoint  ·  back to Hollywood Import  ·  momentum LOCAL enrichment runner (qwen2.5vl:7b, $0): ai_colo d793c5d →