The new A-monogram placeholder shipped in d8ca8ff was correct in the
deployed container, but Cloudflare was serving the previous cached SVG
(cf-cache-status: HIT, last-modified from this morning) because the
account token doesn't carry Zone:Cache Purge scope, so we couldn't
issue an API purge.
Renaming the file to article-placeholder-v2.svg gives CF a fresh URL
to cache, sidestepping the missing-permission entirely. Updated all
6 referencing files (AppImage fallback, legacy-source FALLBACK_IMAGE
constants, FeaturedBento[FromDb], manufacturers/authors pages).
Old file (cached as the old wordmark) just becomes a dangling asset —
not referenced from anywhere, harmless.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two pointed bugs on the article detail page:
1) Width alignment. The right-rail Related Articles and Related Forum
Posts boxes were free-stretching to the lg:col-span-4 width while the
SidebarAdStack below them rendered ads at their natural 300px (items-
end, right-aligned). The visual result: boxes overhung the ad column
on both edges. Wrapped each sidebar in an inner `w-full lg:w-[300px]
lg:ml-auto` div so every block (ads + boxes + newsletter) shares one
300px column on lg+ and stays full-width on mobile. Applied to both
article templates (/articles/[slug] and /news/[slug]).
2) Placeholder rendered the old "AV BEAT" wordmark when an article had no
featured image. Rebuilt article-placeholder.svg around the new brand
mark — the A-monogram tile with the blue gradient (#2563EB→#1E3A8A)
that matches AnimatedLogo + the rest of the brand-gradient system.
Same 1200×630 dimensions so OG/feed embeds aren't affected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sarah Quinn's author page (and any article missing a featured_image) was
showing the old BB-branded placeholder. New SVG uses the AV Beat navy/cyan
palette and 'PRO AV · DISPLAY · LIVE PRODUCTION' tagline.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- SVG logo at public/brand/logo.svg with pink-magenta BROADCAST,
cyan BEAT, cyan heartbeat waveform underline, ™ mark, and
"THE PULSE OF PRODUCTION INTELLIGENCE" tagline
- PNG renders at 1x (1200x320), 2x (2400x640), small (600x160)
- Header swapped from /assets/images/logo.png to /brand/logo.svg
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
USER PROFILES (/forum/user/[username]):
- New API at /api/forum/user-by-username/[username] resolves by
username OR display_name (URL-encoded), since forum threads/replies
store author_name = display_name. Returns the persona's profile,
thread history (up to 50), and recent replies (up to 20).
- New page renders the persona card with archetype badge
(Audio Engineer / Colorist / etc.) + expertise level badge
(beginner/intermediate/senior) + role title, company, location,
years_experience, join date, and an expertise-tags chip row.
- Two columns underneath: "Threads started" and "Recent replies"
with proper deep-links into each thread.
- Author names in /forum, /forum/[slug], and /forum/thread/[id] are
now <Link> elements pointing to /forum/user/<displayname>, with
onClick=stopPropagation so the card-level click handler doesn't
also fire.
FAVICON:
- Hand-built neon pulse waveform — emerald→cyan→purple gradient on
dark navy background, designed to read at 16×16 to 256×256.
- Multi-resolution favicon.ico (16/32/48/64) + SVG + PNGs at
16/32/48/64/96/192/256 under /static/favicons/.
- layout.tsx icons block now references all sizes including the
apple-touch sizes (192, 256).
No env / DB changes here — pure deploy.
Row 1 (Live Wire, scrolls →): most recent imported + AI-rewritten
articles, neon-green label, monospaced [HH:MM] [SOURCE_CODE] prefix.
Row 2 (On Calendar, scrolls ←, slower): upcoming events from
bb.events (confirmed/tentative, start_date >= today), neon-cyan
label, [Mon DD] [SHORT_NAME] prefix.
Defensive: each query is in its own try/catch so a partial failure
renders an empty row rather than crashing the page — that was the
silent build crash that took down the prior DoubleTicker incarnation.
If BOTH queries return zero rows we render nothing instead of two
blank bars.
CSS tokens added to redesign-tokens.css:
- bb-marquee--reverse + bb-marquee--slow modifiers
- .bb-neon-bar / .bb-neon-label / .bb-neon-time / .bb-neon-code
(scoped class names so this is the ONLY place on the site that
uses the neon palette — rest of the site keeps dark-navy + blue)
User cancelled the wholesale neon redesign; only the dual-ticker
keeps the neon green/cyan styling.
Tables (Phase B+):
bb.ad_impressions — every render = a row. is_bot + viewport flags
for filtering. No unique constraints — gross
counts per Ry an spec.
bb.ad_clicks — every /r/[slug] hit = a row.
bb.ad_campaign_clients — schema only; future client reporting.
FK target is bb.banner_creatives (the renderer table from 5/15 banner
refresh). bb.ad_campaigns is the AdOps billing schema and unrelated.
Routes:
GET /r/[slug] — log click, 302 to bb.banner_creatives.click_url
POST /api/track/impression — record impression (slug | campaign_id),
used by client beacon
AdImage rewrite:
- link href is /r/{slug} target=_blank rel=sponsored noopener noreferrer
- sendBeacon on mount fires impression (viewport=false)
- additional sendBeacon on IntersectionObserver ≥0.5 (viewport=true)
- removed direct supabase.from('banner_analytics').insert path
Ad type carries slug now; FALLBACK list + DB mapper both populate it.
/admin/banners:
per-row stats — 24h, 7d, lifetime impressions/clicks/CTR
link to /admin/banners/[id]/analytics
/admin/banners/[id]/analytics (new):
recharts line charts for impressions + clicks (30d), top page paths,
top referrer domains, bot/human toggle.
Tower Products orphan image file removed; banner was not in any active
table or in code (already off rotation).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Backend:
bb.banner_creatives (new) — image_path, click_url, size, start/end_date,
status, adsanity_source_id. Seeded with 8 banners from broadcas_temp
WP-export DB (post_type=ads): LiveU 728x90, Blackmagic DaVinci Resolve
20 (300x600), Studio Hero, Magewell Pro-Convert, LiveU PAYG, AJA
ColorBox, Zixi, Lectrosonics (all 300x250). Dates and click URLs come
from the AdSanity rows; current creatives downloaded from Wayback
snapshot 20260316123737.
src/lib/ads.ts:
- Reads bb.banner_creatives via anon supabase-js client, gated by
status='active' AND start<=NOW()<=end.
- In-process 5-min TTL cache with stale-while-revalidate. Module load
primes the cache; clients see fallback on first hit, live DB on
subsequent.
- Hardcoded FALLBACK list mirrors the seeded rows so the site keeps
rendering banners if Supabase is unreachable during deploy.
- Public helpers (rotateAll, pickAds, ADS_728X90, ADS_300X250,
FIXED_300X600) remain synchronous so existing client component
callsites work unchanged.
/admin/banners:
Admin-only list + inline editor for every banner_creatives row:
name, click URL, start/end date, status (active|scheduled|paused|
expired). PATCH via /api/admin/banners/[id] — service_role bypass for
the write, user_profiles.role admin/administrator for the gate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Magewell was removed when Adsanity went away; PENDING_ads.md flagged it
along with AJA/Zixi/Lectrosonics/Opengear/Studio Hero for real creatives.
This restores Magewell with an in-house SVG placeholder (red/dark Magewell
brand color, wordmark + tagline + CTA chip) so the sidebar 300x250 stack
gets three rotating entries again instead of two. Real Magewell creative
to land when sourced from the vendor.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pluggable rewrite client (Anthropic default, ollama/openrouter stubs)
using claude-opus-4-7 with prompt caching on system prompt + style guide.
Routes the raw submission through:
1. bb.ai_original_submissions — raw never edited
2. bb.ai_rewrite_jobs — every attempt logged with token counts
3. quality gates — AI-tell banned-word check + heuristic
AI-detector score (threshold 0.65)
4. regenerate up to 3x — on banned words or detector trip
5. bb.ai_rewritten_articles — status ai_rewritten_pending_review
6. /admin/review-queue — list + detail page with approve / reject /
needs-human actions; on approve, the
original submission is FK-linked to the
published rewrite
New files only — no existing routes or contributor flow modified.
Persona auto-selection routes by beat keywords; 6 personas seeded
(marcus-halverson, elena-vasquez, darren-okafor, sarah-quinn, mike-trayton,
priya-rao) with SVG monogram avatars in public/assets/images/personas/.
Smoke test (Matrox / ST 2110 sample press release):
- persona auto-routed to darren-okafor (protocols-specs)
- anthropic 22.3s, in=2616 / out=1372 tokens
- gates passed first try, score=0.000, no banned words
- review_queue row created
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
P0-2 (Adsanity iframe path removed):
- AdImage.tsx: deleted the iframe branch and the ADSANITY_CAMPAIGN_MAP
fallback. AdImage now renders local images only; banners without a
src render nothing.
- ads.ts: removed Ad.adsanity_id from the interface. Pruned AJA, Zixi,
Lectrosonics, Opengear, Studio Hero, Magewell 300x250 and Blackmagic
300x600 — they relied on ads.broadcastbeat.com which does not resolve.
Surviving live banners: LiveU 728x90, LiveU PAYG 300x250, Telycam 300x250.
- SidebarAdStack: key no longer references the removed field.
- No banner_analytics rows reference ads.broadcastbeat.com.
Phase A (SEO baseline):
- robots.ts: fallback base URL now broadcastbeat.com (was rocket staging URL).
- sitemap.ts: fallback base URL now broadcastbeat.com (was bb-staging).
- news/[slug]/page.tsx and articles/[slug]/page.tsx: same fallback fix.
JSON-LD now uses ISO 8601 for datePublished, absolute image URL via
SITE_URL prefix, and publisher.logo points at /assets/images/logo.png
instead of the 404-ing /legacy/site/broadcastbeat-logo.png.
- layout.tsx: removed the /en /es /pt /fr /de /zh /ja /ar /hi hreflang
alternates - those routes 404 today; Phase D will reinstate. Replaced
rocket.new Organization schema URL with broadcastbeat.com. Set
robots index/follow=false until Phase B-D land and Rich Results passes.
Featured-image fallback hardening:
- legacy-source: rowToArticle now treats BB_Gray, no_image and placeholder
URLs as null and falls back to the new placeholder so dead images do not
leak through to the page.
- public/assets/images/article-placeholder.svg: new clean dark gradient
with BroadcastBeat wordmark, NOT no_image.png style.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove duplicate 728x90 LeaderboardAd below news ticker (per Ryan)
- Footer: remove NAB Official Media Partner badge
- Header: replace AdSlot stub with real AdImage rotation (3 verified 728x90s)
- Header: fix logo path from dead WP URL to local /assets/images/logo.png
- ads.ts: only include ads with verified real images (3x728x90, 2x300x250)
- ads.ts: remove 22 unrecovered ads — see PENDING_ads.md for upload list
- SidebarAdStack: handle null FIXED_300X600 gracefully (Blackmagic not recovered)
- public/legacy/ads/: 5 real ad images committed (Tower, Sony, LiveU 728x90; LiveU PAYG, Telycam 300x250)
- public/assets/images/logo.png: recovered from Wayback Machine
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>