Skip to content

Combined topic views: /topics/business,saas,crypto (0.3.0) - #267

Merged
sh1pt-actions-fleet[bot] merged 1 commit into
mainfrom
feat/multi-topic
Nov 2, 2026
Merged

sh1pt-actions-fleet[bot] merged 1 commit into
mainfrom
feat/multi-topic

Conversation

@sh1pt-actions-fleet

Copy link
Copy Markdown
Contributor

What

/topics/business,saas,crypto (and every other topic surface) now takes a comma list: the union of the topics, every feed filed under any of them, each feed once.

Surface Example
HTML page + sub-groups /topics/a,b,c, /topics/a,b,c/blogs (title "a, b, c", a link to each topic, unknown ones named)
JSON API /api/topics/a,b,c?group=&limit=&offset= (same shape; adds topics, unknown, per-feed topics)
Feeds / playlists /topics/a,b,c.rss, /topics/a,b,c/blogs.json, /api/topics/[keyword]/feed/[format], [group]/feed/[format] (one river, newest first)
Player /topics/a,b/play, /topics/a,b/podcasts/play, add-all queue
MCP get_topic, topic_posts accept "business, saas, crypto"

Rules

  • A single topic runs the old code path and SQL unchanged (verified locally against prod: /api/topics/business identical to live).
  • , / %2C / spaces accepted; slugs normalised and deduped; max 10 (400 beyond). Nothing known: 404. Partly known: show the known ones and name the unknown. A list that collapses to one topic (business,Business) is that topic.
  • Ordering: tagged by its publisher under any listed topic first, then strength summed across the topics, then title.
  • Performance: one statement per query with slug in (...) (the house kindFilter-style placeholders). The river picks each topic's strongest max(50, 2*200/n) feeds so one big topic cannot crowd out the rest. Timed against prod (warm): union listing 68 ms, kind counts 80-106 ms (count(distinct); the in (subquery) version was 0.3-2 s), river 169 ms, 10 large topics 0.4-0.6 s.
  • SEO: combined pages canonicalise to themselves and are noindex, follow, like the player pages. Sitemaps unchanged. Follow/webring buttons hidden on combined views (they are keyed on one slug).

Tests

  • packages/db/test/multi-topic.test.js: single-element list equals single topic, union dedupe/order/paging/filter, counts, river, media.
  • apps/web/test/topic-set.test.js: parsing, API shape for one vs many, 404/400, feed route, MCP tools.
  • bun run test all green; bun run build green.

🤖 Generated with Claude Code

A comma in a topic URL now means a list (up to 10; %2C and spaces accepted,
slugs normalised and deduped). The view is the union of the topics: every
feed filed under any of them, each once. Order: tagged by its publisher under
any listed topic first, then strength summed across the topics.

Works on every topic surface: /topics/a,b and /topics/a,b/<group>, the JSON
API /api/topics/a,b (same shape, plus `topics` and `unknown`), the feeds and
playlists (/topics/a,b.rss, /topics/a,b/<group>.json, /api/topics/.../feed/*),
the player pages and add-all queue, and the MCP get_topic / topic_posts tools.

A single topic takes exactly the old code path and SQL. Unknown topics in a
list are named and the known ones shown; nothing known is a 404, more than 10
a 400. Combined pages canonicalise to themselves and are noindex; sitemaps are
unchanged. Each query is one statement with `slug in (...)`; the river picks
each topic's strongest feeds (max(50, 2*200/n) per topic) so one large topic
cannot crowd the others out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sh1pt-actions-fleet
sh1pt-actions-fleet Bot merged commit 337cfb4 into main Nov 2, 2026
3 checks passed
@sh1pt-actions-fleet
sh1pt-actions-fleet Bot deleted the feat/multi-topic branch November 2, 2026 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant