✦ Inspiration

We live in the age of information overload. Every news app floods you with whatever gets the most clicks — not what you actually want to read. I wanted to build something different: a platform where you define your feed from the very first login, and the content actually reflects your curiosity.

That's how FocusFeed was born — a clean, fast, full-stack personalized news experience built around your interests, not an algorithm's agenda.


🔨 How I Built It

FocusFeed is a full-stack web application with a clean separation of concerns across every layer.

Backend — Node.js + Express REST API

The server is structured around the MVC pattern:

  • Models (Mongoose): User, Bookmark, Category — each with validation, indexing, and pre-save hooks
  • Controllers: Separate controllers for auth, articles, bookmarks, users, and admin operations
  • Services: A dedicated news.service.js handles all external API communication with a multi-provider fallback chain (NewsAPI → GNews → MediaStack → TheNewsAPI), and analytics.service.js runs MongoDB aggregation pipelines for the admin dashboard
  • Middleware: auth.middleware.js validates JWT on every protected route; role.middleware.js enforces admin-only access using restrictTo()
  • Utils: Standardized sendSuccess / sendError response helpers and JWT generateToken / verifyToken wrappers keep the codebase consistent

Authentication uses bcryptjs (12 salt rounds) for password hashing and 7-day JWT tokens stored in sessionStorage for XSS safety.

Frontend — Vanilla HTML, CSS & JavaScript

No frontend frameworks — every page is hand-crafted:

  • A custom CSS design system built on CSS variables supports full light/dark theming, consistent spacing, shadows, and radius tokens across all 12+ pages
  • Responsive layouts using CSS Grid and Flexbox — mobile bottom nav, collapsible sidebar, adaptive feed grid
  • A shared API layer (api.js) centralizes all fetch calls with Bearer token injection, 401 auto-redirect, and session cleanup
  • Session management without a framework: token validation on every page load, a 30-minute inactivity auto-logout with a 2-minute warning toast, and cross-tab last-activity tracking via localStorage

News Aggregation

Articles are fetched live by interest category. The feed is built by querying multiple news APIs in sequence — if one provider fails or hits a rate limit, the next one takes over automatically. 18 interest categories are supported: Technology, Science, Health, Business, Sports, Entertainment, Politics, Education, Environment, World, Finance, Travel, Religion, Food, Gaming, Music, Art, and Fashion.

Admin Panel

A full admin control center with:

  • Real-time platform metrics (total users, active users, new signups this week, total bookmarks)
  • Top interest analytics using a MongoDB $unwind + $group aggregation:

$$ \text{Interest Score}i = \sum{u \in \text{Users}} \mathbb{1}[\text{interest}_i \in u.\text{interests}] $$

  • User management table with live activate/deactivate toggles
  • Recent signups report

🧠 What I Learned

  • How to design a layered Express architecture — routes → middleware → controllers → services → models — that stays clean as the project grows
  • Building a multi-API fallback system for resilient news fetching
  • Creating a complete custom design system in vanilla CSS with full theming, without any UI library
  • Implementing JWT authentication end-to-end: token generation, route protection, role-based guards, and graceful expiry handling
  • Writing MongoDB aggregation pipelines for real analytics
  • Managing complex client-side state across multiple pages without React or any state management library

⚡ Challenges I Faced

News API rate limits were the hardest obstacle. NewsAPI's free tier cuts off quickly under real usage, so I designed a fallback chain across four providers. Getting consistent article shapes out of four different API response formats required a normalization layer in news.service.js.

Session state without a framework was deceptively complex. Keeping the user object consistent across 12+ pages, syncing theme preferences, handling token expiry mid-session, and running the inactivity timer — all without React context or a store — required careful design of the shared api.js layer that every page loads first.

Admin access security needed to be enforced at two levels: the frontend validates an access code before the form even submits, and the backend restrictTo('admin') middleware independently verifies the JWT role claim — so neither layer alone is the single point of failure.

Responsive design from scratch — building a collapsible sidebar, mobile bottom navigation, adaptive article cards, and a working search bar for both desktop and mobile — without Bootstrap or Tailwind — pushed me to deeply understand CSS layout systems.

Built With

Share this project:

Updates