A repeatable directory engine, live across the UK and US and expanding, that can be pointed at any listing market

Systems thinking and repeatability: one engine, built once, pointed at any listing market.

RoleData model, platform build, content generation, monetisation
TimelineOngoing development
StatusLive
StackReact 19, TypeScript, Node.js / Express

The situation

Directory content is valuable to readers and expensive to produce by hand, and the same underlying structure repeats across dozens of unrelated verticals: parks, trails, restaurants, coworking spaces. Nobody was treating that as one problem.

What I did

I designed the data model, the content generation approach and the page structure, built the base platform, populated it at global scale, and integrated advertising as the revenue model. Dog Park Explorer is the specific site; the actual product is the engine underneath it. If a reader comes away thinking this is a project about dog parks, the page has failed — the point is the machine that can produce a site like this in a fraction of the original build time.

System diagram

ONE CITY PER RUN: FOUND, REVIEWED BY A PERSON, POPULATED, LINKED AND MONETISED BY TEMPLATE — AND POINTED AT A NEW VERTICAL BY THREE SETTINGS.

The engine is only visible in three places

The pipeline decides which city runs next and what a person has to approve before it can publish. None of that is visible as a pipeline, so it surfaces as three screens: the run queue, the review step that holds a candidate back, and the listing a reader eventually lands on.

FIG. 02 · WHAT THE FLOW PRODUCES3 OF 8 STEPS SHOWN
01
ADMIN · CANDIDATE CITIESDESKTOP
Dog Park Explorer admin discovery queue, listing candidate cities pending processing with a count of cities queued.
EXPAND ⤢, expand
02
ADMIN · CANDIDATE LISTINGSDESKTOP
Dog Park Explorer admin park candidates list, each row showing source data and an accepted/rejected toggle.
EXPAND ⤢, expand
03
PUBLIC · PARK LISTINGPHONE
Published Dog Park Explorer listing page on a phone, showing the park name, rating and hero photo.
EXPAND ⤢, expand
01 · CITIES QUEUEDA new city enters a discovery queue as a candidate. Nothing runs until I choose which to process next.
02 · CANDIDATES REVIEWEDEvery discovered park is a candidate with an accept/reject toggle, checked against its source data before it can go live.
03 · PUBLISHEDThe listing page is the output the whole pipeline exists to produce, and the only part a visitor ever sees.

FIG. 02 — CITIES QUEUED, LISTINGS REVIEWED BY A PERSON, A PUBLIC PAGE OUT.

Key decisions and tradeoffs

Four decisions that shaped the engine, the alternative in each case, and what the choice cost.

Decision 01ARCHITECTURE

Building a reusable engine rather than a single site

ALTERNATIVEbuild Dog Park Explorer as a one off site, which is faster to ship the first time.WHY NOTthe underlying structure, listings, locations, content generation, monetisation, repeats across dozens of unrelated verticals. Building it once as a platform means the next site is a redeployment, not a rebuild.COSTthe initial build took longer than a single purpose site would have, in exchange for every subsequent site taking a fraction of that time.
Decision 02QUALITY

Content generation approach and quality control at volume

ALTERNATIVEwrite listing content by hand, which is the safest way to guarantee accuracy at small scale.WHY NOTit does not scale to a worldwide directory, and the whole premise of the engine depends on populating a market quickly.COSTcontent is generated rather than hand written, which means accuracy has to be handled through the generation process and page structure itself, not through manual review of every page.
Decision 03COMMERCIAL

Advertising as the revenue model, rather than listing fees or subscriptions

ALTERNATIVEcharge venues or listers a fee to appear, or run the directory as a paid subscription for visitors.WHY NOTlisting fees work against populating the directory at scale quickly and completely, which is the point of the engine, and a subscription does not fit a directory people expect to browse for free.COSTrevenue depends on traffic and ad rates rather than a predictable recurring fee, which is a slower, less certain way to monetise than charging up front.
Decision 04DISCOVERABILITY

Page structure and internal linking decisions made for search and AI visibility

ALTERNATIVEa flatter site structure with less deliberate cross linking between listings, locations and categories.WHY NOTa directory lives or dies on being findable for very specific queries, and both search engines and AI assistants rely on structure and internal links to work out what a page is actually about.COSTmore upfront design work on the information architecture, before there was any content to put into it.

Current status

About 800 parks are live today, across the UK and the US, and neither country's coverage is complete yet — that's deliberate. The templates are going through Google's own site quality review before wider rollout and advertising switch on, so coverage is staged rather than a limit of the engine itself, which is already built to produce whichever market or vertical comes next: hiking trails, vegan restaurants, coworking spaces, in a fraction of the time the original build took.

Stack and timeline

The frontend is a React 19 and TypeScript single page app (Vite, Tailwind, shadcn/ui, TanStack Query for server state), talking to a Node.js and Express API deployed as Vercel serverless functions rather than a persistent server. Data lives in a Supabase hosted PostgreSQL database through Drizzle ORM, and listing photos are pulled from Google Places and re-hosted permanently on Cloudflare R2 — the originals expire after a week, so a quarterly refresh job keeps them available without re-fetching on every page load. Cloudflare Turnstile filters bot traffic, Upstash Redis handles rate limiting across the stateless serverless functions, Resend sends notification email, and OpenAI drafts blog content for review before it publishes. Advertising runs through Google AdSense, loaded only after cookie consent.

The build split into a base platform phase, a population phase to bring the directory to scale, and the current phase: passing Google's review before opening up full coverage and new verticals.

React 19TypeScriptNode.js / ExpressPostgreSQL (Supabase)Drizzle ORMCloudflare R2Cloudflare TurnstileUpstash RedisResendOpenAIGoogle AdSense

Have a system that half works and nobody wants to touch?

A systems review puts the situation, the cost and the options in writing.