CountdownBoxes logo
CDB
project story

CountdownBoxes: Countdown to Everything.

We built a countdown app that tracks everything from product launches to birthdays. 33 API integrations, cron-based notifications, shared boards, and a full PWA. Here is how it went.

~1800 words; about a 5 minute read

part one.

Why we built this.

Every countdown app we tried was either too simple or too cluttered. You could count down to one thing, maybe two. Want to share a board of countdowns with your team? Good luck. Want push notifications without installing a native app? Forget it.

We wanted something where you could track dozens of events, organize them into shared boards, and get notified right on your phone. No app store required. So we built it.


part two.

What CountdownBoxes is.

CountdownBoxes is a countdown tracking app. You create timers for anything: product launches, birthdays, vacations, deadlines, game releases, whatever matters to you. You organize them into boards. You share those boards with friends or teammates. The countdowns tick in real time, and the app sends you push notifications when events are coming up.

It works as a full PWA. You can install it on your home screen, use it offline, and get notifications like a native app. On desktop too.

We also built a discovery layer. The app comes preloaded with countdowns for holidays, movie releases, sports events, and more, pulled from external APIs. You browse, tap, and add them to your boards.


part three.

The 33 API problem.

The discovery feature pulls data from 33 different third-party APIs. Holidays, sports schedules, movie databases, game release dates, you name it. Every single one of them returns data in a different format with different rate limits and different failure modes.

Normalization layer

We built a normalization layer that sits between the raw API responses and our database. Each source has its own adapter that maps the external format to our internal countdown schema. On top of that, we added per-source caching with different TTLs (sports schedules change more often than holiday dates) and fallback logic so a single API outage does not break the whole discovery page.

Edge cases everywhere

Getting 33 integrations to behave consistently was probably the most tedious part of the project. Not hard conceptually, just a lot of edge cases. Date formats alone could fill a blog post. Some APIs return ISO 8601, some return Unix timestamps, some return strings like "March 15th". Each adapter handles its own parsing and validation before anything touches the database.


part four.

Cron jobs and PWA realities.

Notifications at scale

Push notifications in a PWA are powered by service workers and the Push API. But the tricky part is not sending the notification. It is knowing when to send it. We built a cron-based system that runs on a schedule, queries the database for countdowns that are about to expire, and batches the notifications. Clock drift between your cron runner and your database. Duplicate notifications when a job runs twice. Time zone math that makes your head spin.

Idempotency first

We ended up with a robust batching system that deduplicates by countdown ID and user, respects per-user notification preferences, and handles retries gracefully. The key insight: build idempotency in from day one. A scheduled job that runs "every 5 minutes" sounds simple until you deal with overlapping runs.

PWA: the last 10%

Building a PWA that feels native is still harder than it should be. The install prompt works differently on every browser. Service worker caching strategies are a minefield of stale data if you get them wrong. And iOS support for PWA push notifications is technically there now, but the experience is inconsistent.

We went with a cache-first strategy for static assets and network-first for API data, with an offline fallback page. The result is an app that loads instantly on repeat visits and degrades gracefully when you lose connection.


part five.

The stack.

Frontend

Next.js + React + Tailwind CSS

Backend

Next.js API Routes + Prisma ORM

Database

PostgreSQL

Notifications

Cron + Push API

PWA

Service Workers + Offline

Deploy

Netlify

We chose PostgreSQL because the data model is inherently relational. Users have boards. Boards have countdowns. Users share boards with other users. Permissions control who can view or edit. This maps perfectly to relational tables with foreign keys.

Prisma made it painless. The type-safe query builder caught schema mismatches at compile time instead of at 2 AM in production. Migrations were smooth. The developer experience was genuinely good.


part six.

What we learned.

PWAs are ready, mostly.

The gap between a PWA and a native app is smaller than ever, but the last 10% (reliable push on iOS, smooth install flows, background sync) still requires workarounds and patience.

Normalize early, normalize often.

When you are integrating multiple external data sources, the normalization layer is the most important code you will write. Invest in it upfront. Every shortcut you take there will cost you later.

Cron jobs need more care than you think.

A scheduled job that runs "every 5 minutes" sounds simple until you deal with overlapping runs, retries, and time zones. Build idempotency in from day one.

Prisma + PostgreSQL is a solid combo.

If your data has clear relationships and you want type safety, this stack delivers. We did not fight the ORM once.


We are actively building new features. More event sources, better board collaboration, and calendar sync are all on the roadmap. The app is live right now and free to use.

Try CountdownBoxes

go home