Detour
A smart navigation app that scores routes based on driving difficulty, stress levels, and user preferences rather than just fastest time.
Project Overview
Detour is a personal navigation app I built that goes beyond traditional turn-by-turn directions. Instead of just showing the fastest route, Detour analyzes routes for driving difficulty, stress levels, traffic conditions, and alignment with user preferences.
The app learns from your driving history and preferences to recommend routes that match how you actually want to drive.
Role: Solo developer
Status: Unfinished demo

The Problem
Traditional navigation apps optimize for one thing: time. But that's not always what drivers want:
- New drivers might want to avoid complex highway merges
- Some people prefer surface streets even if it takes longer
- Others want to avoid left turns across traffic
- Familiar routes feel more comfortable than optimal ones
Detour scores routes on multiple dimensions and lets users configure their preferences.
Architecture
Docker Compose Services:
| Service | Role | Port |
|---|---|---|
| Detour API | FastAPI backend, route scoring | 8000 |
| Valhalla | OSM routing engine | 8002 |
| PostGIS | Spatial database | 5432 |
Client:
| Component | Technology |
|---|---|
| Mobile App | Flutter with MapLibre GL |
Route Scoring System
Each route is scored across multiple dimensions:
| Score | What It Measures |
|---|---|
| Stress | Highway merges, complex intersections, turn frequency |
| Executability | Difficulty of individual maneuvers (hard left turns, short merge lanes) |
| Predictability | How consistent the route is (highways vary more with traffic) |
| Preference Alignment | Match against user's stated preferences |
| Traffic | Real-time congestion and incidents via HERE API |
| Familiarity | Routes the user has taken before get a boost |
Routes are ranked by a weighted combination of these scores, not just travel time.
Executability Analysis
The API analyzes every maneuver for difficulty:
# Maneuvers are tagged as easy, moderate, or hard
exec_result = analyze_route(raw_maneuvers)
# Hard maneuvers get warnings
warnings_map = {}
for mi, diff in enumerate(exec_result["difficulty_per_maneuver"]):
if diff == "hard":
warnings_map[mi] = exec_result["warnings"][warning_idx]
Examples of hard maneuvers:
- Left turn across 4+ lanes of traffic
- Short highway merge lanes
- Complex interchange weaves
- Unprotected left turns at busy intersections
User Preferences
Users can configure their routing preferences:
class Preference:
avoid_highways: bool
avoid_left_turns: bool
prefer_familiar_routes: bool
avoid_heavy_traffic: bool
avoid_incidents: bool
max_acceptable_delay_pct: float
The stress calculation adapts to preferences:
if user_avoids_highways:
# Highways are stressful for this user
highway_stress = highway_pct * 0.4
surface_stress = 0
else:
# Surface streets are more stressful (more complexity)
highway_stress = highway_pct * 0.1
surface_stress = surface_pct * 0.25
Familiarity Scoring
Detour tracks routes users have taken and boosts familiar routes in rankings:
familiarity_results = await compute_batch_familiarity(
db=db,
user_id=user.id,
routes=route_data_for_familiarity,
origin_lat=req.origin.lat,
origin_lng=req.origin.lng,
dest_lat=req.destination.lat,
dest_lng=req.destination.lng,
)
# Familiar routes get tagged and boosted
if fam_result.is_familiar:
r.tags.append("familiar")
Valhalla Routing Engine
The backend uses Valhalla, an open-source routing engine built on OpenStreetMap data:
valhalla:
image: ghcr.io/gis-ops/docker-valhalla/valhalla:latest
environment:
- tile_urls=https://download.geofabrik.de/north-america/us/michigan-latest.osm.pbf
https://download.geofabrik.de/north-america/us/nevada-latest.osm.pbf
Multiple costing profiles generate route alternatives:
- Balanced — Default mix of highways and surface streets
- Highway Heavy — Prefer interstates
- No Highway — Avoid highways entirely
- Shortest — Minimize distance
Traffic Integration
Real-time traffic data from HERE API:
route_traffic = await get_route_traffic(
polyline=polyline,
total_distance_m=distance_m,
base_duration_sec=duration_sec,
)
traffic_data = TrafficConditions(
overall_severity=route_traffic.overall_severity,
avg_jam_factor=route_traffic.avg_jam_factor,
total_delay_sec=route_traffic.total_delay_sec,
incident_count=route_traffic.incident_count,
)
Flutter App
The mobile app uses:
- MapLibre GL — Open-source map rendering
- Geolocator — Device GPS access
- Google/Apple Sign-In — Authentication
- Provider — State management
Why I Stopped
The core routing and scoring system works well in the demo. I stopped development because:
- Building a production-quality navigation UI is a massive undertaking
- Maintaining up-to-date map data requires ongoing infrastructure
- The problem space (navigation) is well-served by existing apps
The project was a great learning experience in routing algorithms, geospatial databases, and scoring systems.
Tech Stack
| Area | Tools |
|---|---|
| API | FastAPI, Python |
| Routing | Valhalla (OSM) |
| Database | PostGIS, SQLAlchemy |
| Traffic | HERE API |
| Mobile | Flutter, MapLibre GL |
| Auth | Google Sign-In, Apple Sign-In |
| Infrastructure | Docker, Docker Compose |