Clinica Naturell
A wellness clinic's site, booking and CMS - shipped without a backend, at €0 a month

- Routes
- 29 - 20 public, 9 admin
- Backend
- none · 9 Firestore collections · rules carry authorization
- Search
- 8 routes prerendered · per-page JSON-LD · sitemap from the same data module
- Consent
- versioned 4-category store gating the TikTok Pixel and Google Maps
- Paid social
- 246 leads from 1,375 RON · best campaign 2.52 RON per lead
- Infrastructure cost
- €0 / month
- Role
- Sole technical and marketing resource
- Client
- Clinica Naturell, Timișoara
- Stack
- React 19TypeScriptFirebaseFirestore rulesPuppeteer prerenderTailwind CSS 4Cloudflare DNS + Google Workspace
Security rules as the authorization layer
The clinic needed booking, lead capture and a CMS, but no server and no monthly bill - and Firebase's free tier has no Cloud Functions. So the trust boundary moved into Firestore rules. Public collections accept creates only, and only when the payload carries the required keys with the expected types; reads, updates and deletes require the admin claim. Appointments add a second read path so a signed-in client can see their own bookings and nothing else.
Transactional email - the one thing that genuinely wants a server - goes through a third-party form API, fire-and-forget, so a failed notification can never block the Firestore write that is the actual source of truth.
The content audit
The clinic reported that service photos sometimes didn't match. They matched almost nothing. Content had been migrated from a hosted CMS that named every image with an opaque hash, so pairings had been made by filename, effectively at random. Hashing the directory showed why: 29 device photographs were only 16 unique files. A biofeedback description sat over a photo of a different device; four of five blog posts carried unrelated equipment.
The fix was not a find-and-replace. I opened every unique image, identified the equipment, and replaced the hash references with a named, commented map so a wrong pairing is visible on sight in review. The service list went from sixteen ad-hoc entries to the six categories the clinic actually books, with a 301 for every retired URL and zero new 404s. This is the story I tell in interviews: a vague complaint pointed at something systemic, and the fix left the codebase unable to hide the same class of bug again.
Marketing with the numbers in view
Because I ran the paid campaigns as well as the site, tracking had to be lawful and load-bearing at once. A versioned four-category consent store gates the TikTok Pixel; it injects itself only once analytics consent is granted and activates the moment a visitor changes their mind, no reload. The campaigns delivered 246 leads from 1,375 RON of spend, and the channel grew to 2,185 followers on daily publishing I produced and edited myself.
Assessment and recruitment platform for a university department - five quiz engines, one data model