- analytics: union byDayReal+byDayBot keys so bot-only days aren't dropped from range totals
- analytics: exclude timestamp-less visitor rows from range filters (was unconditionally including them)
- App.tsx: init `configured` to false so a network failure doesn't show a misleading "no episodes" state; add r.ok guard before r.json()
- episodes.js: wrap fetch in try/catch so clearTimeout is called on network failure, matching the nuggets.js pattern
- helpers.js: add sanitizeNuggets + wire it into sanitizeSiteContent so corrupted hosts/urls can't crash NuggetsPage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New /nuggets page for the companion show, linked from the Episodes nav
dropdown. Hosts (name, role, bio, photo) show in a left column with the
episode list on the right — latest episode featured, rest below.
Episodes are pulled from an admin-configurable RSS feed URL (empty by
default, shows "coming soon" until set) rather than hardcoded like the
main show's feed, since the show doesn't have one yet.
Everything is editable in /admin under a new Nuggets section: Show
Settings (title, tagline, description, podcast art, RSS/platform URLs)
and Hosts (add freely; removing a host archives them instead of
deleting — kept on record and restorable, never lost).
Extracted the RSS item-parsing logic shared with the main show's feed
(server/routes/episodes.js) into server/rss-helpers.js so both feeds
use the same parser instead of duplicating it.
Also fixes the local Vite dev server not proxying /uploads/* to the
backend — it was silently serving the SPA shell (200, text/html)
instead of the actual file, so any admin-uploaded image (podcast art,
host photos, etc.) appeared broken in local dev only.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Yvx4rPVy2HWe7ubuk3X3J
RSS Feed
- /feed.xml proxies the Anchor feed under the site's canonical domain
- Rewrites channel <link> and atom:link self-ref to the site URL
- Served with 30-min Cache-Control, reuses the existing episode cache
PWA
- vite-plugin-pwa installed; Workbox service worker auto-generated on build
- manifest.json inlined in vite.config.ts (name, icons, theme, standalone)
- pwa-192.png and pwa-512.png generated from existing book_icon.png
- StaleWhileRevalidate for /api/episodes and /api/questions; CacheFirst for images
- API, feed.xml, and uploads routes excluded from navigate fallback
Lesson Comments
- Import and wire StudySectionComments into ColossiansStudySectionPage
- Replaces the CommunityBoard in the Lesson Discussion section
- All routes and moderation already existed; only the render was missing
Progress Tracking + Streaks
- Mark-complete handler now records lastStudiedDate, currentStreak, longestStreak on the user record
- Streak increments on consecutive calendar days, resets on a gap
- /api/study-account/overview now returns streak fields
- Account page: 4-stat summary row (notes, streak 🔥, longest streak, member since)
- Per-study progress bars showing completedLessons/totalLessons with gold → green fill at 100%
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New FinishedBook type in content.ts + finishedBooks[] field on SiteContent
- RSS parser now extracts itunes:season into each episode object
- /finished grid page and /finished/:id playlist page (filters episodes by season)
- Episodes nav link replaced with dropdown: Current Series / Finished Books
- Finished Books link added to footer
- Admin: "End Current Series & Start New Book" wizard on Current Series tab
- Admin: Finished Books management tab (add/edit/remove entries)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add /api/episode-audio route returning MP3 URLs from Anchor RSS feed
- Replace Spotify URL text inputs in admin with RSS episode dropdowns
- New EpisodeAudioPlayer component with podcast art, show name, progress
bar, and Spotify icon link — full and compact sizes
- Backward-compatible: legacy Spotify embed URLs still render as iframes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>