17:00:09CCU, IN
Back to projects

From Chaos to Clarity: Building a Contest Aggregator

How an itch to build something led me to build a solution for a problem I kept hearing about.


The Spark

It started with an assignment and a conversation.

I needed to build something, and I was sick of building yet another todo app or basic CRUD system. Around the same time, I was talking to friends who were getting into competitive programming, and they kept complaining about the same thing: missing contests.

The problem was everywhere. LeetCode, CodeChef, Codeforces, each platform had its own schedule, its own notification system (or lack thereof). People would check two platforms, forget the third, and miss a contest they actually wanted to participate in. It was a small annoyance that added up over time.

I saw an opportunity. Why not build a single dashboard that shows everything? One place where you can see upcoming contests across all three platforms, filter by what matters to you, and bookmark the ones you care about.

It wasn't groundbreaking, but it felt cool and useful


The Vision

One Dashboard. All Contests.

I wanted to build a hub where competitive programmers could:

  1. Track all upcoming contests across LeetCode, CodeChef, and Codeforces
  2. Filter by platform or view everything at once
  3. Review past contests
  4. Bookmark contests without needing to sign up

The Stack

React + ViteExpress.jsMongoDBNode-cronTailwindCSS + ShadCN


Engineering Highlights

1. The Automation Engine (Cron Jobs)

The core problem: keeping data fresh across three different APIs without babysitting the server.

I needed the system to pull contest data automatically, update statuses when contests ended, and handle failures gracefully. Manual updates weren't an option, this thing had to run itself.

The Solution: I built an automated pipeline using Node-cron.

  • Cron jobs run every 6 hours to fetch contest data from LeetCode, CodeChef, and Codeforces APIs
  • The system checks for contests that have recently ended and updates their status
  • Handles API rate limits and failures gracefully with retry logic
  • Getting APIs unofficially was a task in iteslf as well
  • Result: Always up-to-date contest information without any manual work

2. Client-Side Persistence (LocalStorage Bookmarks)

I wanted zero friction. No signup walls, no forced registrations, just use the tool.

The Fix: I used localStorage for a lightweight bookmarking system.

  • Users can bookmark any contest with a single click
  • Bookmarks persist across sessions without requiring a backend
  • Filter and view bookmarked contests separately
  • Result: Simple, fast, and zero barriers to entry

3. Smart Filtering System

With hundreds of contests across three platforms, I needed a way to cut through the noise.

The Approach:

  • Multi-platform filtering, select one, two, or all three platforms simultaneously
  • Toggle between upcoming and past contests
  • Clean, responsive UI built with TailwindCSS and ShadCN components
  • Result: Users can find exactly what they're looking for in seconds

What I Learned

1. Automation > Manual Work, Always.

I could have built a system where I manually updated contest data or required user accounts to track bookmarks. But every bit of friction you remove makes the tool more useful. Cron jobs meant the data stayed fresh on its own. LocalStorage meant no signup required. Less work for me, less hassle for users.

2. Working with Multiple APIs is Messy.

Each platform has its own quirks. Different response formats, different rate limits, occasional downtime. I spent a lot of time building retry logic and error handling to make sure one API failing didn't break the entire system. It taught me a lot about building resilient backends that can handle the real world's unpredictability.

3. Small Problems Are Still Worth Solving.

This wasn't some revolutionary app. It was just a cleaner way to track contests. But solving small, real problems taught me more than building flashy features no one needs. Even though I never shared it widely, building something genuinely useful, even at a small scale—felt way more rewarding than just checking off an assignment.


Current Limitations & Future Optimizations

The platform works, but there's room for improvement:

Database-Level Pagination - Currently, all contests are fetched at once. Implementing cursor-based pagination would improve performance as the dataset grows.

Client-Side Caching - Adding React-Query or Zustand would reduce unnecessary API calls and improve load times.


What's Next

Email/Calendar Integration - Let users subscribe to contests and get reminders. Sync directly with Google Calendar or Outlook.

Push Notifications - Real-time browser notifications for contests starting soon.

User Analytics Dashboard - Track participation history, performance trends, and contest streaks.