← 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
A momentum-feed/refresh.mjs
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 →