Astro Tales
Astrology lifestyle app backend โ Express.js, Supabase, payments, push notifications.
The Challenge
The Astro Tales mobile app had a working React Native frontend and a user base growing at 15โ20% month-over-month, but was running on a monolithic Node.js backend that had been written incrementally without a defined architecture. As the feature set expanded โ premium subscriptions, daily horoscope push notifications, SMS-based OTP auth, personalised birth-chart computations โ the codebase became impossible to maintain: adding a new notification provider required touching 6 different files, and a bug in the payment webhook handler had once silently failed 200 subscription renewals before being detected.
The notification volume was the critical scalability challenge: sending personalised daily content to 50,000+ users within a 6 AMโ7 AM delivery window (when users expect to receive their morning horoscope before leaving for work) required a reliable job queue that the existing architecture could not provide. Direct API calls from the web server had a 3โ8% failure rate during peak volume.
What We Built
We rebuilt the backend from scratch using a strict Controller โ Service โ Provider (CSP) architecture. Controllers handle HTTP request/response and input validation (using Zod schemas). Services contain business logic with no I/O dependencies โ pure functions that can be unit-tested without a database. Providers are thin adapters over external services (Supabase, Razorpay, Twilio, Firebase, Expo Push) โ swappable behind interfaces, which immediately solved the "adding a provider touches everything" problem.
Astrological computations (planetary positions, house calculations, dasha periods) are CPU-intensive and deterministic given a birth datetime and location. We extracted these into a separate computation service using the Swiss Ephemeris JavaScript port, with results cached in Redis keyed on birth parameters โ so repeat requests for the same birth details (common for returning users checking multiple chart types) are served from cache in <10ms rather than recomputed.
Push notifications for daily horoscopes run as a Bull queue job (backed by Redis), scheduled via node-cron to enqueue the day's notifications at 5:45 AM. The queue processes 500 notifications per second in parallel worker threads, with automatic retry (3 attempts with exponential backoff) for failed sends. Expo Push handles iOS/Android routing; a separate Twilio SMS leg sends to users without push-enabled devices.
The Outcome
The rebuilt backend handled the 50,000 daily notification volume within the 6 AM window with a 99.9% delivery success rate โ up from the previous 96โ97% โ and reduced the delivery window from 45 minutes to under 12 minutes for the full user base. Zero subscription renewal failures have been recorded since the Razorpay webhook handler was rebuilt with idempotency keys.
Backend response times (P95) improved from 820ms on the old monolith to 94ms on the new CSP architecture for standard API calls, primarily because of the Redis caching layer on computation results. The architecture also proved its extensibility: when the team added a new "Compatibility Report" feature three months post-launch, it required writing exactly one new Service file and one new Provider โ no modifications to existing code.