Personal project
Zenaye
A tech-news aggregator that pulls stories from popular RSS feeds into a single fast, dark-themed feed — with accounts, bookmarks, and a personalizable default view.
Problem
Following tech news across TechCrunch, The Verge, Ars Technica, Hacker News, Wired, and Engadget means juggling multiple sites. Readers need one feed with filtering, save-for-later, and a default tailored to what they care about.
Contribution
Built the full stack: server-side RSS ingestion with a 15-minute TTL cache, Auth.js credentials auth, Prisma-backed bookmarks and preferences, and a responsive Next.js UI with skeletons and empty/error states.
Outcome
A working aggregator with source filtering, accounts, per-user bookmarks, and personalization — built on Next.js 16 App Router, React 19, Auth.js v5, Prisma 6 (SQLite), and Tailwind CSS v4.
Technical decisions
- Fetch and normalize feeds server-side into a shared Article shape, then merge/sort newest-first with an in-process cache keyed by the source set.
- Use Auth.js Credentials with bcrypt and JWT sessions (no database session table) so user id can scope bookmarks and preferences.
- Store denormalized article snapshots on bookmarks so saved stories render without re-fetching upstream feeds.
- Persist favorite source ids on the user and use them as the logged-in default feed when no explicit ?source= filter is present.
Feed pipeline
Sources are registered in a feed helper, fetched with rss-parser, normalized, merged, and sorted. An in-process TTL cache (15 minutes) avoids hitting upstream feeds on every request. Source filtering is available via ?source=.
Auth, bookmarks, and preferences
Email/password auth uses Auth.js with bcrypt verification and JWT sessions. Bookmarks and favorite sources are scoped to the session user through Server Actions and REST endpoints. Preferences drive the default home feed for logged-in readers.
Product polish
The UI includes loading skeletons, empty and error states, and a responsive layout so the feed stays usable while data loads or when a source returns nothing.
Scope & limitations
Feed caching is in-process (fine for a single Node instance). Upstream feed availability and rate limits still depend on third-party sources.