Case study · Territory intelligence
RoutePro: a whole market, ready to work.
Turning an entire geographic market into a sales territory someone can actually work.
- Role
- Founder, sole builder
- One modeled territory
- 8,378 facilities in 35 miles
- Service value found
- $2M+ a year, one market
- Contact coverage
- About 90%
The problem
No database lists these markets.
Local commercial service companies (hood cleaners, fire inspectors, grease trap pumpers) don't have a traditional account database. Their market is spread across Google Maps, directories, public datasets, and thousands of small websites.
Standard filters fail here. Only 38% of hood cleaners sit under any one LinkedIn industry, and the matching industry code returns 184,000 contacts, mostly the wrong ones.
How do you turn every potential business in a territory into a ranked list of accounts a salesperson can actually work?
What I built
From raw places to a ranked territory.
It combines 4+ primary data sources (paid databases, public data, and AI-assisted enrichment) and reaches about 90% contact coverage. Each business is stored once and shared across every customer; contacts are licensed separately and unlocked per account.
It's built to give field sales teams the same account-mapping workflow that cut my own mapping from about 4 hours a day to 30 minutes. At a modeled 10-rep deployment, that is about 9,100 hours a year, or roughly 4.4 full-time employees of capacity.
- 1Market dataOverture Maps and OpenStreetMap places, loaded into PostGIS
- 2Business discoveryEvery business inside a territory the customer draws on the map
- 3EnrichmentWebsite, category and location data
- 4ICP classificationAccounts classified by vertical
- 5Score and tierTier A, B and C so reps start with the best accounts
- 6Decision makersLicensed contacts, unlocked and billed per account
- 7Territory mapMapbox view of the whole ranked territory
- 8Routes, CRM and outreachRoute planning, contacts, campaigns and a reply inbox inside the app
Architecture
The stack, and why each piece.
| Layer | Choice | Why |
|---|---|---|
| App | Next.js 15, TypeScript, Turborepo | One deployable for UI and API, with shared packages for data, jobs and providers |
| Database | PostgreSQL 16 and PostGIS on Neon | Geospatial queries are the core of the product |
| Data access | Prisma for CRUD, raw SQL for geo | Prisma can't model geography types, so geo reads use hand-written SQL functions |
| Tenancy | Clerk orgs and row-level security | Three separate layers of tenant isolation, so any one can fail without leaking data |
| Maps | Mapbox GL | Clustering at territory-scale point counts |
| Quality | Vitest, GitHub Actions | 12 test files run in CI |
| Data source | Cost per 1k | Can store and re-serve? | Verdict |
|---|---|---|---|
| Overture Maps | $0 | Yes (CDLA-Permissive 2.0) | Chosen |
| OpenStreetMap | $0 | Yes (ODbL, share-alike) | Fallback |
| Google Places | $32 | No, prohibited by its terms | Rejected |
| Yelp Fusion | $229–643/mo | No, 24-hour cap | Rejected |
| D7 Lead Finder | Unpublished | No, and no coordinates | Rejected |
What I learned
What worked, what didn't, what's next.
What worked
- Writing the architecture and data model before code: 63 commits in nine days, with no rewrites of the core schema.
- Storing each business once and serving it to every customer. A second customer unlocking the same contact is served from cache, so the provider isn't paid twice.
What didn't
- My first plan assumed Google Places data. Its terms prohibit storing names and addresses and using coordinates for point-in-polygon queries, which is exactly what a territory is. The licence decided the architecture.
Data limitations
- Maps misses operators without a Google Business Profile, and includes fake ones. One fire protection "company" was a network of about 136 template sites.
- A list graded 5,395 "confirmed" hood cleaners held about 2,229 real businesses once every site was re-read, and a hand check of 100 still found only half were real. I now hand-audit a random sample before trusting any machine grade.
- Only about 7% of hood cleaning sites name an owner, so personalization comes from the company's own story instead.
What I'd change and build next
- Territories now work for every vertical. Next is account data from a source licensed for re-serving, starting with OpenMart.
- Add a site-check step to every record before it can be tiered, so bad data never reaches a rep's list.