Skip to content

Latest commit

 

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Route Planner — Excel → map → delivery order (OSRM)

Leer en español

Upload an Excel file with stops, plot them on a map, and compute the order in which they should be delivered by solving the TSP with OSRM. Includes per-stop ETAs, time-window alerts, and Excel export.

The Vite/React frontend and the FastAPI API run separately. The routing engine stays independent of the UI and of the HTTP transport.

Excel/CSV ─▶ normalize ─▶ geocode (missing) ─▶ OSRM /trip ─▶ itinerary ─▶ map + panel

Quick start

cd web
npm ci
npm run dev
# http://localhost:5173

Click Cargar datos de ejemplo (Load sample data) or drag in web/public/samples/paradas-ejemplo.xlsx. The frontend uses npm packages; the map tiles still need internet access.

Loading sample data and calculating a route in Miami-Dade, FL


Excel format

Headers are auto-detected, in Spanish or English, with or without accents. Every column is optional except that you need an address or lat/lon:

Field Recognized headers
Reference Referencia, Ref, ID, Orden, BL, Contenedor, Guía, Tracking
Name Cliente, Nombre, Consignatario, Destinatario, Customer
Address Direccion, Dirección, Address, Calle, Domicilio
City / State / ZIP / Country Ciudad, Municipio, Departamento, CP, País
Coordinates Latitud/Lat/Y, Longitud/Lon/Lng/X
Service time Servicio, Tiempo_servicio, Dwell (minutes)
Time window Ventana_inicio/Desde, Ventana_fin/Hasta (HH:MM)
Notes Notas, Observaciones, Remarks

Rules: rows with valid lat/lon are used as-is; otherwise the app geocodes address + city + state + zip + country. Accepts decimal commas (10,9878) and discards 0,0. Rows that can't be located are listed separately and excluded from the route.

Parameters

  • Depot / origin — any row; the first one by default. Fixed as the starting point (source=first in OSRM).
  • Return to depotroundtrip=true; adds the return leg to the totals.
  • Fixed final destination — the last row in the file closes the route (destination=last).
  • Departure time and service time per stop — used to compute ETAs; service time can be overridden per row.
  • Strategy:
    • OSRM /trip (default) — OSRM solves the TSP. Fast and good.
    • /table + NN + 2-opt — time matrix + a custom heuristic. Slower, but it's the extension point for priorities, hard time windows, or multi-vehicle routing (web/src/lib/core/strategies/nn-two-opt.js, tourCost function).

Architecture

web/
  src/
    App.jsx                 composition root (React mount point)
    store/
      useConfigStore.js     Zustand + persist: server mode, OSRM/geocoder/plan config
      usePlannerStore.js    Zustand: stops, ingestion, calculation, alerts, selection
    hooks/
      useTheme.js           light/dark theme
    components/             TopBar, FilePanel, RouteParamsPanel, ResultsPanel,
                             RouteSequence, StopsTable, PlannerMap (Leaflet)
    lib/
      config.js             DEFAULT_CONFIG + deepMerge, consumed by useConfigStore
      ports.js               contracts: Geocoder, RoutingEngine, StopSource
      core/                 ← pure logic, no DOM or HTTP (testable in Node)
        normalize.js          raw Excel -> Stops
        planner.js            geocoding -> optimization -> itinerary with ETAs
        strategies/            osrm-trip.js · nn-two-opt.js
      adapters/              ← swappable implementations
        xlsx-source.js         SheetJS (read + export)
        nominatim-geocoder.js  Nominatim with rate-limit + cache
        osrm-engine.js         OSRM /trip, /table, /route
        http-backend.js        the same ports, against YOUR API
        factory.js             the single decision point: which adapter goes in
api/                        optional FastAPI layer (same contracts)
osrm/                       reproducible OSRM data build
docker-compose.yml          local OSRM infrastructure

The rule: core/ never imports from adapters/, store/, or the React tree. That's why switching from "everything in the browser" to "behind my own API" is just changing cfg.mode — and why the tests run in Node, without a browser.

The layers you add when the client wants this for real

Each one is additive; none of them require touching core/.

Layer What it solves Where
1. Your own API hides OSRM/geocoder URLs, shared geocoding cache, global rate limiting, auth and per-client quotas api/app/main.py + flip server mode in the UI
2. Your own OSRM removes the ~100-stop limit and the dependency on an SLA-free demo osrm/build.py + docker-compose.yml
3. Your own Nominatim geocoding without the 1 req/s limit (the real bottleneck on large files) commented-out service in the compose file
4. Persistence save plans, compare planned vs. executed, per-driver history new RouteStore adapter + tables
5. Real VRP multiple vehicles, capacities, hard time windows, shifts swap the strategy for VROOM/OR-Tools behind the same port

1 · Run the API

cd api
uv sync --all-extras --dev
OSRM_URL=https://router.project-osrm.org uv run uvicorn app.main:app --port 8000
# API at http://localhost:8080; Vite serves the frontend on :5173

Then in the UI: Servidores → Modo servidor (Servers → Server mode). The frontend switches to calling /api/geocode, /api/trip, /api/table instead of reaching out to the internet.

2 · Your own OSRM (removes the 100-stop limit)

uv run --project osrm python osrm/build.py build florida
OSRM_REGION=florida docker compose up -d --wait osrm

osrm-routed comes up with --max-trip-size 1000 --max-table-size 2000: that's where the public demo's ceiling disappears. Start the API with OSRM_URL=http://localhost:9090 and turn on server mode in the UI.

The builder supports only the current Colombia and Florida markets:

uv run --project osrm python osrm/build.py build colombia
OSRM_REGION=colombia docker compose up -d --wait osrm

Tests

cd web
npm test                # core: normalization, OSRM parsing, 2-opt, ETAs
npm run build           # Vite production build

cd ../api
uv run pytest -q        # API tests, once they exist

Known limitations

  • Public OSRM demo: ~100 coordinates per request, car profile only, no SLA. Don't use it with client data in production.
  • Public Nominatim: 1 req/s and bans bulk use. 200 addresses without coordinates ≈ 4 minutes the first time (cached afterward).
  • /trip optimizes distance/time, not time-window compliance: the UI flags stops that arrive late, but doesn't reorder around windows. That's layer 5.
  • One vehicle per file.

Licenses

Leaflet (BSD-2) and SheetJS (Apache-2.0) are installed from npm. OSM data is ODbL: map attribution must be kept.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages