← back to Wallco Ai
bulk-action 'digital': exempt designs with a built room-size mural master from demotion
5499527ae945cc8a7bd7ca775cca061cfcbdba51 · 2026-06-03 22:34:16 -0700 · Steve Abrams
The low-res mural demotion (mark digital-for-sale → unpublish) was unpublishing
designs that NOW have a built 12x11ft master (e.g. #27151) — i.e. premium mural
products got demoted as 'low-res junk'. Guard: skip any id with a
data/mural-previews/<id>.jpg, report them as mural_skipped. Prevents the
mural-block PDPs from being silently 404'd by the demotion.
Files touched
Diff
commit 5499527ae945cc8a7bd7ca775cca061cfcbdba51
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Jun 3 22:34:16 2026 -0700
bulk-action 'digital': exempt designs with a built room-size mural master from demotion
The low-res mural demotion (mark digital-for-sale → unpublish) was unpublishing
designs that NOW have a built 12x11ft master (e.g. #27151) — i.e. premium mural
products got demoted as 'low-res junk'. Guard: skip any id with a
data/mural-previews/<id>.jpg, report them as mural_skipped. Prevents the
mural-block PDPs from being silently 404'd by the demotion.
---
server.js | 52 +++++++++++++++++++++++++++++-----------------------
1 file changed, 29 insertions(+), 23 deletions(-)
diff --git a/server.js b/server.js
index 33ef3f7..79b8f60 100644
--- a/server.js
+++ b/server.js
@@ -4989,6 +4989,7 @@ app.post('/api/designs/bulk-action', express.json({ limit: '64kb' }), (req, res)
const idList = ids.join(',');
try {
let affected = 0;
+ let muralSkipped = [];
if (action === 'delete') {
psqlExecLocal(`UPDATE spoon_all_designs SET user_removed=TRUE WHERE id IN (${idList});`);
affected = ids.length;
@@ -5004,34 +5005,39 @@ app.post('/api/designs/bulk-action', express.json({ limit: '64kb' }), (req, res)
psqlExecLocal(`UPDATE spoon_all_designs SET is_published=FALSE WHERE id IN (${idList});`);
affected = ids.length;
} else if (action === 'digital') {
- // Unpublish from the wallpaper catalog AND mark as a digital file for sale.
- // Mirrors the proven cactus-curator 'digital' verdict (lines ~3018): off
- // the live catalog (is_published/web_viewer=FALSE), stamp digital_file_at,
- // and tag 'digital-file' so the digital-pack pipeline picks it up.
- // Written against the base table all_designs (the columns digital_file_at /
- // web_viewer / tags live there) — same target the cactus path uses.
- psqlExecLocal(`UPDATE all_designs
- SET is_published=FALSE, web_viewer=FALSE, digital_file_at=now(),
- tags = array_remove(COALESCE(tags, ARRAY[]::text[]), 'digital-file') || ARRAY['digital-file']::text[]
- WHERE id IN (${idList});`);
- // PROD spoon_all_designs is a SEPARATE base table the storefront/PDP reads;
- // on Mac2 it's a VIEW over all_designs so this is a harmless echo. The
- // 'unpublish' action already writes spoon — 'digital' must too, or on prod
- // the item stays visible on its PDP after being marked digital-for-sale
- // (the all_designs-only write doesn't reach the table the live site reads).
- // This is the root cause of the digital-for-sale leak. Steve 2026-06-03.
- psqlExecLocal(`UPDATE spoon_all_designs SET is_published=FALSE WHERE id IN (${idList});`);
- affected = ids.length;
- // Drop from in-memory catalog so it leaves the live feed immediately.
- for (const id of ids) {
- const idx = DESIGNS.findIndex((x) => x.id === id);
- if (idx >= 0) DESIGNS.splice(idx, 1);
+ // GUARD (Steve 2026-06-04): a design that's been built into a 12x11ft
+ // room-size mural master (data/mural-previews/<id>.jpg) is now a PREMIUM
+ // mural product — never silently demote it to digital-only. The low-res
+ // demotion was unpublishing exactly these (e.g. #27151). Skip + report them.
+ muralSkipped = ids.filter((id) => {
+ try { return fs.existsSync(path.join(__dirname, 'data', 'mural-previews', String(id) + '.jpg')); }
+ catch (e) { return false; }
+ });
+ const toDemote = ids.filter((id) => !muralSkipped.includes(id));
+ if (toDemote.length) {
+ const dList = toDemote.join(',');
+ // Unpublish from the wallpaper catalog AND mark as a digital file for sale
+ // (is_published/web_viewer=FALSE, stamp digital_file_at, tag 'digital-file').
+ psqlExecLocal(`UPDATE all_designs
+ SET is_published=FALSE, web_viewer=FALSE, digital_file_at=now(),
+ tags = array_remove(COALESCE(tags, ARRAY[]::text[]), 'digital-file') || ARRAY['digital-file']::text[]
+ WHERE id IN (${dList});`);
+ // PROD spoon_all_designs is a SEPARATE base table the storefront/PDP reads
+ // (on Mac2 it's a VIEW → harmless echo); mirror the unpublish so digital
+ // actually drops the item from the live site on prod.
+ psqlExecLocal(`UPDATE spoon_all_designs SET is_published=FALSE WHERE id IN (${dList});`);
+ // Drop from in-memory catalog so it leaves the live feed immediately.
+ for (const id of toDemote) {
+ const idx = DESIGNS.findIndex((x) => x.id === id);
+ if (idx >= 0) DESIGNS.splice(idx, 1);
+ }
}
+ affected = toDemote.length;
} else if (action === 'tag') {
// For now — accept but don't implement tag-write path (needs UI for tag input)
return res.status(501).json({ error: 'tag action not yet implemented — coming soon' });
}
- res.json({ ok: true, action, affected, ids });
+ res.json({ ok: true, action, affected, ids, mural_skipped: muralSkipped });
} catch (e) {
res.status(500).json({ error: e.message });
}
← d2aa744 Add clean-edge vector-trace 150-DPI upscale pipeline (potrac
·
back to Wallco Ai
·
Feature murals prominently on home: pinned Shop Murals quick c85a001 →