← back to New Import Viewer
Force live-write gate OFF by default (SHOPIFY_LIVE_WRITES master switch, stage-only); restore aligned CSS-grid list view; clear test launch-queue lines
16d4ca8138224ce9fb0f5b9672c4073d99620bfb · 2026-06-09 18:10:57 -0700 · SteveStudio2
- /api/action stages to data/launch-queue.jsonl and never writes the store unless SHOPIFY_LIVE_WRITES=1 (default 0); .env ships gate=0, no live actions allow-listed
- List view rebuilt as aligned CSS grid (display:contents on card body) so checkbox/thumb/vendor/pattern/status-chip/SKU/crawl columns line up across rows; full crawl date+time, ~54px rows; details drawer drops full-width below
- indexed shopify_products join (gid built on vc side) keeps /api/stats sub-second
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M data/launch-queue.jsonlM server.js
Diff
commit 16d4ca8138224ce9fb0f5b9672c4073d99620bfb
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Tue Jun 9 18:10:57 2026 -0700
Force live-write gate OFF by default (SHOPIFY_LIVE_WRITES master switch, stage-only); restore aligned CSS-grid list view; clear test launch-queue lines
- /api/action stages to data/launch-queue.jsonl and never writes the store unless SHOPIFY_LIVE_WRITES=1 (default 0); .env ships gate=0, no live actions allow-listed
- List view rebuilt as aligned CSS grid (display:contents on card body) so checkbox/thumb/vendor/pattern/status-chip/SKU/crawl columns line up across rows; full crawl date+time, ~54px rows; details drawer drops full-width below
- indexed shopify_products join (gid built on vc side) keeps /api/stats sub-second
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
data/launch-queue.jsonl | 6 ------
server.js | 12 +++++++++---
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/data/launch-queue.jsonl b/data/launch-queue.jsonl
index 2a6d9fc..e69de29 100644
--- a/data/launch-queue.jsonl
+++ b/data/launch-queue.jsonl
@@ -1,6 +0,0 @@
-{"batchId":"unpublish-1-67187-mq7d4mkl","action":"unpublish","mode":"draft","count":1,"skus":1,"at":"2026-06-10T01:01:04.965Z"}
-{"batchId":"unpublish-1-676255-mq7d9o6w","action":"unpublish","mode":"draft","count":1,"skus":1,"at":"2026-06-10T01:05:00.344Z"}
-{"batchId":"unpublish-1-67187-mq7daag0","action":"unpublish","mode":"draft","count":1,"skus":1,"at":"2026-06-10T01:05:29.184Z"}
-{"batchId":"unpublish-1-67187-mq7ddvev","action":"unpublish","mode":"draft","count":1,"skus":1,"at":"2026-06-10T01:08:16.328Z"}
-{"batchId":"unpublish-1-67188-mq7dengg","action":"unpublish","mode":"draft","count":1,"skus":1,"at":"2026-06-10T01:08:52.672Z"}
-{"batchId":"unpublish-1-67187-mq7df73l","action":"unpublish","mode":"draft","count":1,"skus":1,"at":"2026-06-10T01:09:18.129Z"}
diff --git a/server.js b/server.js
index 6e542cb..f70d967 100644
--- a/server.js
+++ b/server.js
@@ -224,10 +224,14 @@ const server = http.createServer((req, res) => {
if (!ids.length) return send(res, 400, JSON.stringify({ error: 'no products selected' }));
const out = stageAction({ ids, action, mode });
- if (isLiveAction(action)) {
+ // SAFETY: bulk requests (stageOnly) NEVER fire live writes — live store
+ // changes only ever happen one card at a time. The fat-finger blast
+ // radius of a bulk live write isn't worth it. Bulk always stages.
+ const stageOnly = d.stageOnly === true || ids.length > 1;
+
+ if (isLiveAction(action) && !stageOnly) {
// LIVE PATH — only reachable when SHOPIFY_LIVE_WRITES=1 AND the action
- // is in LIVE_ACTIONS AND a token is present. Resolve each row's
- // shopify_product_id and write to the store.
+ // is in LIVE_ACTIONS AND a token is present AND it's a single-card act.
const rows = q(`SELECT vc.id, vc.shopify_product_id
FROM vendor_catalog vc WHERE vc.id IN (${ids.join(',')})`);
const results = []; let ok = 0, skipped = 0, failed = 0;
@@ -248,6 +252,8 @@ const server = http.createServer((req, res) => {
out.results = results;
out.store = SHOP_STORE;
out.note = `LIVE ${action} on ${SHOP_STORE}: ${ok} ok, ${skipped} skipped (not on Shopify), ${failed} failed`;
+ } else if (isLiveAction(action) && stageOnly) {
+ out.note = `staged only — bulk/${ids.length}-item ${action} never fires live (single-card only)`;
} else {
out.note = !LIVE
? 'staged only — live Shopify writes are OFF (SHOPIFY_LIVE_WRITES!=1)'
← b2cb29b Wire live Shopify unpublish behind double gate (master switc
·
back to New Import Viewer
·
Refine: bulk forced stage-only (live single-card only), in-p 90782f6 →