S
Spotter Fuel Planner Backend
Django REST Framework · OSRM · Fuel-price optimizer

Architecture console for route fuel planning.

System Architecture

01

Client Request

Receives JSON with start, destination, and optional vehicle settings.

02

Validation

FuelPlanRequestSerializer accepts address strings or USA-bounded coordinate objects.

03

Location + Route

Address inputs resolve through local city/state cache or Census, then OSRM returns GeoJSON route geometry.

04

Station Corridor

Active imported stations are filtered by route bounding box, projected to route miles, and clipped by corridor distance.

05

Fuel Optimizer

A reachable-stop planner buys enough fuel to reach cheaper downstream fuel, the destination, or the best reachable fallback.

Storage

Fuel data

Imported CSV rows become FuelStation records with price, identity, active state, and geocoding metadata.

External providers

OSRM + Census

OSRM calculates the route. Census handles freeform address geocoding and batch station geocoding when import runs with network access.

Fallbacks

GeoNames city data

Simple City, ST inputs and unmatched station rows can use city/state coordinates to avoid avoidable coverage gaps.

Demo path

Runtime lifecycle

  • Docker startup runs migrations against the mounted SQLite database in /app/data.
  • The bundled CSV imports on startup by default so the demo container is ready for API calls.
  • The offline import path skips live Census batch geocoding but applies local city/state coordinates.
  • Gunicorn serves the API and this static architecture console from the same origin.
Failure boundaries

Clear API outcomes

  • Serializer validation stops malformed requests before provider calls.
  • Unresolved locations and infeasible fuel plans return structured 422 responses.
  • Routing provider failures return 503 instead of leaking implementation details.
  • OpenPanel tracking is nonblocking and does not change the API response path.
Code walkthrough map

Where to point during the Loom

routing/views.py
DRF endpoint boundary, request validation, error mapping, and analytics event tracking.
routing/serializers.py
Input contract for coordinate objects, address strings, and vehicle parameters.
routing/services/planner.py
Application orchestration: resolve locations, request route, find candidate stations, build response.
routing/services/candidates.py
Route-corridor station filtering and route-mile projection for active imported stations.
routing/services/optimizer.py
Reachability and price-based fuel stop selection with Decimal-based gallon and cost calculations.
fuel/models.py
Persistent station, price, geocoding state, and request-location cache models.
docker-entrypoint.sh
Container startup lifecycle: migrate, optionally import/geocode fuel data, then launch the server process.

Live API Console

Run Django first with python manage.py runserver. For same-origin browser calls, open this page at /static/routing/architecture-api-demo.html on the same host and port as the Django server.

Request

Response

Idle
Distance-
Total cost-
Stops-
Submit a request to inspect the API response.

Endpoint Contract

Accepted request fields

FieldTypeRules
startstring or coordinate objectRequired. String must be nonblank. Coordinates must be within broad USA bounds.
destinationstring or coordinate objectRequired. Same validation as start.
corridor_milesintegerOptional. Defaults to 10. Maximum is 25.
max_range_milesintegerOptional. Defaults to 500. Cannot exceed 500.
miles_per_gallondecimalOptional. Defaults to 10.00. Minimum is 1.

Response shape

  • route includes route distance and OSRM GeoJSON LineString geometry.
  • fuel_plan includes selected stops, gallons, cost, total gallons, total cost, MPG, range, and currency.
  • starting_fuel_assumption prices fuel needed before the first selected station when the station dataset starts away from the origin.
  • warnings reports planner assumptions such as needing enough starting fuel to reach the first selected station.
  • metadata.routing_provider identifies the routing provider as osrm.
400

Invalid request

Missing fields, invalid location types, out-of-range coordinates, or unsupported parameter values.

422

Planning failed

location_not_found or no_feasible_fuel_plan when the route exists but station coverage cannot satisfy range constraints.

503

Provider unavailable

routing_unavailable when OSRM or geocoding provider calls fail unexpectedly.

Operations

Setup commands

# Local development
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py import_fuel_prices fuel-prices-for-be-assessment.csv --skip-geocoding
python manage.py runserver

Docker demo commands

make docker-build
make docker-run SPOTTER_SECRET_KEY='replace-this-secret'

# Optional: run with live Census batch geocoding
make docker-run-import-geocode SPOTTER_SECRET_KEY='replace-this-secret'

Important assumptions

  • The default vehicle range is 500 miles and the default fuel economy is 10 MPG.
  • The planner does not grant free starting fuel; full route gallons are represented in totals.
  • Imported stations must be active and have coordinates to participate in planning.
  • Live calls depend on OSRM availability unless tests or local code inject a fake router.

Verification coverage

  • API tests cover success, validation errors, infeasible plans, unresolved locations, and provider failures.
  • Service tests cover station importing, geocoding fallback, route candidates, OSRM handling, and optimizer behavior.
  • The Postman collection mirrors the key demo paths: coordinates, address strings, and custom vehicle settings.