[object Object]

← back to Fabricut Landing

fix(fabricut): make build schema-resilient + build on canonical Mac2

41f035e549823de7701c97ae1d8850ff38b5c47f · 2026-08-24 18:56:22 -0700 · Steve

build-fabricut.js crashed on Kamatera ('column book_name does not exist') because
the Kamatera fabricut_catalog mirror is schema-drifted (only has 'collection').
Add an information_schema guard so the query degrades gracefully instead of crashing,
and move the data build to a PREDEPLOY_HOOK that runs on canonical Mac2 (where
book_name + real book labels live) — ship the finished products.json instead of
rebuilding on the drifted mirror. Verified local build: 1325 products, 11 books, 189 patterns.

Files touched

Diff

commit 41f035e549823de7701c97ae1d8850ff38b5c47f
Author: Steve <steve@designerwallcoverings.com>
Date:   Mon Aug 24 18:56:22 2026 -0700

    fix(fabricut): make build schema-resilient + build on canonical Mac2
    
    build-fabricut.js crashed on Kamatera ('column book_name does not exist') because
    the Kamatera fabricut_catalog mirror is schema-drifted (only has 'collection').
    Add an information_schema guard so the query degrades gracefully instead of crashing,
    and move the data build to a PREDEPLOY_HOOK that runs on canonical Mac2 (where
    book_name + real book labels live) — ship the finished products.json instead of
    rebuilding on the drifted mirror. Verified local build: 1325 products, 11 books, 189 patterns.
---
 .deploy.conf              |  8 ++++++--
 scripts/build-fabricut.js | 10 +++++++++-
 2 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/.deploy.conf b/.deploy.conf
index bf44b14..d3ad26c 100644
--- a/.deploy.conf
+++ b/.deploy.conf
@@ -2,5 +2,9 @@
 PROJECT_NAME="fabricut-landing"
 DEPLOY_PATH="/var/www/fabricut.designerwallcoverings.com"
 DOMAIN="fabricut.designerwallcoverings.com"
-HEALTH_URL="http://localhost:PORT/healthz"
-BUILD_CMD="MODE=public node scripts/build-fabricut.js"
+HEALTH_URL="http://localhost:35959/healthz"
+# Build the PUBLIC data on canonical Mac2 (has fabricut_catalog.book_name) BEFORE rsync,
+# then ship the finished data/products.json. Do NOT rebuild on Kamatera — its mirror is
+# schema-drifted (no book_name), which would blank every book label. (TK: fabricut-dedupe)
+PREDEPLOY_HOOK="MODE=public node scripts/build-fabricut.js"
+BUILD_CMD=""
diff --git a/scripts/build-fabricut.js b/scripts/build-fabricut.js
index b22d5d2..ec0cfed 100644
--- a/scripts/build-fabricut.js
+++ b/scripts/build-fabricut.js
@@ -46,8 +46,16 @@ function bucketFromHSV(hsv) {
 }
 
 async function main() {
+  // book_name is a Mac2-canonical *_catalog column; the Kamatera mirror can be schema-drifted
+  // (has `collection` only). Detect it so the build degrades gracefully instead of crashing.
+  // Correct data comes from building on canonical Mac2 (see .deploy.conf PREDEPLOY_HOOK).
+  const hasBook = (await pool.query(
+    `SELECT 1 FROM information_schema.columns WHERE table_name='fabricut_catalog' AND column_name='book_name' LIMIT 1`
+  )).rows.length > 0;
+  if (!hasBook) console.warn('[warn] fabricut_catalog.book_name absent on this host — falling back to collection (build on Mac2 for real book labels)');
+  const bookSel = hasBook ? 'book_name' : 'collection AS book_name';
   const { rows } = await pool.query(`
-    SELECT dw_sku, mfr_sku, pattern_name, color_name, product_type, collection, book_name,
+    SELECT dw_sku, mfr_sku, pattern_name, color_name, product_type, collection, ${bookSel},
            width, length, repeat_v, material, match_type, finish, backing, fire_codes, scale,
            country_origin, roll_yards, min_order_yards, msrp_unit, vendor_msrp,
            price_retail, price_trade, ai_description, ai_styles, ai_patterns, ai_colors,

← bdb71d3 chore(fabricut): rebase onto live — add GA snippet + pin pro  ·  back to Fabricut Landing  ·  fabricut: filter dead _stylized_secondary room images (403 A e588706 →