[object Object]

← back to Ventura Corridor

fix: move RSS route ahead of /issue/:cat handler — Express was matching 'feed.xml' as a category and serving the HTML issue page; RSS route now defined first; /issue/:cat/feed.xml correctly returns RSS XML for vertical-specific feeds

a45aad19e0ced1287e71ccccbb49b3e47be26697 · 2026-05-06 17:38:38 -0700 · SteveStudio2

Files touched

Diff

commit a45aad19e0ced1287e71ccccbb49b3e47be26697
Author: SteveStudio2 <steve@designerwallcoverings.com>
Date:   Wed May 6 17:38:38 2026 -0700

    fix: move RSS route ahead of /issue/:cat handler — Express was matching 'feed.xml' as a category and serving the HTML issue page; RSS route now defined first; /issue/:cat/feed.xml correctly returns RSS XML for vertical-specific feeds
---
 src/server/index.ts | 90 ++++++++++++++++++++++++++++-------------------------
 1 file changed, 48 insertions(+), 42 deletions(-)

diff --git a/src/server/index.ts b/src/server/index.ts
index 5670946..36e68e3 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -1971,6 +1971,51 @@ Write the feature.`;
   }
 });
 
+// /issue/feed.xml or /issue/:cat/feed.xml — RSS feed (must be defined BEFORE /issue/:cat
+// or Express matches "feed.xml" as a category)
+app.get(['/issue/feed.xml', '/issue/:cat/feed.xml'], async (req, res) => {
+  try {
+    const cat = (req.params as any).cat || null;
+    const baseUrl = process.env.PUBLIC_BASE_URL || 'http://127.0.0.1:9780';
+    const where: string[] = [`status = 'published'`];
+    const params: any[] = [];
+    if (cat) { params.push(cat); where.push(`category_tag = $${params.length}`); }
+    const r = await query(
+      `SELECT mf.id, mf.headline, mf.subhead, mf.editorial, mf.published_at, mf.category_tag,
+              b.name AS biz_name
+       FROM magazine_features mf JOIN businesses b ON b.id = mf.business_id
+       WHERE ${where.join(' AND ')}
+       ORDER BY published_at DESC LIMIT 50`,
+      params
+    );
+    const esc = (s: any) => String(s ?? '').replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]!));
+    const items = r.rows.map((f: any) => `
+    <item>
+      <title>${esc(f.headline || f.biz_name)}</title>
+      <link>${baseUrl}/magazine/${f.id}</link>
+      <guid isPermaLink="true">${baseUrl}/magazine/${f.id}</guid>
+      <pubDate>${new Date(f.published_at || Date.now()).toUTCString()}</pubDate>
+      <category>${esc(f.category_tag || 'feature')}</category>
+      <description>${esc(f.subhead || '')} — ${esc(f.biz_name)}</description>
+      <content:encoded><![CDATA[${esc(f.editorial || '')}]]></content:encoded>
+    </item>`).join('');
+    const title = cat ? `The Corridor — ${cat}` : 'The Corridor';
+    res.setHeader('Content-Type', 'application/rss+xml; charset=utf-8');
+    res.send(`<?xml version="1.0" encoding="UTF-8"?>
+<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
+  <channel>
+    <title>${esc(title)}</title>
+    <link>${baseUrl}${cat ? '/issue/' + esc(cat) : '/issue'}</link>
+    <description>A magazine of who's here on Ventura Boulevard.${cat ? ' Vertical: ' + esc(cat) + '.' : ''}</description>
+    <language>en-us</language>
+    <lastBuildDate>${new Date().toUTCString()}</lastBuildDate>${items}
+  </channel>
+</rss>`);
+  } catch (e: any) {
+    res.status(500).send('error: ' + e.message);
+  }
+});
+
 // /issue — the curated public-facing issue (status='published' only)
 // Mirrors /magazine.html aesthetic but stripped of admin controls + prints clean.
 app.get(['/issue', '/issue/:cat'], async (req, res) => {
@@ -2111,48 +2156,9 @@ ${urls.join('\n')}
   }
 });
 
-// /issue/feed.xml or /issue/:cat/feed.xml — RSS for the (vertical-) issue
-app.get(['/issue/feed.xml', '/issue/:cat/feed.xml'], async (req, res) => {
-  try {
-    const cat = (req.params as any).cat || null;
-    const baseUrl = process.env.PUBLIC_BASE_URL || 'http://127.0.0.1:9780';
-    const where: string[] = [`status = 'published'`];
-    const params: any[] = [];
-    if (cat) { params.push(cat); where.push(`category_tag = $${params.length}`); }
-    const r = await query(
-      `SELECT mf.id, mf.headline, mf.subhead, mf.editorial, mf.published_at, mf.category_tag,
-              b.name AS biz_name
-       FROM magazine_features mf JOIN businesses b ON b.id = mf.business_id
-       WHERE ${where.join(' AND ')}
-       ORDER BY published_at DESC LIMIT 50`,
-      params
-    );
-    const esc = (s: any) => String(s ?? '').replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]!));
-    const items = r.rows.map((f: any) => `
-    <item>
-      <title>${esc(f.headline || f.biz_name)}</title>
-      <link>${baseUrl}/magazine/${f.id}</link>
-      <guid isPermaLink="true">${baseUrl}/magazine/${f.id}</guid>
-      <pubDate>${new Date(f.published_at || Date.now()).toUTCString()}</pubDate>
-      <category>${esc(f.category_tag || 'feature')}</category>
-      <description>${esc(f.subhead || '')} — ${esc(f.biz_name)}</description>
-      <content:encoded><![CDATA[${esc(f.editorial || '')}]]></content:encoded>
-    </item>`).join('');
-    const title = cat ? `The Corridor — ${cat}` : 'The Corridor';
-    res.setHeader('Content-Type', 'application/rss+xml; charset=utf-8');
-    res.send(`<?xml version="1.0" encoding="UTF-8"?>
-<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
-  <channel>
-    <title>${esc(title)}</title>
-    <link>${baseUrl}${cat ? '/issue/' + esc(cat) : '/issue'}</link>
-    <description>A magazine of who's here on Ventura Boulevard.${cat ? ' Vertical: ' + esc(cat) + '.' : ''}</description>
-    <language>en-us</language>
-    <lastBuildDate>${new Date().toUTCString()}</lastBuildDate>${items}
-  </channel>
-</rss>`);
-  } catch (e: any) {
-    res.status(500).send('error: ' + e.message);
-  }
+// (RSS route moved earlier — see /issue/feed.xml above)
+app.get('/__rss-removed', (_req, res) => {
+  res.status(410).send('moved');
 });
 
 app.get('/robots.txt', (_req, res) => {

← fa94a30 iter 104+105+106+107+108: regen-thin job + sitemap + robots  ·  back to Ventura Corridor  ·  iter 109+110: building-mates on /magazine/:id reader + score 715edc1 →