DEV Community

Cover image for How I built a production mobile app boilerplate in two weeks without writing a line of frontend code
DGIT
DGIT

Posted on

How I built a production mobile app boilerplate in two weeks without writing a line of frontend code

How I built a production mobile app boilerplate in two weeks without writing a line of frontend code

Eight months ago my wife and I had twins.

The baby tracker apps on the App Store weren't designed for multiples. Most were paid. The free ones were missing things. None of them thought about two babies at the same time — one timer, one log, one feeding. So I built my own. TwinLog is a free tracker for twins and multiples ([https://play.google.com/store/apps/details?id=com.dgit.babytracker]) . My wife uses it every day. It just launched on the Play Store with almost no users and I'm genuinely fine with that — it was built because we needed it, not because I wanted users.

After shipping it I noticed something obvious in hindsight: every app starts with the same work. Authentication, payments, cloud infrastructure, CI/CD pipelines. Two weeks of scaffolding before you write a single line of what your app actually does. TwinLog has none of that — no auth because I didn't have time, no payments because it's free, no web frontend. I skipped everything non-essential to ship fast.

But a commercial app can't skip those things. And I wasn't going to rebuild them from scratch every time.

So I built MiniStack — a full-stack mobile boilerplate — instead.

The stack

Expo for mobile (React Native), Next.js 15 for the web frontend, ASP.NET Core with EF Core for the backend, PostgreSQL for the database. Terraform modules for both GCP and Azure. GitHub Actions for CI/CD. Google and Apple Sign-In, email/password auth, Stripe subscriptions with a free tier, email verification, push notification wiring.

I'm a .NET developer. Ten years. I don't particularly enjoy frontend — I can do it but it takes me longer and I enjoy it less. Picking ASP.NET Core as the backend wasn't a considered tradeoff, it was just the obvious choice. I know it, it's fast, and I had no reason to relearn deployment tooling and testing patterns in Node just because the frontend uses TypeScript.

Most React Native starters assume a JavaScript backend. This one doesn't. If you're a Node developer this probably isn't for you. If you're a .NET developer who wants to ship a mobile app without switching ecosystems, keep reading.

How it was actually built

The whole codebase was written by Claude AI. I directed, it implemented.

I should be specific about what that means, because "written by AI" covers a lot of ground. I didn't paste prompts into a chat and copy code into files. I used Claude Desktop's Cowork tab for the earlier project (TwinLog) — that gives Claude direct access to your repo and it edits files itself, but you still copy-paste and run terminal commands manually. I switched to Claude Code in VS Code quickly. The difference is that Claude Code runs the commands too. You see file diffs appear in your editor in real time. When something breaks you can see exactly what changed and why, which makes course-correcting much faster on a project with dozens of interconnected files.

What I actually did: described what I wanted, reviewed what came back, made the architectural calls, and corrected direction when something was wrong. I didn't write the implementation. It's the first time I've worked this way on a real project — not a tutorial, not a toy — and it held up.

It took about two weeks. A couple of hours a day, not every day.

Auth: custom JWT without Auth0

TwinLog has no authentication. MiniStack has full authentication. The decision to build it ourselves rather than use Auth0, Clerk, or Supabase Auth was mostly about familiarity. I understand .NET JWT auth. I didn't want another external service managing my users or another pricing tier to reason about when my next app scales.

This is personal preference, not a universal recommendation. Auth0 and Clerk are good products. For teams without strong backend auth experience they're probably the right call.

The implementation uses a split-token pattern. Access tokens live in memory only, 60-minute lifetime. Refresh tokens are in the database, one row per device, rotated every time they're used. On the web the refresh token sits in an httpOnly cookie managed by a Next.js API route — JavaScript in the browser never touches it. On mobile it goes into expo-secure-store, which maps to iOS Keychain or Android Keystore.

Each device has its own session. Logging out on your phone doesn't end your session on your laptop.

Google and Apple Sign-In took a while to get right. The mental model that helped: the backend doesn't do a redirect flow. Expo's libraries handle the OAuth dance on-device and return a signed token — id_token from Google, identityToken from Apple. The backend validates that token against the provider's public keys and issues its own JWT. That's the whole thing. Once I understood that the server was just validating a JWT — something it already knew how to do — it stopped feeling mysterious.

Getting it working across all platforms was four separate bug fixes. I'll cover them in detail in the Google Sign-In article.

Infrastructure: Terraform because I don't like clicking in portals

My Azure subscription had one month of free credits. GCP offers three. I moved to GCP.

I didn't want to learn where to click in the GCP console. The portal changes constantly and every tutorial has screenshots of a UI that no longer exists. I wanted something I could run again from scratch without rediscovering each step.

The goal was simple: terraform init && terraform apply. Phase 1 is three terminal commands — authenticate, set a project ID, enable billing. After that Terraform provisions everything: Cloud Run service, Artifact Registry, service accounts, IAM roles, Workload Identity Federation so GitHub Actions can deploy without any stored credentials. The deploy workflow pushes a Docker image and Cloud Run updates. No secrets sitting in GitHub settings beyond the ones you actually need.

Getting there took more iterations than I expected. Workload Identity Federation has ordering dependencies that aren't obvious — the identity pool has to exist before you can grant roles against it, but the service account needs those roles before Cloud Run can pull from Artifact Registry. The Terraform for Azure had its own issues around federated credentials and Container App identity. The infra modules went through several revisions.

But once it's done it just works. A buyer runs Terraform once, puts a handful of values into GitHub Secrets, and pushes. Every merge to master builds, tests, and deploys.

Stripe

The demo entity in MiniStack is a habit tracker. Free tier: 3 habits. Pro: unlimited. That's not because anyone buying a boilerplate wants to build a habit tracker — it's because it's a clean way to show subscription gating. The pattern is straightforward to swap out for whatever your actual paid feature is.

The implementation is a Stripe Checkout Session for subscribing, a Customer Portal session for managing or cancelling, and a webhook handler that updates the user's subscription status in the database. The backend returns 403 upgrade_required when a free-tier user hits a gated endpoint. The client handles that and redirects to the subscription screen.

Honest take on building with Claude

It worked for this kind of project. The backend code was fast and I could review it confidently because I know the domain. Terraform was solid. The frontend worked but I was a less useful reviewer there — issues showed up at runtime rather than in code review, because I'm not strong enough on React to spot them from reading.

What it doesn't replace is understanding. There were decisions throughout that I had to make — what to use, why, how the pieces fit together. Claude implemented those decisions. When something was wrong I had to notice and describe what was wrong. That requires knowing enough to have an opinion.

If you're hoping to build something you don't understand by delegating to an AI, this workflow won't save you. If you know the domain well enough to review what comes back and catch what's off, the speed gain is real.

MiniStack is a commercial template — US$197, one purchase, unlimited projects. You clone it, run node scripts/setup.js, answer three questions, and it renames everything across the monorepo. Then you wire up your credentials and push.

https://gormez.gumroad.com/l/ministack

Also in this series: the auth architecture in detail — Google Sign-In: four bugs, four fixes — Terraform without the portal — Stripe subscription gating in ASP.NET Core (To be published soon)

Top comments (0)