Case study №01

One monorepo, 13 apps

Building a consumer-app factory with SvelteKit, Capacitor and tRPC

Role
Platform engineer
Timeline
Feb 2025 — Present
Scale
3.3M+ users

Context

IndiDino builds consumer apps for the Indian market — dating, AI companions, astrology, learning. The ambition was a portfolio of products, not one: find what resonates, double down, keep shipping. The engineering team is small, so the usual answer — one codebase, one team, one app — was never going to get there.

The problem

Shipping N apps normally costs N× everything: N codebases, N auth flows, N payment integrations, N release processes, N sets of store builds. The goal was to make app number thirteen cost roughly a config file plus its own screens — and nothing else.

The architecture

A pnpm monorepo. Each app is a thin SvelteKit + Capacitor shell over shared packages: a UI kit, authentication (OTP, Google, Apple, Truecaller), payments (Razorpay, Google Pay, Apple Pay, UPI, wallets), notifications (FCM delivery, deep-link routing, 60+ templates) and analytics. A type-safe tRPC API on Node talks to PostgreSQL through Kysely, with pg-boss for background jobs and ClickHouse for behavioral events.

13 SVELTEKIT + CAPACITOR APP SHELLSHIDNNDOSTIIRIVER AICOSMIQ+ 9 MORESHARED PACKAGESUI KITAUTHPAYMENTSNOTIFICATIONSANALYTICSTRPC API — NODE (HONO)SHARED INFRASTRUCTUREPOSTGRESQLPG-BOSSCLICKHOUSEFCMONE RELEASE PIPELINE · APP №14 = CONFIG + ITS OWN SCREENS
Fig 1 — every box below the app row is written once, shipped 13 times

Cross-cutting systems live below the app layer, so they work for every app automatically — the fraud pipeline (device fingerprinting that blocks banned users from re-registering on any of the 13 apps) and the AI moderation pipeline (a multi-provider vision-LLM architecture, benchmarked across 6 models, running at ~$0.30 per 1,000 images) were each built once.

Key decisions

Chose a monorepo over a repo per app

One dependency graph and atomic cross-app changes: a fix to the payments package lands in every app in the same commit. The cost is CI time and ownership discipline — a platform change can break thirteen apps at once, which is what pushed us to centralized release management.

Chose Capacitor over React Native or native teams

The web team ships the native apps. The cost surfaced on iOS — plugins for biometrics, permissions, payments and media processing didn't exist the way we needed them, so I ended up owning native plugin development to keep iOS at parity with Android.

Chose tRPC end-to-end types over REST + hand-written clients

Schema drift between frontend and backend simply stopped being a failure mode; refactors became mechanical. The coupling it creates between FE and BE releases is real — and is exactly the coupling a monorepo makes cheap.

Chose shared packages over copy-paste per app

A paywall improvement or a notification-template fix ships to every app at once. In exchange, nothing platform-level can be merged casually: every change is a change to thirteen products.

Outcomes

13
apps in production
3.3M+
users served
350+
banned users blocked platform-wide

The platform is the product: paywalls, A/B-tested onboarding funnels, authentication and push campaigns are built once and tuned per app with data from ClickHouse.