Skip to content
back to projects

case study · 2025

Ihsan

Full-stack Islamic productivity app — zikr, salat, fasting, and Quran habit tracking with streaks, goals, and timezone-aware analytics.

role

Solo developer

ReactTypeScriptNode.jsExpressMongoDBFirebase AuthZustandTanStack QueryTailwind CSS

architecture

Frontend

React + Vite + Tailwind CSS

Client & server state

Zustand + TanStack Query

Backend

Node.js + Express REST API

Database

MongoDB Atlas (Mongoose)

Authentication

Firebase Auth — Bearer ID tokens, stateless

Hosting

Vercel (frontend) + Render (API)

The problem

Habit trackers exist everywhere, but nothing served Muslim daily worship well: counting zikr, logging the five daily prayers, tracking voluntary fasts against actual Islamic calendar rules, and building a Quran reading habit — in one place, with real analytics.

Key features

  • Zikr counter — local-first tap counting with debounced batch sync, lifetime totals, daily goals
  • Salat tracker — five daily prayers with status, location, and per-day history
  • Prayer times — computed fully client-side from device location, no API dependency
  • Fasting tracker encoding real fiqh: prohibited days (both Eids, Tashriq) blocked in the UI, disliked patterns warned, every rule linked to its source hadith with exact reference numbers
  • Quran habit — daily pages goal, khatm (completion) progress bar, reading streaks
  • Streaks with grace days — one missed day survives if the next is completed; backfill reconnects broken streaks
  • Per-habit analytics dashboards with configurable date ranges
  • 19-test backend suite (Jest + mongodb-memory-server)

Challenges

Timezones done right. A "day" for a user in Dhaka is not a UTC day. Daily buckets are anchored so the bucket's UTC date always equals the user's local date, and for prayer/fasting logs the client's local civil date is authoritative — the server clock never decides what "today" means. Daily resets happen at local midnight with zero configuration.

Write-heavy counters without lost updates. Zikr counting is a hot path — taps are counted locally first, then flushed in debounced batches. Server-side writes are atomic MongoDB operations ($inc, $addToSet), never read-modify-save, so concurrent batches can't lose counts.

No cron on free tiers. Streaks that should expire are evaluated lazily on read — the same result as a scheduled job, with zero infrastructure and nothing to monitor.

Domain correctness. Encoding fasting rules meant researching primary sources and linking each rule to its hadith reference — the app is only useful if the fiqh is right.

What I learned

  • Client-authoritative time is the only sane model for habit apps with global users
  • Atomic write patterns ($inc over read-modify-save) as the default for any counter under concurrency
  • Free-tier architecture is a real constraint discipline: lazy evaluation replaces cron, cold starts shape UX decisions