Series: Weekend at Claude's — misadventures in building a production app with an AI anyone could mistake for the person who's going to make the whole thing happen
I asked Claude a question I'd been turning over for a while: large companies probably don't want to use our admin PWA, but they might genuinely want to use our functions. Is the PWA built on an API layer, or is it talking straight to the database from the page?
Straight to the database. The PWA and the mobile app both call Firestore directly from the client — subscribeToQuery, onSnapshot, real-time listeners, with app logic and data logic living together in the same components. A handful of Cloud Functions exist, but each one was built for a specific screen action, not as a stable contract anyone outside the project could integrate against. The whole security model is Firestore's rules engine, which only means anything to a client holding a real Firebase login.
So: two tiers, not three. Client and database, nothing in between.
Why I asked Claude if it had an objection
I wanted to know if there was a good reason this hadn't been built already, before I assumed there wasn't. Claude's answer was straightforward — there was no architectural objection, just that nobody had asked for it yet, because nothing outside the project had needed a stable contract until now. A two-tier app talking directly to Firestore is a completely reasonable, fast way to build a single-tenant consumer product. It's also exactly the wrong shape the moment a third party wants to integrate against you, because every internal refactor becomes a silent breaking change for them.
I'll be honest, I half expected Claude to say this should have been the plan from day one — that a proper API layer is the textbook way to build anything, and skipping it was a mistake. It didn't say that, and on reflection it's right not to: there was no third party to design for until this conversation. Building the abstraction speculatively, before anyone needed it, would have been the bigger mistake — more code, more indirection, slower iteration, for a use case that didn't exist yet.
The actual design
Once the case was real, the fix was narrow on purpose. Not "abstract everything" — just the slice that an outside org would actually want: pushing offers in, pulling demand signals out, reading member lists. New, versioned, HTTP-triggered Cloud Functions sitting in front of a handful of existing internal functions, authenticated with API keys instead of Firebase logins, every response reshaped so an internal field rename never breaks an external partner. The consumer-facing mobile app stays exactly as it is — direct Firestore access is the right call there, full stop, because its real-time and offline requirements are exactly what a generic REST API handles worst.
The debate that mattered more than the architecture
The architecture took one afternoon to land on. The harder call was how to build it without breaking what already works.
My instinct was to build a second, parallel instance of the whole PWA stack — stand up the new design next to the old one, compare them side by side, only cut over once I trusted it. That's the standard advice for exactly this kind of change.
Claude pushed back, gently. That pattern — the strangler fig, gradual cutover, traffic shifted slowly — earns its cost when you have live users you can't afford to break. We don't have that yet. A full second PWA instance means a second build, a second hosting target, a second .env, and a second set of screens that can quietly drift from the original while you're busy comparing them. For a project built solo on weekends, that's real ongoing weight for a comparison I could get more cheaply another way.
What we landed on instead: build the new API as additive functions, test it directly with real requests, and add one new panel inside the existing PWA — a Developer/API Keys screen — that calls the new layer instead of Firestore. Enough to prove the pattern end to end. If something's wrong with the design, I unwind one panel, not a forked app.
We're not in production. That's exactly why this was the moment to just make the change, carefully, instead of building two of everything to be sure.
Bernie would have built the second copy out of habit. We asked whether we actually needed it first.
Aphilaty is a privacy-first community coordination app. aphilaty.com