[object Object]

← back to Wallco Ai

design page: Sell on Etsy (digital) button → tags etsy-digital-file + queues to data/etsy-queue.jsonl (no Etsy API call yet — listing stays a gated batch op)

3ed1a1953546146f35f31c5cc8fa209d203650f6 · 2026-05-28 06:43:23 -0700 · Steve Abrams

Files touched

Diff

commit 3ed1a1953546146f35f31c5cc8fa209d203650f6
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu May 28 06:43:23 2026 -0700

    design page: Sell on Etsy (digital) button → tags etsy-digital-file + queues to data/etsy-queue.jsonl (no Etsy API call yet — listing stays a gated batch op)
---
 server.js | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/server.js b/server.js
index 794f29c..582be6f 100644
--- a/server.js
+++ b/server.js
@@ -17918,6 +17918,35 @@ app.post('/api/spoonflower/upload', requireAdmin, (req, res) => {
   res.json({ ok: true, job_id: jobId, dry, log_url: `/api/spoonflower/status/${jobId}` });
 });
 
+// ── POST /api/design/:id/etsy-tag — mark a design for Etsy digital-file resale
+//
+// Admin-only. Tags the row with 'etsy-digital-file' and appends to data/etsy-queue.jsonl
+// so a separate etsy-export pipeline can pick it up. Does NOT call the Etsy API — actual
+// listing is a downstream batch op that needs per-design approval (money/identity). The
+// fix-decision route at line ~986 also writes this tag via a 'verdict=etsy' path; this
+// endpoint is the same tag but reachable from the /design/:id admin UI.
+app.post('/api/design/:id/etsy-tag', requireAdmin, express.json({ limit: '4kb' }), (req, res) => {
+  const id = parseInt(req.params.id, 10);
+  if (!Number.isFinite(id) || id < 1) return res.status(400).json({ error: 'bad id' });
+  try {
+    const raw = psqlQuery(`SELECT row_to_json(t) FROM (SELECT id, COALESCE(ai_title, title, '') AS title, dig_number, local_path, COALESCE(tags, ARRAY[]::text[]) AS tags FROM spoon_all_designs WHERE id=${id}) t;`);
+    if (!raw || raw.length < 3) return res.status(404).json({ error: 'design not found' });
+    const row = JSON.parse(raw);
+    const already = Array.isArray(row.tags) && row.tags.includes('etsy-digital-file');
+    if (!already) {
+      psqlExecLocal(`UPDATE spoon_all_designs
+        SET tags = array_remove(COALESCE(tags, ARRAY[]::text[]), 'etsy-digital-file') || ARRAY['etsy-digital-file']::text[]
+        WHERE id=${id};`);
+    }
+    const queued_at = new Date().toISOString();
+    fs.appendFileSync(path.join(__dirname, 'data', 'etsy-queue.jsonl'),
+      JSON.stringify({ ts: queued_at, id, dig_number: row.dig_number, title: row.title, local_path: row.local_path, source: 'design-page-button' }) + '\n');
+    res.json({ ok: true, id, dig_number: row.dig_number, title: row.title, already_tagged: already, queued_at });
+  } catch (e) {
+    res.status(500).json({ error: String(e.message || e).slice(0, 200) });
+  }
+});
+
 // ── POST /api/design/:id/upload-shopify — push a wallco.ai design as a NEW Shopify product
 //
 // Admin-only. Reads the design row, picks the DW Original Number

← 78093f0 etsy bucket: wallco_etsy_bucket table + /api/etsy-bucket/{ad  ·  back to Wallco Ai  ·  etsy-tag endpoint: drop nonexistent 'title' column (view has 3fc593c →