Fireweld Tesfaye
← Back to work

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.

Stack

Next.jsReactAuth.jsPrismaSQLiteTailwind CSSrss-parser