DEV Community

Cover image for How I built a work-friendly cafe finder PWA for my city (MERN, zero budget, solo dev)
Sanket Golekar
Sanket Golekar

Posted on

How I built a work-friendly cafe finder PWA for my city (MERN, zero budget, solo dev)

For the past few months, I've been working from different cafes across Chandigarh every weekday and I'm surprised to see that a lot of people in the city prefer working from cafes.

But there's one problem I noticed, majority of people work from only 2 popular cafes in the city because they don't know about other work friendly cafes, which results in these cafes being crowded most of the times. Many cafes which students and people working remotely
visit have no proper WiFi or worse, they don't welcome you working from their cafes.

So I spent the last 3 months fixing this.

I started building an app which shows all the work friendly cafes in Chandigarh with personally tested WiFi speeds, number of power outlets for charging, sat there working long enough to honestly judge the noise levels. Everything is verified personally by me and updated regularly.

The result is BaseBrew, a free work friendly cafe discovery platform PWA built specifically for Chandigarh
tricity. Here's what I built, how I built it, and
the gotchas I ran into along the way.

Just open BaseBrew on your phone.

Search filters you can use to find the cafe of
your choice:

→ WiFi Speed (actual Mbps, personally tested by me)
→ Power Outlets availability + outlet count
→ Noise levels (quiet / moderate / lively)
→ Opening and closing hours
→ Sector filters (Sector 8, 35, 22, 7, Elante etc)
→ Price range (budget / mid / premium)
→ Near Me filter (shows cafes closest to
your location)
→ I'm Working Here — check in when you're at
a cafe, shows how many people are working
there right now

24 verified cafes in Chandigarh are live right
now. Adding more every week if the cafes match
our work friendly criteria.

The app is 100% free, no ads, no paywall.

Now let me get into how I actually built this:
the stack decisions, the architecture, and the bugs that cost me the most time.

Why MERN?
I'm a solo developer, having one language across the entire stack is a huge productivity advantage. MongoDB's flexible schema worked well for cafe data since every cafe has different attributes. Atlas M0 free tier handles the current scale comfortably.

Why PWA over a native app?

The honest reason: I didn't want to pay ₹10,000 for app store fees before validating the idea.

But the more I built it the more it made sense. No app store review delays. Instant updates the moment I push to main. Works offline. Installs to home screen. For India's Android dominant
market, PWA install rates are surprisingly strong.

I used vite plugin pwa with Workbox's injectManifest strategy instead of the simpler generateSW strategy. It's more work to set up but gives you full control over the service worker, which I needed for custom push notification handling.

Why Vercel + Render?

Total monthly infrastructure cost: ₹0.

Vercel handles the frontend — auto-deploys on every push to main, global CDN, zero config. Render hosts the Express backend on their free tier.

The catch with Render free tier is cold starts. First request after inactivity takes around 50 seconds. My fix: UptimeRobot pings the /health endpoint every 5 minutes. Free, takes 2 minutes to set up, completely solves the problem.

Why not Next.js?

I considered it for SSR and SEO benefits. Decided against it because I already knew Vite + React well and solo maintainability mattered more than marginal SSR gains at MVP stage.

I solved the SEO problem a different way, react-helmet-async for unique title and meta description on every route, a dynamic sitemap
served directly from Express hitting MongoDB so it's always current, and JSON-LD schema markup on every cafe page. Ended up with
Lighthouse SEO score of 100 in production.

These are the bugs that cost me the most time. Sharing them so you don't lose the same hours.

Mongoose mapped 'Cafe' to 'caves'

Mongoose has an irregular pluralisation rule. My 'Cafe' model was being mapped to a MongoDB collection called 'caves' — not 'cafes'.
Everything appeared to work fine but data was being written to and read from the wrong collection entirely.

Lost a lot of time to this one before I figured out what was happening.

Fix: explicitly set the collection name in schema options:

const CafeSchema = new mongoose.Schema({...},
{ collection: 'cafes' })

Worth watching for with any model name that has an irregular plural form.

VAPID key mismatch silently broke all push notifications

Push notifications worked perfectly in development. In production — nothing. No errors, no logs, just complete silence.

Root cause: I had generated different VAPID key pairs on Vercel and Render. The browser stores the public key at subscription time. When the server uses a different private key to sign the push, the push service rejects it silently, no error thrown, nothing in the logs.

Fix: generated one matched VAPID pair, set both public and private keys as environment variables on both platforms. Then wipe all existing push subscriptions from MongoDB and make users resubscribe. The mismatch is a silent killer, if push ever stops working with no obvious reason, check this first.

iOS Web Push is not what it looks like

iOS 16.4+ technically supports Web Push. In practice it's a different story.

The PWA must be installed to the home screen before push works at all. The user must grant permission after install, not before. Safari
handles the permission flow completely differently from Chrome. And even after all that, reliability is inconsistent.

I spent a week trying to get iOS push working properly before accepting it as a known limitation. For India's market this turned out to not matter, Android is the dominant platform and Android push works perfectly. Don't let iOS Web Push block your launch.

React SPA is invisible to Google on day one

A standard React SPA serves a nearly empty HTML file and injects content via JavaScript. Googlebot can render JavaScript but does it
slowly and inconsistently. On launch day the cafe pages were essentially invisible to Google.

The fix stack I used:

→ react-helmet-async, unique title and meta
description on every route. Single highest
impact SEO change you can make on a React app.

→ Dynamic sitemap from Express, a route that
queries MongoDB and generates sitemap.xml
on request. Always current, never stale,
updates automatically when you add new cafes.

→ JSON-LD schema markup, CafeOrCoffeeShop
schema on every cafe page with rating,
opening hours, and address. Eligible for
rich results in Google Search.

→ vercel.json rewrites, ensures all routes
return index.html so direct navigation
doesn't 404.

Result: Lighthouse SEO score of 100 in production. First organic impressions appearing in Google Search Console within 2 weeks of
launch.

Here's the full stack if you want the quick overview:

Frontend: Vite + React 18 + Tailwind CSS + vite-plugin-pwa + deployed on Vercel.
Backend: Node.js + Express 4 + Mongoose 8,deployed on Render free tier.
Database: MongoDB Atlas M0 (free tier).
Media: Cloudinary with f_auto + q_auto for automatic WebP optimisation.
Auth: JWT + bcryptjs + Google OAuth via Passport.
Push: web-push npm package with VAPID keys, zero third party cost.
Total monthly cost: ₹0.

I posted about BaseBrew on r/Chandigarh last week, first ever Reddit post, 24 day old account with 1 karma when I woke up that morning.

24 hour results:
→ 13,000 views
→ 92 upvotes, 96% upvote ratio
→ #1 post on r/Chandigarh
→ 53 organic private shares
→ 70 comments

The 53 private shares surprised me most, that means 53 people saw BaseBrew and immediately thought of a specific person to send it to.
That's the word of mouth signal I was building toward.

Current: 12 signups, 57 PWA installs.

Next up:

→ Cowork Sessions — post intentional work
sessions at a cafe, other users request to
join, host approves. The trust model is the
most interesting engineering problem I've
designed so far.
→ Play Store + App Store via PWABuilder TWA
→ Delhi NCR expansion once Chandigarh hits
500+ MAU

Building this entirely in public. If you're working on a hyperlocal product, have questions about the PWA setup, VAPID push implementation, GeoJSON Near Me search, or the React SPA SEO
approach, drop them in the comments. Happy to answer everything.

visit BaseBrew if you're
ever in Chandigarh.

Top comments (0)