Skip to content
All projects
Challengers app icon

Challengers

Push your limits. Bet on yourself.

LiveBuilt solo
Live demoGitHub
challengers-theta.vercel.app

What it is

A social habit tracker built on friendly competition. Join or create challenges, log every day with photo proof, climb consistency-based leaderboards, and chat with the group in real time. A Next.js 16 PWA with web push and AI-assisted check-in verification.

System design

Firestore is the single source of truth for app data, while Supabase Postgres exists only to host the pg_cron jobs that POST back to the Next.js API on a schedule, and Supabase Storage holds the photo proofs. Redis backs per-user rate limiting across every endpoint, returning 429 with Retry-After when limits are crossed. FCM tokens live as a capped array, max five with the oldest pruned, so notifications reach a user's latest devices without stale tokens piling up. Cron idempotency is enforced by checking the day against a points_history array rather than a separate runs table, keeping the data model simple and transaction-free.

What I got wrong, then fixed.

  1. 01 · the problem

    The dashboard fired a separate participant-count query per challenge, an N+1 that scaled Firestore reads with the number of challenges on screen.

    what I did

    Batched the counts into Firestore 'in' queries so reads stay constant regardless of challenge count, and cached the dashboard for five minutes with RTK Query. O(N) reads became O(1), revisits became instant.

  2. 02 · the problem

    Missed-day penalties read the current points, then subtracted. Two cron runs firing at once could deduct the same day twice.

    what I did

    Switched the deduction to an atomic increment and computed live points from the document, with an idempotency check against the day's points_history as a backstop. Concurrency-safe by construction.

  3. 03 · the problem

    The app is serverless, but reminders need to fire every minute, and Vercel only runs sub-minute crons on paid plans.

    what I did

    Drove the schedule from Supabase pg_cron, which uses pg_net to POST the Next.js endpoints with a CRON_SECRET header. Reliable per-minute crons, zero extra infrastructure.

See Challengers liveBack to all projects