[object Object]

← back to Customdigitalmurals

stage2: wire customdigitalmurals onto shared catalog (hand-tailored)

8e87abfb272661d72f8ec6e40ab7fa7f3bcdcb17 · 2026-05-19 11:07:56 -0700 · Steve Abrams

Files touched

Diff

commit 8e87abfb272661d72f8ec6e40ab7fa7f3bcdcb17
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue May 19 11:07:56 2026 -0700

    stage2: wire customdigitalmurals onto shared catalog (hand-tailored)
---
 package.json     |  4 +++-
 server.js        | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 site.config.json | 15 +++++++++++++++
 3 files changed, 68 insertions(+), 3 deletions(-)

diff --git a/package.json b/package.json
index 64db1ea..915d9a2 100644
--- a/package.json
+++ b/package.json
@@ -7,6 +7,8 @@
     "start": "node server.js"
   },
   "dependencies": {
-    "express": "^4.18.2"
+    "dotenv": "^16.4.5",
+    "express": "^4.18.2",
+    "pg": "^8.11.5"
   }
 }
diff --git a/server.js b/server.js
index 8dfec26..fcd00c0 100644
--- a/server.js
+++ b/server.js
@@ -6,13 +6,28 @@
  * density slider, Cloudflare-aware, pm2 + systemd.
  */
 'use strict';
+try { require('dotenv').config({ path: require('path').join(__dirname, '.env') }); } catch (e) {}
 const express = require('express');
 const path    = require('path');
 const fs      = require('fs');
 
 const PORT = process.env.PORT || 9896;
 const DATA_FILE = path.join(__dirname, 'data', 'products.json');
-const ALL = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
+
+// Shared catalog module — read-path from dw_unified.microsite_products + admin CRUD.
+const catalog   = require('../_shared/admin-catalog');
+const siteCfg   = JSON.parse(fs.readFileSync(path.join(__dirname, 'site.config.json'), 'utf8'));
+const SITE_SLUG = siteCfg.slug || path.basename(__dirname);
+const SITE_RAILS = Array.isArray(siteCfg.rails) ? siteCfg.rails : [];
+
+// Static JSON snapshot — keeps the rich fields (images[], price, body_html) the
+// migration into microsite_products didn't carry over, and is the PG-down fallback.
+const STATIC = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
+const STATIC_BY_HANDLE = new Map(STATIC.map(p => [p.handle, p]));
+
+// ALL is populated async at startup (see bottom). Seed with the static snapshot
+// so the very first requests before PG resolves still have data.
+let ALL = STATIC;
 
 const DW_BASE = 'https://designerwallcoverings.com';
 const GA4_ID  = process.env.GA4_MEASUREMENT_ID || '';
@@ -95,7 +110,40 @@ app.get('/sitemap.xml', (_req, res) => {
   res.send(`<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls}\n</urlset>`);
 });
 
-app.listen(PORT, () => console.log(`customdigitalmurals.com :${PORT}`));
+// Admin catalog CRUD — /admin/catalog (basic-auth) + /api/admin/* REST.
+catalog.mount(app, { siteSlug: SITE_SLUG, rails: SITE_RAILS });
+
+// Merge a PG microsite_products row with the rich static snapshot (by handle),
+// so the storefront still has images[], price and body_html the migration dropped.
+function enrich(row) {
+  const s = STATIC_BY_HANDLE.get(row.handle) || {};
+  return {
+    id: s.id,
+    title: row.title || s.title,
+    handle: row.handle,
+    vendor: row.vendor || s.vendor,
+    product_type: row.product_type || s.product_type,
+    tags: (Array.isArray(row.tags) && row.tags.length) ? row.tags : (s.tags || []),
+    body_html: s.body_html || '',
+    images: s.images || (row.image_url ? [row.image_url] : []),
+    price: row.max_price != null ? String(row.max_price) : (s.price || '0'),
+    dw_url: row.product_url || s.dw_url,
+  };
+}
+
+// Load the catalog from dw_unified, then start listening. PG down → JSON snapshot.
+(async () => {
+  try {
+    const rows = await catalog.getProducts(SITE_SLUG);
+    if (!rows.length) throw new Error('microsite_products returned 0 rows');
+    ALL = rows.map(enrich);
+    console.log(`[${SITE_SLUG}] loaded ${ALL.length} products from dw_unified`);
+  } catch (e) {
+    console.error(`[${SITE_SLUG}] PG catalog load failed (${e.message}) — using data/products.json`);
+    ALL = STATIC;
+  }
+  app.listen(PORT, () => console.log(`customdigitalmurals.com :${PORT} (${ALL.length} products)`));
+})();
 
 // ── Templates ──────────────────────────────────────────────────────────────
 
diff --git a/site.config.json b/site.config.json
new file mode 100644
index 0000000..faa7d89
--- /dev/null
+++ b/site.config.json
@@ -0,0 +1,15 @@
+{
+  "slug": "customdigitalmurals",
+  "siteName": "Customdigitalmurals",
+  "domain": "customdigitalmurals.com",
+  "heroHeadline": "CUSTOMDIGITALMURALS",
+  "rails": [
+    "green",
+    "botanical",
+    "commercial",
+    "blue",
+    "architectural",
+    "white"
+  ],
+  "_generated": true
+}

← 31a4c17 initial scaffold: customdigitalmurals.com Off-White storefro  ·  back to Customdigitalmurals  ·  Phase 2: mobile-ready + tap-to-reveal 917bb01 →