← back to Ventura Corridor
iter 164: morning_feature_email now includes 'Suggested next publish' block — draft-pick-of-the-night
48b33424cd5e7bc5e57338577c7560befe9acf74 · 2026-05-06 19:46:39 -0700 · SteveStudio2
Files touched
M src/jobs/morning_feature_email.ts
Diff
commit 48b33424cd5e7bc5e57338577c7560befe9acf74
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed May 6 19:46:39 2026 -0700
iter 164: morning_feature_email now includes 'Suggested next publish' block — draft-pick-of-the-night
---
src/jobs/morning_feature_email.ts | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/src/jobs/morning_feature_email.ts b/src/jobs/morning_feature_email.ts
index 192500b..ad0cdbe 100644
--- a/src/jobs/morning_feature_email.ts
+++ b/src/jobs/morning_feature_email.ts
@@ -27,6 +27,22 @@ async function main() {
if (r.rowCount === 0) { console.log('[morning_email] no candidate feature'); await pool.end(); return; }
const f = r.rows[0];
+ // Draft pick of the night — strongest unpublished draft from last 24h, scored.
+ const dp = await query(`
+ SELECT mf.id, mf.headline, mf.subhead, mf.editorial, mf.category_tag, length(mf.editorial) AS editorial_len,
+ b.name AS biz_name,
+ (length(mf.editorial) +
+ CASE WHEN mf.pull_quote IS NOT NULL THEN 100 ELSE 0 END +
+ CASE WHEN mf.subhead IS NOT NULL THEN 50 ELSE 0 END +
+ COALESCE((be.ad_signals->>'paid_ads_count')::int, 0) * 30) AS score
+ FROM magazine_features mf
+ JOIN businesses b ON b.id = mf.business_id
+ LEFT JOIN business_enrichment be ON be.business_id = mf.business_id
+ WHERE mf.status = 'draft' AND mf.generated_at > NOW() - INTERVAL '24 hours' AND length(mf.editorial) > 240
+ ORDER BY score DESC LIMIT 1
+ `);
+ const draftPick = dp.rows[0] || null;
+
const html = `<div style="font-family:Georgia,serif;max-width:580px;color:#1a1a1a;background:#faf6ee;padding:32px">
<div style="font-size:9px;letter-spacing:.4em;text-transform:uppercase;color:#8a6d3b;font-family:Helvetica,sans-serif;font-weight:500">The Corridor · ${new Date().toLocaleDateString('en-US',{weekday:'long',month:'long',day:'numeric'})}</div>
<h1 style="font-family:Georgia,serif;font-style:italic;font-weight:500;font-size:36px;margin:14px 0 8px;line-height:1.05">${esc(f.headline || f.biz_name)}</h1>
@@ -37,6 +53,12 @@ ${f.pull_quote ? `<div style="font-style:italic;font-size:18px;color:#6a3a1a;bor
<strong>${esc(f.biz_name)}</strong> · ${esc(f.biz_address || '')} · ${esc(f.city || '')}<br>
<span style="color:#8a6d3b">category: ${esc(f.category_tag || '')}</span>
</div>
+${draftPick ? `<div style="margin-top:30px;padding:18px 20px;background:rgba(184,153,104,0.10);border:1px solid #d8cdb8;border-left:3px solid #8a6d3b">
+ <div style="font-size:9px;letter-spacing:.4em;text-transform:uppercase;color:#8a6d3b;font-family:Helvetica,sans-serif;font-weight:500;margin-bottom:8px">Suggested next publish</div>
+ <div style="font-family:Georgia,serif;font-style:italic;font-size:20px;line-height:1.15;margin-bottom:6px"><a href="http://127.0.0.1:9780/magazine/${draftPick.id}" style="color:#1a1815;text-decoration:none;border-bottom:1px solid #8a6d3b">${esc(draftPick.headline || draftPick.biz_name)}</a></div>
+ ${draftPick.subhead ? `<div style="font-family:Georgia,serif;font-style:italic;color:#6e6356;font-size:13px;margin-bottom:8px">${esc(draftPick.subhead)}</div>` : ''}
+ <div style="font-size:11px;color:#888;font-family:Helvetica,sans-serif;letter-spacing:.05em">${esc(draftPick.biz_name)} · ${esc(draftPick.category_tag || '')} · ${draftPick.editorial_len}c · score ${draftPick.score}</div>
+</div>` : ''}
<div style="margin-top:18px;font-size:10px;color:#888;font-family:Helvetica,sans-serif;letter-spacing:.05em">
Read more issues at <a href="http://127.0.0.1:9780/issue" style="color:#8a6d3b">/issue</a> · admin <a href="http://127.0.0.1:9780/magazine.html" style="color:#8a6d3b">/magazine</a>
</div>
← 280b679 iter 163: /api/magazine/draft-pick-of-the-night + 'Publish n
·
back to Ventura Corridor
·
iter 165: /api/magazine/duplicates + nav pill — surfaces qwe 680bcb7 →