[object Object]

← back to Ventura Corridor

iter 113+114: pitch_event_log audit panel on /magazine/:id + feature-of-the-week — reader page now appends a collapsible <details> 'Editorial dossier · N pipeline events' that lists last 10 audit events from pitch_event_log for the underlying business (timestamp · event_type · old → new) in JetBrains Mono with subtle italic footnote ('From the DW outreach pipeline that produces the magazine — every walk, every reply, every status change'); /api/magazine/feature-of-the-week picks deterministic-by-week-of-year (id*WK%count) feature requiring editorial>300 chars + status IN (published, reviewed); /today.html grows '📰 Feature of the week' compact pill below FOTD

0bc6fd66a1ee37a35c99a6e24322b9e9f1a3e80b · 2026-05-06 17:58:26 -0700 · SteveStudio2

Files touched

Diff

commit 0bc6fd66a1ee37a35c99a6e24322b9e9f1a3e80b
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date:   Wed May 6 17:58:26 2026 -0700

    iter 113+114: pitch_event_log audit panel on /magazine/:id + feature-of-the-week — reader page now appends a collapsible <details> 'Editorial dossier · N pipeline events' that lists last 10 audit events from pitch_event_log for the underlying business (timestamp · event_type · old → new) in JetBrains Mono with subtle italic footnote ('From the DW outreach pipeline that produces the magazine — every walk, every reply, every status change'); /api/magazine/feature-of-the-week picks deterministic-by-week-of-year (id*WK%count) feature requiring editorial>300 chars + status IN (published, reviewed); /today.html grows '📰 Feature of the week' compact pill below FOTD
---
 public/today.html   | 23 +++++++++++++++++++++++
 src/server/index.ts | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+)

diff --git a/public/today.html b/public/today.html
index 7d972d7..8e916b4 100644
--- a/public/today.html
+++ b/public/today.html
@@ -154,6 +154,14 @@
   <div id="fotd-body" style="margin-top:14px"></div>
 </section>
 
+<section id="fotw-section" style="display:none;padding:18px 32px;border-bottom:1px solid var(--rule);background:radial-gradient(ellipse at left, rgba(106,58,26,0.06), transparent 70%)">
+  <div style="display:flex;justify-content:space-between;align-items:baseline;flex-wrap:wrap;gap:10px">
+    <h3 style="font-family:var(--serif);font-style:italic;font-weight:400;font-size:18px;color:var(--accent,#a8763a);margin:0">📰 Feature of the week</h3>
+    <a id="fotw-link" href="/magazine.html" style="color:var(--metal);text-decoration:none;font-size:10px;letter-spacing:.18em;text-transform:uppercase;border:1px solid var(--rule);padding:3px 8px">Open ↗</a>
+  </div>
+  <div id="fotw-body" style="margin-top:8px;font-family:var(--serif);font-style:italic;font-size:14px;color:var(--ink-mute);line-height:1.5"></div>
+</section>
+
 <section id="magazine-section" style="padding:20px 32px;border-bottom:1px solid var(--rule);background:rgba(184,153,104,0.04)">
   <div style="display:flex;justify-content:space-between;align-items:baseline;flex-wrap:wrap;gap:10px">
     <h3 style="font-family:var(--serif);font-style:italic;font-weight:400;font-size:22px;color:var(--metal-glow);margin:0">📖 The Corridor <span style="font-size:11px;letter-spacing:.18em;color:var(--ink-mute);margin-left:8px">corridor magazine</span></h3>
@@ -630,6 +638,21 @@ async function loadFOTD() {
   } catch {}
 }
 loadFOTD();
+
+async function loadFOTW() {
+  try {
+    const d = await fetch('/api/magazine/feature-of-the-week').then(r => r.json());
+    const f = d.feature;
+    if (!f) return;
+    document.getElementById('fotw-section').style.display = 'block';
+    document.getElementById('fotw-link').href = '/magazine/' + f.id;
+    document.getElementById('fotw-body').innerHTML = `
+      <a href="/magazine/${f.id}" style="font-family:var(--serif);font-size:18px;font-style:italic;color:var(--ink);text-decoration:none">${escHtml(f.headline || f.biz_name)}</a>
+      <span style="color:var(--ink-mute);font-size:12px;margin-left:6px">— ${escHtml(f.biz_name)} · ${escHtml(f.category_tag || '')}</span>
+    `;
+  } catch {}
+}
+loadFOTW();
 </script>
 </body>
 </html>
diff --git a/src/server/index.ts b/src/server/index.ts
index 608e765..32526a0 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -1778,6 +1778,26 @@ app.get('/api/magazine/stale', async (req, res) => {
   }
 });
 
+// Stable per-week pick: rotates weekly, prefers published features for editorial polish
+app.get('/api/magazine/feature-of-the-week', async (_req, res) => {
+  try {
+    const r = await query(`
+      SELECT mf.id, mf.headline, mf.subhead, mf.editorial, mf.pull_quote, mf.category_tag,
+             b.name AS biz_name, b.address AS biz_address, b.city
+      FROM magazine_features mf
+      JOIN businesses b ON b.id = mf.business_id
+      WHERE mf.editorial IS NOT NULL AND length(mf.editorial) > 300
+        AND mf.status IN ('published', 'reviewed')
+      ORDER BY (mf.id * (EXTRACT(WEEK FROM CURRENT_DATE)::int + 7)) % (SELECT GREATEST(count(*), 1) FROM magazine_features)
+      LIMIT 1
+    `);
+    if (r.rowCount === 0) return res.json({ feature: null });
+    res.json({ feature: r.rows[0] });
+  } catch (e: any) {
+    res.status(500).json({ error: e.message });
+  }
+});
+
 app.get('/api/magazine/feature-of-the-day', async (_req, res) => {
   try {
     const r = await query(`
@@ -2692,6 +2712,16 @@ app.get('/magazine/:id', async (req, res) => {
      LIMIT 3`,
     [f.category_tag, id]
   );
+  // Pull last 10 pipeline events for the underlying business (status changes, walks, replies, etc)
+  const events = await query(
+    `SELECT pel.event_type, pel.old_value, pel.new_value, pel.occurred_at
+     FROM pitch_event_log pel
+     JOIN pitches p ON p.id = pel.pitch_id
+     WHERE p.business_id = $1
+     ORDER BY pel.occurred_at DESC, pel.id DESC
+     LIMIT 10`,
+    [f.business_id]
+  );
   // Pull building-mates: other businesses in the same canonical building
   const bldg = (f.biz_address || '').replace(/\s*(SUITE|STE|UNIT|#).*$/i, '').trim();
   const mates = bldg ? await query(
@@ -2767,6 +2797,17 @@ footer{margin-top:48px;padding:24px 0;text-align:center;font-size:10px;letter-sp
     <dt>Generated</dt><dd class="mono">${new Date(f.generated_at).toLocaleString('en-US', { month:'short', day:'numeric', year:'numeric'})} via ${esc(f.model)}</dd>
     <dt>Views</dt><dd class="mono">${f.views || 0}</dd>
   </dl>
+  ${events.rows.length > 0 ? `<details style="margin-top:48px;padding-top:24px;border-top:1px solid var(--rule)">
+    <summary style="cursor:pointer;font-size:9px;letter-spacing:.32em;text-transform:uppercase;color:var(--ink-mute);font-family:'Inter',sans-serif">Editorial dossier · ${events.rowCount} pipeline events</summary>
+    <div style="margin-top:14px;font-family:'JetBrains Mono',monospace;font-size:11px;line-height:1.7;color:var(--ink-mute)">
+      ${events.rows.map((ev: any) => {
+        const arrow = ev.old_value ? `${esc(ev.old_value)} → ${esc(ev.new_value || '')}` : esc(ev.new_value || '');
+        const ts = new Date(ev.occurred_at).toLocaleString('en-US',{month:'short',day:'numeric',hour:'2-digit',minute:'2-digit'});
+        return `<div><span style="color:var(--metal)">${ts}</span> · <span style="color:var(--ink)">${esc(ev.event_type)}</span>${arrow ? ' · ' + arrow : ''}</div>`;
+      }).join('')}
+    </div>
+    <div style="margin-top:8px;font-size:10px;color:var(--ink-mute);font-style:italic">From the DW outreach pipeline that produces the magazine — every walk, every reply, every status change.</div>
+  </details>` : ''}
   ${mates.rows.length > 0 ? `<section style="margin-top:48px;padding-top:24px;border-top:1px solid var(--rule)">
     <div style="font-size:9px;letter-spacing:.32em;text-transform:uppercase;color:var(--ink-mute);margin-bottom:14px">In the same building · ${esc(bldg)}</div>
     <div style="display:flex;flex-direction:column;gap:6px">

← 97d5a13 iter 111+112: /api/magazine/:id/embed.html iframe-friendly m  ·  back to Ventura Corridor  ·  iter 115+116+117: og/twitter/JSON-LD meta + /api/magazine.js cfd5c5a →