Back to all deployments

Spiritual-Tech

JapaApp

Offline-first PWA for Vedic mantra practice — live in production with donation-based monetization.

Customer

Practitioners of japa meditation — devotional mantra counting

Timeline

2024–Present

Status

Live in production

Capability

Full-StackPWAConsumer

Stack

React 18TypeScriptFirebaseFramer MotionRazorpayPWA

Outcome

Live
In production
Practitioners can use it now
Offline
Core functionality
Full offline-first PWA
3
Donation tiers
Culturally-named pricing
0
Server-side latency
Firebase local-first reads

Customer Context

Who they are and what world they live in

Japa is the daily practice of repeating a sacred mantra — a count of 108, 1008, or more repetitions per sitting. Practitioners use physical mala beads to count. The gap: no digital tool built for the actual practice. Existing apps were built for meditation broadly, not for mantra counting specifically. The user base spans age groups — from teenagers to elderly practitioners — with varying technical comfort. Many practice in quiet spaces without internet. The monetization has to fit the cultural context: donation, not subscription.

The Problem

The fuzzy ask, translated

The ask was 'build a mantra counter app.' The real design challenge was: how do you build a streak and progress system that respects practice integrity? Practitioners don't want to game streaks — they want to track genuine sadhana. The monetization had to feel like an offering, not a paywall. And the app had to work offline, completely, because meditation and WiFi don't always coexist.

The Constraints

Time · Budget · Regulatory · Technical · Organizational

01

Offline-first: practitioners meditate in spaces without reliable internet — the core counting and tracking must work without connectivity

02

Donation-based monetization: culturally, asking practitioners to subscribe feels transactional in a way that doesn't fit the practice — donation tiers with spiritual naming

03

Streak mechanics that respect practice integrity: no gamification pressure that conflicts with the nature of the practice

04

Firebase Custom Claims for global admin: one admin tier across all users without exposing admin functionality in the client

05

Cross-age-group UX: elderly practitioners need large tap targets and minimal cognitive load

Architecture Decisions

What I chose. What I rejected. Why.

Platform

Chosen

Firebase (Auth + Firestore + Custom Claims)

Rejected

Original AWS architecture (Lambda + RDS Proxy + Cognito JWT + SAM)

Why

Owned the migration decision after realizing the AWS architecture was over-engineered for the use case. Firebase's real-time sync, offline persistence, and built-in auth eliminated three separate services and reduced cold-start latency that mattered for a counting interface.

Offline persistence

Chosen

Firestore offline persistence with service worker for asset caching

Rejected

IndexedDB + custom sync

Why

Firestore's offline mode handles conflict resolution automatically. Custom IndexedDB sync would have required implementing CRDT-style merge logic for count updates — significant complexity for a solo build.

Monetization model

Chosen

Razorpay donation flow with spiritually-themed tiers (Seva, Daan, Arpan)

Rejected

Subscription / paywall

Why

The user base responds to offering language, not subscription language. Donation tiers with Sanskrit naming ('Seva' = service, 'Daan' = gift, 'Arpan' = offering) have higher conversion in this cultural context than 'Basic / Pro / Enterprise'.

The Hard Problem

The one thing that almost broke the deployment

PWA offline-first with Firestore is harder than React Native offline-first. The service worker has to cache the right assets at install time, update them correctly on new versions, and not break Firestore's own network detection. Early builds had a failure mode where Firestore's offline mode and the service worker's cache disagreed on whether the app was online — users saw stale data after reconnecting.

The Fix

Separated the service worker concerns: asset caching (Workbox, network-first strategy for dynamic routes, cache-first for static assets) from Firestore connectivity (managed entirely by the Firestore SDK, not the service worker). The service worker explicitly yields network detection to Firestore and only manages the asset layer. Took two architectural rewrites to get the separation clean.

Production Reality

What I had to fix in week 2

Firebase Custom Claims are set server-side and only take effect after the user's ID token refreshes. Early admin testing showed a 1-hour delay between granting admin access and it appearing in the app. Added a forced token refresh on admin grant, surfaced in a simple admin management UI. Not documented anywhere obvious in the Firebase docs.

Lessons Carried Forward

What this taught me that I apply to every deployment

01

PWA service worker architecture is harder than React Native for true offline-first — the separation of asset caching from data sync has to be explicit

02

Firebase Custom Claims token refresh is not automatic — force a refresh on grant or users wait an hour for their new access level

03

Monetization language matters in culturally-sensitive markets — donation tier naming with Sanskrit terms outperformed generic subscription language in early user feedback

04

Own platform migration decisions: the move from AWS to Firebase was the right call, and making it early saved months of over-engineering

Related Deployments