[object Object]

← back to Ventura Corridor

feat(news): news_count badge on /buildings.html tenant rows

04183311f91c3951b6ec8ee5b6a4dcfa6b8f267a · 2026-05-07 13:12:06 -0700 · SteveStudio2

When Steve clicks an address on /buildings to expand its tenant
roster, any tenant with scraped news_items now shows a small
gold-border pill: 📰 N (where N = article count). Click goes to
/news.html#biz-{id} for filterable access.

API change:
  /api/buildings/:bldg                +news_count INT per tenant row
                                      via LATERAL count from news_items

UI change:
  public/buildings.html roster table  badge appended to tenant name
                                      cell, only when news_count > 0

Verified: 14622 Ventura Boulevard Sherman Oaks 91403 has 9 tenants,
3 with news (Baja Fresh, Noah's Bagels, The Habit Burger Grill).

Continues the discoverability theme from tick 41 (map detail panel
news rail) — every existing surface that shows businesses now has a
quiet way to surface what their site has been publishing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 04183311f91c3951b6ec8ee5b6a4dcfa6b8f267a
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Thu May 7 13:12:06 2026 -0700

    feat(news): news_count badge on /buildings.html tenant rows
    
    When Steve clicks an address on /buildings to expand its tenant
    roster, any tenant with scraped news_items now shows a small
    gold-border pill: 📰 N (where N = article count). Click goes to
    /news.html#biz-{id} for filterable access.
    
    API change:
      /api/buildings/:bldg                +news_count INT per tenant row
                                          via LATERAL count from news_items
    
    UI change:
      public/buildings.html roster table  badge appended to tenant name
                                          cell, only when news_count > 0
    
    Verified: 14622 Ventura Boulevard Sherman Oaks 91403 has 9 tenants,
    3 with news (Baja Fresh, Noah's Bagels, The Habit Burger Grill).
    
    Continues the discoverability theme from tick 41 (map detail panel
    news rail) — every existing surface that shows businesses now has a
    quiet way to surface what their site has been publishing.
    
    Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---
 public/buildings.html | 2 +-
 src/server/index.ts   | 6 +++++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/public/buildings.html b/public/buildings.html
index 11a1917..c1aefa7 100644
--- a/public/buildings.html
+++ b/public/buildings.html
@@ -357,7 +357,7 @@ async function toggleBldg(addrEl) {
         ${rows.map(r => `
           <tr>
             <td class="suite">${escapeHtml(r.suite || '')}</td>
-            <td class="name">${escapeHtml(r.name)}${dupeBadge(r.business_id)}</td>
+            <td class="name">${escapeHtml(r.name)}${dupeBadge(r.business_id)}${r.news_count > 0 ? `<span class="pill" style="color:var(--metal-glow);border-color:var(--metal-glow);font-size:7px;margin-left:6px" title="${r.news_count} scraped news/blog post${r.news_count === 1 ? '' : 's'}"><a href="/news.html#biz-${r.business_id}" style="color:inherit;text-decoration:none">📰 ${r.news_count}</a></span>` : ''}</td>
             <td class="naics">${escapeHtml((r.naics || '').slice(0, 50))}</td>
             <td>${r.pitch_id
               ? `<span class="pill ${r.status}">${escapeHtml(r.status)}</span>`
diff --git a/src/server/index.ts b/src/server/index.ts
index 3b12f64..07a7e1c 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -1635,9 +1635,13 @@ app.get('/api/buildings/:bldg', async (req, res) => {
               bc.lat, bc.lng, bc.phone, bc.website, bc.category, bc.naics,
               p.id AS pitch_id, p.pitch_type, p.priority, p.status, p.outreach_channel,
               p.dw_proximity, p.sent_at, p.replied_at, p.closed_at, p.won_value_usd,
-              p.li_message, p.contact_name, p.notes
+              p.li_message, p.contact_name, p.notes,
+              COALESCE(n.news_count, 0)::int AS news_count
        FROM v_building_canonical bc
        LEFT JOIN pitches p ON p.business_id = bc.id
+       LEFT JOIN LATERAL (
+         SELECT COUNT(*) AS news_count FROM news_items WHERE business_id = bc.id
+       ) n ON TRUE
        WHERE bc.bldg_address = $1
        ORDER BY
          CASE WHEN p.id IS NULL THEN 1 ELSE 0 END,

← fd03767 feat: apply_exa_websites.ts — merge Exa-discovered website J  ·  back to Ventura Corridor  ·  fix(security): escape source_url + scheme-validate href in / 7594bb3 →