All case studies

Consumer web app

How we built Mincha Time

Mincha (the afternoon prayer) has a window that shifts every day with sunset, and it is different in every city. Without checking a calendar daily, people miss the window without realizing it.

Built in about 1 monthView live project
Screenshot of Mincha Time

Stack

ViteReactBase44Firebase Cloud FunctionsFirestoreFirebase Cloud MessagingHebcal zmanim API

Why this was the right shape

Mincha Time was intentionally smaller than a typical religious calendar app. The first version did not try to become a full siddur, calendar, community platform, or settings-heavy utility. It focused on one daily outcome: help a person know when mincha is relevant in their current location and remind them before they miss it.

The landing page is the visible half. The other half is a scheduled notification engine that has to fire the right message, in the right language, at the right minute, every day, for every location — without a dedicated task queue.

Key build decisions

Firestore documents as the schedule, not a queue

A Cloud Function runs every minute and checks whether a document exists at the path for the current time, grouped by location and notification type. No external queue or scheduler service — the current minute is just a document lookup.

Group by location, not by user

Users near the same coordinates share a notification group, so the zmanim calculation and the Hebcal API call happen once per location per day, not once per user. Personal, self-set reminder times run through a separate, simpler path.

Each run schedules the next day

After sending today's notifications for a location and type, the same function call fetches tomorrow's zmanim from Hebcal and writes forward to tomorrow's time-bucket document. The system advances itself one day at a time instead of precomputing a calendar in advance.

Six languages as plain lookup objects

Hebrew, English, Russian, Spanish, French, and Yiddish notification copy live in a simple translations map, keyed by a per-user language field — no i18n library, just small pure functions per language.

What shipped

  • A public landing page with multilingual messaging.
  • A phone-style notification preview showing the two important reminder moments.
  • A minute-resolution scheduled notification engine (Firebase Cloud Functions + Firestore + FCM) covering both location-based group reminders and personal reminder times.
  • A monthly cleanup job that removes tokens and records for users inactive more than 30 days.
  • FAQ content around calculation method, offline behavior after setup, and halachic method support.

What got tricky

  • Timezone handling for the next day's time-bucket comes from parsing the UTC offset out of the Hebcal API's response string — it works, but it is the kind of manual parsing that would need to become more robust if Hebcal ever changed its response format.
  • The scheduler runs every minute regardless of whether anything is due, which is simple and cheap at this scale but is the first thing that would need to change if the user base grew by an order of magnitude.
  • Two separate opt-out flags — a permanent disable and a same-day snooze — both have to be checked before every send, and both needed to be easy for a non-technical user to set from the app.

What we would improve next time

  • Move the offset parsing to a proper timezone library instead of slicing the API response string, now that the pattern has proven itself in production.
  • Batch the per-minute check across locations more efficiently as the number of distinct location groups grows.
  • Add a small public demo that lets a visitor choose a city and preview today's mincha window before installing.
Technical deep-diveHow the notification scheduler actually worksNo task queue, no per-user cron — just time-bucketed Firestore documents and a function that reschedules itself one day at a time.

Want a teardown like this for your own workflow?

Send the current process, the tools involved, and what keeps breaking. We can usually find the smallest useful build before anyone writes code.

Talk through a project