Live: https://ihsan-web-app-main.vercel.app/
Iḥsān is to worship Allah as though you see Him.
A calm, ad-free companion for the Muslim day — salat, zikr, Quran, fasting, prayer times, a first-of-its-kind cycle room for sisters, and a dedicated Ramadan home. Free forever, private by design, and honest with every reference: each Quran verse and hadith links to quran.com or sunnah.com with its exact number and grade.
- Local-first tap counter with focus mode, goals, and custom dhikr — each with Arabic, transliteration and a verified reference
- A curated zikr library in Settings: ṣalawāt (Durud Ibrāhīm & the short ṣalawāt), every istighfār formula, the weighty words, calls on His Names — one tap to add to your own list
- Six core adhkār (SubḥānAllah, Alḥamdulillah, Allāhu Akbar, the tahlīl, Āyatul Kursī, Astaghfirullāh) can never be deleted — the salat wiring depends on them
- A fair streak system: miss one day and you get a grace chance 🧊; backfill up to 2 days to repair a streak (works on mobile and web)
- Analytics: trends, per-type breakdown, weekly heatmap with met/grace/missed tags — rendered with a hand-rolled SVG chart, no heavyweight charting library
- All five fard prayers with on-time / late / missed states, location (mosque / jamaah / home), sunnah and nafl
- Mark the tasbīḥ after a prayer and it posts to your zikr counter itself — no more opening the counter five times a day to log 33s by hand (un-tap subtracts the same amount)
- Salat settings (⚙️): choose your tasbīḥ mode — 33/33/33 + tahlīl (Muslim 597a, default) or 33/33/34 (Muslim 596a) — and your ʿAṣr madhab (standard or Ḥanafī, which shifts ʿAṣr's start and Ẓuhr's end)
- Post-salat surahs one tap away: Āyatul Kursī + the three Quls after every fard, al-Mulk after Isha, al-Kahf on Friday — with a live ʿAṣr→Maghrib duʿā-hour banner on Fridays
- Nafl (Tahajjud, Duha, Ishraq, Awwābīn…) with a minimum of 2 rakʿah, pair-stepped
- Streaks, per-prayer analytics, and a 90-day calendar. During Ramadan a tarawih row appears under Isha
- Calculated fully on-device (adhan, Moonsighting Committee) — GPS or city search, your location never leaves your browser
- Live clock with current/next prayer, forbidden windows and nafl windows on an educational timeline
- Fiqh-aware: qaḍā make-up counter, kaffārah (consecutive-day tracking), vowed fasts, and every sunnah day (Mon/Thu, White Days, ʿArafah, ʿĀshūrā, Six of Shawwāl…)
- Blocks ḥarām days (Eids, Tashrīq) and warns on disliked ones — each rule cites its exact hadith
- Intention auto-completes after iftar; month calendar; full analytics with editable history
- Countdown mode before the month: days-until, expected Gregorian date, and "prepare your heart" links (qaḍā, Shaʿbān, Quran)
- Live mode: Day N hero with a live suhoor→iftar countdown pill, the salat tracker inline (five fard rows + nafl + a tarawih toggle — the same rows and hooks as
/salat, no extra navigation), a three-ashra calendar (Raḥmah / Maghfirah / ʿItq min an-Nār) with pulsing odd nights, and a worship strip to every tracker - Ramadan analytics (
/ramadan/analytics): fasted vs obligated rate (excused days are subtracted from the denominator so they never drag it down), longest run, tarawih nights, per-ashra bars, last-ten focus - Rayhanah-aware: excused days show 🌸 and flow into the qaḍā counter automatically
- Āyah-by-āyah reader: one calm card with the Arabic and its meaning, single-āyah recitation with word highlighting, fullscreen mode with a draggable tafsir split, keyboard navigation, bookmarks, in-app zoom
- Six rooms: Overview · Khatam (serial journey) · Read (any surah, searchable) · Listen (7 reciters, Yasser Al-Dossari default) · Analytics · Saved
- Authentic tafsir (Ibn Kathīr, Maʿārif and more, EN/BN) sourced from quran.com — never AI
- Beloved surahs, authentic protection selections (Āyatul Kursī, last verses of al-Baqarah…), and duʿās from the Quran — each opens straight in the reader
- One unified streak: āyāt from khatam, free reading, special selections and listening all count toward your daily goal
- Connect via a single invite link; see each other's streaks and today's worship
- A calm daily measure called Noor (max 100: prayers 50 · zikr streak 20 · Quran goal 20 · fasting 10) — today's Noor resets at midnight, all-time Noor only ever grows
- The first Muslim productivity app with first-class menstrual & post-natal (nifās) support
- Salat & fasting pause automatically with zero guilt — dhikr, Quran listening & ṣalawāt take over your Noor, and nothing about it is ever visible to friends
- Ghusl guide, cycle predictions, madhab-aware istiḥāḍa guidance, and Ramadan days auto-added to your qaḍā counter
- Private flow / symptom / mood notes, a cycle calendar with predicted windows, and a dedicated analytics page with a regularity score, prediction windows, and past-period backfill
- Hijri dates with a ±1-day moon-sighting adjustment; every quote linked to quran.com / sunnah.com with grading
- Wherever a ḍaʿīf (weak) grade appears, a
<DaifExplainer>card before the footer names the claim, the collection, the specific defect in the chain, the verdict, and how Ihsan uses it anyway — we never ship a weak label without the reasoning - Fajr-to-Fajr worship day (the day flips at dawn, not midnight); celebration animations that respect reduced-motion
- PWA: installable, offline-ready, and self-updating (workbox
skipWaiting+clientsClaim) - i18n (English + Bengali) on the core screens; full backup export / restore and per-feature deletion from Settings
- React 18 + TypeScript · Vite
- Zustand (local state) · TanStack React Query + persist-client (server state, offline cache)
- Tailwind CSS + DaisyUI · Framer Motion
- vite-plugin-pwa (workbox) · react-i18next
- Charts are hand-rolled SVG (Catmull-Rom → Bézier) — no charting dependency
- Node.js + Express + TypeScript (
tsxin dev,tscin prod) - Ships as one Vercel serverless function (
api/index.ts) — the whole Express app, region Singapore (sin1) - MongoDB Atlas (Mongoose, cached connection reused across warm invocations)
- Firebase Auth — Bearer ID tokens, no cookies.
firebase-adminpinned to v12 (v14 breaks the serverless bundle) - Zod validation on every write route · Jest (ESM + ts-jest, mongodb-memory-server)
There is no cron and no separate long-running server. Anything time-decayed (e.g. streaks) is computed lazily on read.
ihsan/
├── api/
│ └── index.ts # Vercel serverless entry — wraps the whole Express app
├── backend/
│ └── src/
│ ├── models/ # Mongoose models
│ ├── routes/ # Express routes
│ ├── controllers/ # Route handlers
│ ├── services/ # Business logic (streak, social, backup, quran, ai…)
│ ├── middleware/ # Auth, validation
│ └── config/ # Mongo + Firebase Admin init
├── frontend/
│ └── src/
│ ├── components/ # Reusable UI
│ ├── pages/ # Route pages
│ ├── hooks/ # React Query hooks
│ ├── store/ # Zustand stores
│ ├── utils/ # Client logic (tracking day, rules, quran data…)
│ └── locales/ # i18n (en, bn)
├── vercel.json # Serverless + SPA routing (region sin1)
└── README.md
- Node.js v18+ (repo targets Node 22 in prod)
- A MongoDB connection string (Atlas M0 is fine)
- A Firebase project (for authentication)
git clone https://github.com/isttiiak/ihsan-web-app.git
cd ihsan-web-appcd backend
npm install
# create backend/.env with:
# MONGODB_URI, FIREBASE_PROJECT_ID, FIREBASE_PRIVATE_KEY, FIREBASE_CLIENT_EMAIL
# (optional AI: GROQ_API_KEY, GEMINI_API_KEY)
# macOS note: port 5000 is taken by AirPlay Receiver — run on 5001
PORT=5001 npm run devcd frontend
npm install
# create frontend/.env.local with:
# VITE_BACKEND_URL=http://localhost:5001
# VITE_FIREBASE_API_KEY, VITE_FIREBASE_AUTH_DOMAIN, VITE_FIREBASE_PROJECT_ID,
# VITE_FIREBASE_STORAGE_BUCKET, VITE_FIREBASE_MESSAGING_SENDER_ID, VITE_FIREBASE_APP_ID
# VITE_GA_MEASUREMENT_ID (optional — GA4, e.g. G-XXXXXXXXXX)
# VITE_WEB3FORMS_ACCESS_KEY (optional — feedback/contact form delivery)
npm run dev- Frontend: http://localhost:5173
- Backend: http://localhost:5001
In production the frontend calls the API same-origin (
/api) — no second host, no CORS.VITE_BACKEND_URLis only for local dev.
Ihsan's tracking day flows the way a worship day does — it flips at local Fajr,
not midnight (utils/trackingDay.ts). Isha prayed at 1 AM and suhoor before
dawn belong to the right day. Salat and fasting use client-authoritative local
civil date strings; the server clock is never the source of "today". Hijri dates
go through getHijriDate() with a user ±1-day moon-sighting adjustment.
| Area | Base | Highlights |
|---|---|---|
| Zikr | /api/zikr |
POST /increment/batch (signed deltas), GET /summary, GET|POST|DELETE /types, PATCH /types/rename, DELETE /all |
| Analytics | /api/analytics |
GET / (charts + derived streak), GET|POST /goal, POST /streak/pause|resume |
| Salat | /api/salat |
GET /?date=, PATCH /prayer, PATCH /nafl, GET /analytics?today=, DELETE /all |
| Fasting | /api/fasting |
PUT /log, GET /summary?today=, GET /history, PATCH /profile, vows CRUD, DELETE /category/:c, DELETE /all |
| Quran | /api/quran |
POST /read-ayat, POST /bookmark, GET /summary?today=, GET /tafsir, PUT /resume, PATCH /profile, DELETE /all |
| Cycle | /api/cycle |
GET /summary, POST /start|end, PUT /day, PATCH /logs/:id, PATCH /profile, DELETE /all |
| Social | /api/social |
GET /summary (leaderboard), GET /noor, GET /friends, POST /connect, DELETE /friends/:uid |
| User | /api/user |
GET /export (full backup .json), POST /import (merge restore) |
| AI | /api/ai |
POST /suggest|reflect|weekly-summary|simplify — encouragement only, never a source of evidence |
cd backend && npm test # jest ESM + ts-jest, mongodb-memory-server (54 tests)The whole app deploys as one Vercel project:
- Root Directory points at the repo root;
vercel.jsonbuildsfrontend/distand servesapi/index.tsas a serverless function (regionsin1). - Set the backend env vars (Mongo, Firebase Admin) and the
VITE_*frontend env vars in the Vercel dashboard. - Root
package.jsonmust keep"type": "module"— without it the serverless bundle fails withERR_REQUIRE_ESM. - Keep
firebase-adminat v12 — v14 pulls an ESM-onlyjosethat breaksverifyIdToken()in the bundled runtime.
Contributions are welcome — fork, branch (feature/…), and open a PR.
For translations, add values to frontend/src/locales/<lang>/common.json
(keep Arabic and references out of translation files). Any Quran/hadith
addition must link to quran.com or sunnah.com with the exact number and grade —
if it can't be verified, it doesn't ship.
MIT.
Istiak Islam — GitHub @isttiiak
If you spot a mis-cited or mis-graded reference anywhere in the app, there's a "Report it" link beside every reference — corrections are always welcome.
Built with ❤️ for the Muslim ummah.