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
Stack
Outcome
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
Offline-first: practitioners meditate in spaces without reliable internet — the core counting and tracking must work without connectivity
Donation-based monetization: culturally, asking practitioners to subscribe feels transactional in a way that doesn't fit the practice — donation tiers with spiritual naming
Streak mechanics that respect practice integrity: no gamification pressure that conflicts with the nature of the practice
Firebase Custom Claims for global admin: one admin tier across all users without exposing admin functionality in the client
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
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
Firebase Custom Claims token refresh is not automatic — force a refresh on grant or users wait an hour for their new access level
Monetization language matters in culturally-sensitive markets — donation tier naming with Sanskrit terms outperformed generic subscription language in early user feedback
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