Freelance DevRole
Client WorkType
1 WeekTimeline
−50%Driving Saved

THE PROBLEM

The company had an Excel sheet and told people to figure it out

A client's field service workers were handed a list of addresses every morning with no logic attached. No clustering. No optimization. Just stops in the order someone typed them. Workers were covering 2,000 km/month when 80% of that could be covered in half the distance. Burning fuel, burning time, hitting half the clients they could have. Management knew. Nobody fixed it. They had an Excel sheet and told people to figure it out.

THE PROCESS

How I approached it

I mapped the actual failure points first. The gap wasn't CRM features — it was the complete absence of geographic reasoning. The existing workflow had no clustering, no travel time awareness, and no conflict handling. I needed a routing engine that could own the full lifecycle: import, cluster, optimize, version, and sync back.

Engineering Perspective

"Google Maps charges per matrix calculation. At real usage — hundreds of leads, daily route generation — that bill adds up fast. I didn't want the cost model to punish people for using the tool correctly. So I self-hosted OSRM on my own server using OpenStreetMap data. Zero cost per query. I built batching logic that splits large lead sets into geographic quadrants so responses stay under two seconds. It's more work upfront, but the economics are completely different."

EXECUTION LIFECYCLE

1. CRM Ingestion

Custom Chrome extension scrapes CRM pages and pushes to Next.js API. Leads with invalid phone data are automatically flagged for verification.

2. Distance Matrix Calculation

System builds an OSRM distance matrix (Table API) for all eligible leads. Requests >300 leads are batched via geographic quadrant partitioning.

3. Multi-Phase Routing

Phase A: Clusters leads with hard time-constraints. Phase B: Clusters remaining by proximity. Final step optimizes visit order via OSRM Trip API (TSP).

4. Route Versioning & Execution

Routes are assigned to a calendar day. If a lead drops out, system patches the route by identifying proximity-scored filler candidates and re-optimizing.

KEY DECISIONS

Why I built it this way

What we gainedWhy self-hosted OSRM

Google Maps charges per request. Route matrix calculations at scale means thousands of API calls per day. OSRM runs on my own server, pulls from OpenStreetMap, and costs nothing per query. I wrote batching logic that partitions large lead sets into geographic quadrants to keep response times under 2 seconds regardless of set size.

What we gainedWhy tRPC over REST

With REST, one schema change and something breaks silently. tRPC gives you end-to-end type safety — one change propagates everywhere automatically. "The API returns this field but the frontend expects that field" is not a bug I want to spend time debugging.

What we gainedWhy route versioning

When a lead cancels mid-route, you can't just delete the stop. The original plan needs to stay as history — for billing, for audit, for the rep who needs to explain why they skipped an address. Every change creates a new RouteVersion. The rep only sees the current version.

What we gainedWhy token-based billing

Per-lead pricing means you pay for what you actually use. A token gets consumed on first calculation only — re-optimizing the same lead doesn't cost again. The billing model matches how the tool actually gets used instead of forcing everyone into the same box.

THE SOLUTION

One button. Optimized routes. Synced back to the CRM automatically.

FieldFlow pulls leads from the CRM through a Chrome extension, clusters them by geography and scheduling constraints, and generates optimized daily routes using real road distances — not straight-line estimates. The routing runs on a self-hosted OSRM instance. Actual roads, actual travel times. The rep opens the app, hits “Generate Routes,” and gets a compact visit sequence that cuts driving to the minimum. If a lead cancels mid-route, the system finds the nearest replacement and re-optimizes on the spot. Every status update syncs back to the CRM automatically.

TECHNICAL ARCHITECTURE

EXTERNAL
Custom CRM
CLIENT
Chrome Extension
APPLICATION LAYER
Next.js 15 App Router
tRPC 11Better Auth
PERSISTENCE
PostgreSQL + Drizzle
Lead States, Route Versions, Billing Tokens
ROUTING ENGINE
Self-Hosted OSRM
Table API (Matrix) & Trip API (TSP)

RESULTS

−50%Driving Distance
~1,000 kmSaved Monthly
0 hrsManual Routing
Real-TimeCRM Sync

Workers cut driving from ~2,000 km/month to ~1,000. Same clients, same coverage, half the fuel.

LEARNINGS

What Worked

  • — Self-hosting OSRM was the right call — zero cost per query and full control over road data.
  • — Multi-phase clustering handled hard scheduling constraints without hacks.

What I'd Do Differently

  • — I over-invested in the UI before the core routing logic was fully proven. The conflict-resolution algorithm should have been built and validated first.
  • — Route versioning added complexity early. A simpler append-only history would have been enough to start.
Next.js 15tRPC 11Drizzle ORMPostgreSQLOSRMBetter Auth