[object Object]

← back to Designer Wallcoverings

TK-10899: add in-place PJ Fall 2026 CC draft updater (dry-run default)

6197515ef1a39043fe10cbc6b687dbf7d8238695 · 2026-09-10 07:38:20 -0700 · Steve

The PJ draft (activity 54105fd3) already exists since 2026-08-31, so re-running
build-phillip-jeffries-campaign.js --confirm would create a DUPLICATE draft. This
updates the existing activity in place (PUT), following the update-showcase-draft.js
precedent, and stays double-gated on CC_LIVE=1 AND --confirm.

Carries a hard refusal if the mailer still hotlinks the vendor CDN, so the asset swap
cannot be silently skipped or undone by a later draft push.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TCFwJYZFtrKWTt2wALsWzv

Files touched

Diff

commit 6197515ef1a39043fe10cbc6b687dbf7d8238695
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Sep 10 07:38:20 2026 -0700

    TK-10899: add in-place PJ Fall 2026 CC draft updater (dry-run default)
    
    The PJ draft (activity 54105fd3) already exists since 2026-08-31, so re-running
    build-phillip-jeffries-campaign.js --confirm would create a DUPLICATE draft. This
    updates the existing activity in place (PUT), following the update-showcase-draft.js
    precedent, and stays double-gated on CC_LIVE=1 AND --confirm.
    
    Carries a hard refusal if the mailer still hotlinks the vendor CDN, so the asset swap
    cannot be silently skipped or undone by a later draft push.
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01TCFwJYZFtrKWTt2wALsWzv
---
 mailers/cc-api/update-pj-fall-2026-draft.js | 64 +++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/mailers/cc-api/update-pj-fall-2026-draft.js b/mailers/cc-api/update-pj-fall-2026-draft.js
new file mode 100644
index 00000000..092247b1
--- /dev/null
+++ b/mailers/cc-api/update-pj-fall-2026-draft.js
@@ -0,0 +1,64 @@
+'use strict';
+
+/**
+ * update-pj-fall-2026-draft.js — TK-10899
+ *
+ * Pushes the current phillip-jeffries-fall-2026-launch.html into the EXISTING
+ * Constant Contact DRAFT activity (PUT /v3/emails/activities/{id}).
+ *
+ * WHY THIS AND NOT build-phillip-jeffries-campaign.js --confirm:
+ *   The draft ALREADY EXISTS (created 2026-08-31). Re-running the build script's
+ *   --confirm would create a SECOND, duplicate draft. Use this to update in place.
+ *
+ * Updating a DRAFT's content is NOT a send. Still double-gated: CC_LIVE=1 AND --confirm.
+ * The live send remains a separate, explicit action in Steve's Constant Contact console.
+ *
+ *   node update-pj-fall-2026-draft.js                      # dry-run (NO-OP, no network)
+ *   CC_LIVE=1 node update-pj-fall-2026-draft.js --confirm  # update the draft in place
+ */
+
+const fs = require('fs');
+const path = require('path');
+const cc = require('./cc-client');
+
+const ACTIVITY_ID = '54105fd3-5114-4090-94a2-24fd31d3de52'; // PJ Fall 2026 primary_email, DRAFT
+const MAILER = path.join(__dirname, '..', 'phillip-jeffries-fall-2026-launch.html');
+const CONFIRM = process.argv.slice(2).includes('--confirm');
+
+const CAMPAIGN = {
+  subject: 'Phillip Jeffries Fall 2026 — fifty years in the making',
+  preheader: 'A celebration of artisanal history: Idyllic, Cirque de Soho, Coco Weave & Plush Pillars — the new Phillip Jeffries Fall 2026 Collection. Explore it online or experience Phillip Jeffries materials at our Sherman Oaks showroom.',
+  fromName: 'Designer Wallcoverings',
+  fromEmail: 'steve@designerwallcoverings.com',
+  replyTo: 'steve@designerwallcoverings.com',
+  // Real, staffed physical address — CAN-SPAM §5(a)(5). Matches what is already on the draft.
+  physicalAddress: {
+    address_line1: '15442 Ventura Blvd', city: 'Sherman Oaks',
+    state_code: 'CA', postal_code: '91403', country_code: 'US',
+  },
+};
+
+async function main() {
+  const html = fs.readFileSync(MAILER, 'utf8');
+
+  // Guard: refuse to push content that still hotlinks the vendor CDN. Re-hosting is the
+  // whole point of the TK-10899 asset swap; pushing un-swapped HTML would silently undo it.
+  const vendorHosts = ['api.phillipjeffries.com', 'cdn2.webdamdb.com'];
+  const leaks = vendorHosts.filter((h) => html.includes(h));
+  if (leaks.length) {
+    console.error(`[update-pj-draft] REFUSING: mailer still hotlinks vendor CDN (${leaks.join(', ')}).`);
+    console.error('  Run the asset swap first: node ../tools/pj-asset-swap.mjs --apply  (Steve-gated)');
+    process.exitCode = 1;
+    return;
+  }
+
+  console.log(`[update-pj-draft] activity ${ACTIVITY_ID}  html=${html.length} bytes  confirm=${CONFIRM}  CC_LIVE=${process.env.CC_LIVE === '1' ? '1' : '(unset)'}`);
+  const res = await cc.updateCampaignActivity(ACTIVITY_ID, {
+    subject: CAMPAIGN.subject, preheader: CAMPAIGN.preheader,
+    fromEmail: CAMPAIGN.fromEmail, fromName: CAMPAIGN.fromName, replyTo: CAMPAIGN.replyTo,
+    htmlContent: html, physicalAddress: CAMPAIGN.physicalAddress,
+  }, CONFIRM);
+  console.log('[update-pj-draft] result:', JSON.stringify(res).slice(0, 300));
+}
+
+main().catch((e) => { console.error('[update-pj-draft] ERROR:', e.message); process.exitCode = 1; });

← a6000b9b TK-10899: add gated, reversible PJ Fall 2026 mailer asset-sw  ·  back to Designer Wallcoverings  ·  guard TK-11299: skip $0 quote-only variants in the 6-hourly 23987f86 →