The Tech Stack Decisions
Frontend: Next.js 14 with App Router
We could have used something simpler, but Next.js 14's App Router gives us server-side rendering for the trend feed, which matters for load performance. We're fetching from Supabase on the server, rendering the content, and hydrating the interactive parts on the client. Clean, fast, and we know the stack well.
Embedding pipeline: OpenAI text-embedding-3-small
We evaluated a few embedding models. OpenAI's text-embedding-3-small hits the right balance of quality, speed, and cost for this use case. At $0.02 per million tokens, embedding several thousand content pieces per day is essentially free at the volume we're running.
Vector database: Pinecone
For semantic similarity search at scale, Pinecone is our default. We're storing embeddings with metadata (source, date, content type, source URL) and querying by similarity with metadata filters. The managed service means no infrastructure maintenance.
Trend detection: LangChain + Claude 3.5 Sonnet
The trend synthesis layer is where the interesting work happens. We embed incoming content, cluster similar pieces using cosine similarity in Pinecone, and then pass the clusters to Claude 3.5 Sonnet to generate trend summaries. Claude is unusually good at identifying the underlying theme in a cluster of semantically similar content and articulating it in plain language.
Backend: Node.js with a content ingestion queue
A lightweight Node.js API handles the content ingestion pipeline. Content from configured RSS feeds, newsletters (via email parsing), and manual URL submissions goes into a queue, gets fetched, chunked, embedded, and stored.
Scheduled processing: Vercel Cron + Edge Functions
We run the ingestion pipeline every 4 hours and the trend synthesis every 24 hours. Vercel Cron triggers the jobs, Edge Functions handle the lightweight orchestration, and a separate Node.js worker handles the heavy lifting.
Database: Supabase
Postgres via Supabase for structured data (user preferences, source configurations, trend history). We use Supabase's Row Level Security to scope data per user. The Supabase JS client makes the integration trivially easy from Next.js.