03 of 04

PierdutCheie

Built for one thumb, on five percent battery.

Emergency car locksmith, Bucharest and Ilfov. Next.js, PWA, 2,332 static pages.

Eleven seconds of the build. The home screen, then one of the 2,332 generated pages for one service in one sector of Bucharest, then the keyword monitor with its service by location matrix open. The two public pages are the live site. Every figure on the dashboard was generated for the photograph: invented queries, invented impressions, invented dates, laid over the real service and location names.

An emergency car locksmith covering Bucharest, Ilfov and five counties around them. The public product is one screen answering one question for somebody standing next to a car they cannot open: will somebody come, and how do I reach them now. There is no form, no account and no cart. Around that screen sits a layer of 2,332 landing pages, one for every service in every place, in two languages, generated at build time out of one typed data layer. Behind a sign-in there is a dashboard counting what the site is actually for, and a second one, built and not yet deployed, that reads the search results back.

The problem

Somebody is standing next to a car they cannot open. The keys are inside it, or the fob is dead, or the car is new enough that the electronics have simply decided not to. They search, they tap the first result, and they have one question: will somebody come, and how do I reach them now. The phone in their hand is usually nearly flat.

Nobody in that state fills in a form or makes an account. So there is no form, no account and no cart. Every public action leaves the site: a phone call, a WhatsApp message with the first line already written, a map pin, a mailbox in the footer. The primary one is pinned to the bottom edge of the screen, where a thumb already is.

What we built

  1. 01

    A site that installs like an app

    Add to home screen and it opens standalone and dark, with a bottom tab bar and a shortcut straight to the emergency sheet. No store, no download, no update to miss. The same code renders a conventional website on a laptop. Both chromes are written into the static HTML and one of them is hidden by CSS, so the right one paints before any JavaScript runs, then the DOM is pruned to the shell that matched rather than left doubled.

    The home screen: an availability badge reading DISPONIBILI ACUM · BUCUREȘTI & ILFOV, the headline “Ești blocat? Te rezolvăm rapid.”, a blurred photograph of a hand holding a car key, a floating capsule of icons with an orange SOS disc at its centre, and a Sună acum and WhatsApp pair along the bottom edge.
    The same page on a phone and on a laptop. Deciding to ship both chromes in one document is what costs the homepage 303 KB of HTML, and it is why neither layout ever flashes into the other.
  2. 02

    There is no form anywhere in it

    Every service card carries the two things a person in this situation will actually do, and so does every one of the generated pages, and so does the sheet behind the SOS disc. A WhatsApp tap asks the phone where it is and writes the answer into the message as a map link, so the locksmith gets a map pin rather than somebody’s description of where they are. Nothing about a caller is stored: the location goes into the message and nowhere else.

    The services list on a phone: cards for deblocare urgentă mașină, înlocuire cheie auto and programare transponder, each with a Sună and a WhatsApp button, above a full-width tab bar with a raised orange SOS disc at its centre.
    This is one of the app’s own preview routes, where the shell draws the full-width tab bar. The homepage renders the same shell with a floating capsule at the right edge instead, which is the version in the film above.
  3. 03

    A page for every service in every place

    Twenty two services across fifty three places, in Romanian and English: 1,166 combinations and 2,332 pages, all generated at build time from 927 lines of typed data. The headings, the breadcrumbs, the structured data, the matrix of internal links, the 2,494 sitemap entries and a social card for every page come out of those same three modules, so adding a location adds its pages and everything that points at them.

    One generated landing page: a breadcrumb, the heading “Deblocare urgentă mașină în Sectorul 1”, a one sentence answer, and a card headed Intervenție rapidă carrying Sună acum and WhatsApp.
    One of the 2,332, for one service in one sector of Bucharest. The body text on it is the fallback the data layer synthesizes rather than copy written for this page, because the per-page copy has never been generated.
  4. 04

    One map, and it is a real one

    The 44 service hubs carry Leaflet over OpenStreetMap tiles, no API key, all 53 places pinned at their true coordinates with the view fitted to them. The search box strips diacritics before it compares, so typing stefanesti finds Ștefăneștii de Jos. Select a pin and the map flies to it and opens a card with a call and a WhatsApp message already addressed to that service in that place. Its 158 KB is loaded on demand and reaches no other page.

    The coverage map: OpenStreetMap tiles under 53 pins across Bucharest and the county around it, with a search box and a distance sorted list of places beside it, each row tagged Rapid or La cerere.
    The map at rest on a phone, and on the laptop capture, one word into the search box: stefanesti typed without diacritics has narrowed the list to two, the map has flown to the first, and its card is open with both actions filled in.
  5. 05

    Its own traffic, counted without a cookie

    The dashboard counts what the site is for: calls, WhatsApp taps, map taps, mail taps, SOS opens. It sets no cookie. The session id lives in the tab and is not written at all until consent is given, and no address, no browser string and no location is ever stored. A signed in admin is not counted. Every write goes through one server route; the browser rules deny writes on every collection, so a forged request cannot reach the database at all.

    The traffic dashboard: a range selector with an export button, four counting cards for visits, page views, conversions and conversion rate, each with a sparkline, and five counters for phone, WhatsApp, email, map and SOS taps.
    Every visit count, tap count and date on this screen was invented for the photograph. The dashboard was run against generated fixtures in a throwaway copy of the app with the database taken out, so none of it is the business’s real traffic.
  6. 06

    Which of the 1,166 pages are doing anything

    This screen and the next one are built and not deployed: the two commits that carry them, and the daily job that would fill them from Search Console, have never been merged into what ships. The coverage tab only exists because the site is programmatic. Locations down the side, services across the top, one cell per generated page, coloured by average position and labelled with impressions, genuine gaps left grey. Above it, how many of the 1,166 have been seen at all.

    The coverage tab: four counters reading 218 combinations with impressions, 1,166 total combinations, 18.7 per cent coverage and 228 active pages, above a matrix with locations down the left, services across the top, and a number in each filled cell.
    Invented impressions and invented positions throughout. Only the service and location names are real, because the matrix resolves them against the same data layer the 2,332 pages are generated from, and it would render empty otherwise.
  7. 07

    The queries one place off the first page

    Opportunities takes every query sitting between position four and twenty and scores it: impressions multiplied by the click rate a third position typically earns, less the clicks it gets now, sorted by the difference. The same arithmetic runs over pages. A fourth tab flags two of the site’s own pages competing for one query, which is the failure a 1,166-page site invites. None of it is precomputed. It is all worked out in the browser from the stored rows.

    The opportunities tab: a table headed “La un pas de prima pagină” listing queries with their average position, their impressions and an estimate of the extra clicks each would earn from the top three.
    Every query and every figure in this table was invented for the photograph. The one column that is an estimate says so in the app’s own footnote rather than in ours.

A panicking person does not need flashing red. The SOS disc pulses once a second, which is a resting heart rate rather than an alarm.

The emergency path, which is the whole product: tap the SOS disc, the sheet rises, press the call row. The press is held rather than released, so nothing was ever dialled and WhatsApp was never opened.

The parts worth telling

The arrival estimate was built, and then deleted

Each page used to carry a drive time: straight line distance from the dispatch point, multiplied because roads wind, divided by an average city speed, plus five minutes to get somebody moving, rounded into a five minute range. On 3 June 2026 all of it came off the screen, fifteen files and 230 lines, on the stated grounds that an arrival time is a liability when it cannot be met. The arithmetic is still there. Its answer is now only ever read as true or false: this place gets a fast response, that one gets call for availability.

A refused location is a fact, not an absence

WhatsApp messages were arriving with no address, from phones only. iOS Safari fails silently after a dismissed permission prompt and never asks again, and the missing coordinates were collapsing quietly to nothing. Now a refusal comes back as a reason. High accuracy is switched off on purpose, because a coarse fix in a second or two is precise enough to send a van and GPS regularly overruns the timeout. The message keeps its location line either way: if the phone will not say where it is, the sentence asks the caller to drop a pin.

There is no test suite, and one check that matters

No test runner, no test files, no continuous integration. What stands in for all of it is a single script: service and location ids and slugs unique, every coordinate finite and in range, nearer places estimating lower than farther ones, and every place either inside the fast tier or outside it, never both. It throws rather than warns, and it finishes in 0.16 seconds. Linting does not pass either, at four errors, all of them the same new React rule.

294 KB, on a page written for five percent battery

The homepage pulls thirteen scripts and 294 KB of gzipped JavaScript. The splits work: the 460 KB Firebase chunk, Recharts and Leaflet are none of them on it, and the homepage HTML does not reference Firebase once. What is left is the shell, and it is still more than the brief asked for. Lighthouse on mobile, measured on 25 August 2026, reads 87 for performance, 100 for accessibility and 100 for best practices. The 91 the repository recorded was measured on 31 May, at the second commit, when the app was a shell and nothing else.

How it works

  • 22 services
  • 53 locations with real coordinates
  • One dispatch point
Typed data, checked before the build
  • 2,332 landing pages
  • 2,494 sitemap URLs, ro and en
  • Fast response, or call for availability

Numbers

2,332
landing pages in two languages, from 22 services and 53 locations
4,845
prerendered route entries in one build, 310 MB of HTML on disk
192 / 192
message keys in Romanian and English, none of them diverging
87 / 100 / 100
Lighthouse on mobile, 25 August 2026: performance, accessibility, best practices

Built with

  • Next.js 16
  • React 19
  • TypeScript
  • Tailwind 4
  • next-intl
  • Static at build time
  • Progressive web app
  • Leaflet and OpenStreetMap
  • Firestore
  • Firebase Admin
  • Recharts
  • Google Search Console
  • Vercel

Launched, and it is a client’s business. Two things on it are honestly unfinished. The 2,332 pages render the fallback text the data layer synthesizes rather than copy written for each of them, because that copy was designed to be generated once, offline, and committed, and it has not been run. And the keyword monitor is finished but not deployed: it sits on a branch 1,574 lines ahead of the one that ships, with its daily job and its database rules alongside it.