{"id":47697416,"url":"https://github.com/geiserx/pumperly","last_synced_at":"2026-06-09T01:04:43.366Z","repository":{"id":344453743,"uuid":"1181844101","full_name":"GeiserX/Pumperly","owner":"GeiserX","description":"Open-source fuel \u0026 EV route planner. Real-time prices across enabled countries. Self-hostable.","archived":false,"fork":false,"pushed_at":"2026-04-02T08:22:43.000Z","size":3996,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-03T03:18:13.571Z","etag":null,"topics":["docker","electric-vehicle","europe","ev-charging","fuel-prices","gas-station","geocoding","maplibre","maps","nextjs","open-data","openstreetmap","petrol","postgis","react","route-planner","self-hosted","tailwindcss","typescript","valhalla"],"latest_commit_sha":null,"homepage":"https://pumperly.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GeiserX.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null},"funding":{"github":"geiserx"}},"created_at":"2026-03-14T17:45:43.000Z","updated_at":"2026-04-02T19:16:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/GeiserX/Pumperly","commit_stats":null,"previous_names":["geiserx/propel","geiserx/pumperly"],"tags_count":54,"template":false,"template_full_name":null,"purl":"pkg:github/GeiserX/Pumperly","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeiserX%2FPumperly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeiserX%2FPumperly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeiserX%2FPumperly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeiserX%2FPumperly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GeiserX","download_url":"https://codeload.github.com/GeiserX/Pumperly/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeiserX%2FPumperly/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31491097,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-06T17:22:55.647Z","status":"ssl_error","status_checked_at":"2026-04-06T17:22:54.741Z","response_time":112,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","electric-vehicle","europe","ev-charging","fuel-prices","gas-station","geocoding","maplibre","maps","nextjs","open-data","openstreetmap","petrol","postgis","react","route-planner","self-hosted","tailwindcss","typescript","valhalla"],"created_at":"2026-04-02T16:38:14.635Z","updated_at":"2026-06-09T01:04:43.356Z","avatar_url":"https://github.com/GeiserX.png","language":"TypeScript","funding_links":["https://github.com/sponsors/geiserx"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/images/banner.svg\" alt=\"Pumperly banner\" width=\"900\"/\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n\u003ch1 align=\"center\"\u003ePumperly\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eOpen-source fuel \u0026amp; EV route planner. Real-time prices across 36 countries. Self-hostable.\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pumperly.com\"\u003e\u003cimg src=\"https://img.shields.io/badge/Pumperly-pumperly.com-34d399?style=flat-square\u0026logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMiAzMiI+PHBhdGggZmlsbD0id2hpdGUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTcgMGgxOGMzLjg3IDAgNyAzLjEzIDcgN3YxOGMwIDMuODctMy4xMyA3LTcgN0g3Yy0zLjg3IDAtNy0zLjEzLTctN1Y3QzAgMy4xMyAzLjEzIDAgNyAwek0yMiAyTDcgMTdoOWwtNiAxM0wyNSAxM2gtOXoiLz48L3N2Zz4=\u0026logoColor=white\" alt=\"Pumperly\"\u003e\u003c/a\u003e\n  \u003ca href=\"LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/GeiserX/pumperly?style=flat-square\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://hub.docker.com/r/drumsergio/pumperly\"\u003e\u003cimg src=\"https://img.shields.io/docker/pulls/drumsergio/pumperly?style=flat-square\u0026logo=docker\u0026label=Docker%20Pulls\" alt=\"Docker Pulls\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/GeiserX/awesome-europe#readme\"\u003e\u003cimg src=\"https://img.shields.io/badge/listed%20on-awesome--europe-ffcc00?style=flat-square\u0026logo=europeanunion\u0026logoColor=ffcc00\u0026labelColor=003399\" alt=\"listed on awesome-europe\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://artifacthub.io/packages/helm/pumperly/pumperly\"\u003e\u003cimg src=\"https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/pumperly\u0026style=flat-square\" alt=\"ArtifactHub\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/GeiserX/Pumperly\"\u003e\u003cimg src=\"https://codecov.io/gh/GeiserX/Pumperly/graph/badge.svg?style=flat-square\" alt=\"codecov\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/images/screenshot-route.png\" alt=\"Route planning — Huelva to Girona with fuel stations along the corridor\" width=\"900\"/\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/images/screenshot-map.png\" alt=\"Map view — color-coded fuel stations by price in Murcia\" width=\"900\"/\u003e\n\u003c/p\u003e\n\n---\n\n**Try it now at [pumperly.com](https://pumperly.com)** — or self-host it with Docker Compose.\n\n## What is Pumperly?\n\nPumperly combines route planning with real-time fuel prices and EV charging station data. No other open-source tool does this.\n\n- Plan a route from A to B with autocomplete and alternative routes\n- See every fuel station and EV charger within a corridor along your route\n- Filter by \"cheapest within N minutes detour\" — the feature no competitor has\n- Covers 36 countries across Europe, Latin America, and Oceania\n- 16 languages, multi-currency, fully self-hostable\n- 100% open source (GPL-3.0), no tracking, no cookies, no accounts\n\n## Features\n\n- **Route planning** — Geocoding via [Photon](https://github.com/komoot/photon), routing via [Valhalla](https://github.com/valhalla/valhalla), with alternative routes\n- **Real-time fuel prices** — From government open data APIs and community sources\n- **EV charging stations** — Via [Open Charge Map](https://openchargemap.org) across all supported countries\n- **Detour calculation** — Each station shows estimated detour time from your route\n- **\"Cheapest within N min\"** — Slider filters stations by maximum detour, highlights the best deal\n- **Corridor station list** — Sorted by position along route, with price deltas vs average\n- **Price color scale** — Green (cheap) to red (expensive) based on P5/P95 percentiles\n- **Station clustering** — GPU-accelerated clustering at low zoom levels\n- **16 languages** — ES, EN, FR, DE, IT, PT, PL, CS, HU, BG, SK, DA, SV, NO, SR, FI\n- **Multi-currency** — EUR, GBP, CHF, RON, DKK, SEK, NOK, PLN, CZK, HUF, BGN, RSD, TRY, ARS, MXN, AUD\n- **Geolocation** — Auto-centers on your location with one tap\n- **Privacy-first** — No cookies, no analytics, no personal data collection\n\n## Data Sources\n\n### Fuel prices\n\n| Country | Source | Type | Update |\n|---|---|---|---|\n| Spain | MITECO | Government API | Every 12h |\n| France | prix-carburants.gouv.fr | Government API | Hourly |\n| Germany | Tankerkoenig (MTS-K) | Government API | Hourly |\n| Italy | MIMIT | Government CSV | Every 12h |\n| Austria | E-Control | Government API | Every 2h |\n| UK | CMA Open Data | Government feeds | Every 4h |\n| Portugal | DGEG | Government API | Every 12h |\n| Slovenia | goriva.si | Government API | Every 6h |\n| Netherlands | ANWB | Commercial API | Every 6h |\n| Belgium | ANWB | Commercial API | Every 6h |\n| Luxembourg | ANWB | Commercial API | Every 12h |\n| Romania | Peco Online | Community | Every 12h |\n| Greece | FuelGR | Community API | Every 12h |\n| Ireland | Pick A Pump | Community API | Every 12h |\n| Croatia | MZOE | Government API | Every 12h |\n| Denmark | FuelPrices.dk | Commercial API | Every 6h |\n| Norway | DrivstoffAppen | Government-mandated | Every 6h |\n| Sweden | Drivstoffappen | Community | Every 12h |\n| Serbia | NIS / cenagoriva | Brand-level | Every 12h |\n| Finland | polttoaine.net | Community | Every 12h |\n| Switzerland, Poland, Czech Republic, Hungary, Bulgaria, Slovakia, Estonia, Latvia, Lithuania, Bosnia, North Macedonia | [Fuelo.net](https://fuelo.net) | Community | Every 12h |\n| Turkey | [Fuelo.net](https://fuelo.net) | Community | Every 12h |\n| Moldova | ANRE | Government | Every 12h |\n| Australia (WA + NSW) | FuelWatch / FuelCheck | Government API | Every 12h |\n| Argentina | Secretaria de Energia | Government API | Every 12h |\n| Mexico | CRE | Government API | Every 12h |\n\n### EV charging stations\n\n| Source | Coverage | License |\n|---|---|---|\n| [Open Charge Map](https://openchargemap.org) | All supported countries | ODbL |\n\n### Map \u0026 routing\n\n| Service | Purpose | License |\n|---|---|---|\n| [OpenStreetMap](https://www.openstreetmap.org) via [OpenFreeMap](https://openfreemap.org) | Map tiles | ODbL |\n| [Valhalla](https://github.com/valhalla/valhalla) | Route calculation | MIT |\n| [Photon](https://github.com/komoot/photon) (Komoot/OSM) | Geocoding / address search | Apache 2.0 |\n\n## Self-Hosting\n\nPumperly is designed to be self-hosted. The full stack runs as four Docker containers.\n\n### Architecture\n\n```\n┌─────────────────────────────────────────────────────────┐\n│  docker compose up -d                                   │\n│                                                         │\n│   ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌────────┐  │\n│   │   App    │  │ PostGIS  │  │ Valhalla │  │ Photon │  │\n│   │ Next.js  │  │  17-3.4  │  │  3.5.1   │  │  1.0.1 │  │\n│   │  :3000   │  │  :5432   │  │  :8002   │  │ :2322  │  │\n│   └──────────┘  └──────────┘  └──────────┘  └────────┘  │\n│         ▲             ▲             ▲            ▲      │\n│         └─────────────┴─────────────┴────────────┘      │\n│                    internal network                     │\n└─────────────────────────────────────────────────────────┘\n```\n\n### Requirements\n\n| Resource | First-time build | Steady state |\n|---|---|---|\n| **RAM** | ~24 GB (Valhalla tile build peaks at ~15 GB) | 6-8 GB |\n| **Disk** | ~300 GB (Photon imports + Valhalla tiles) | ~100 GB |\n| **CPU** | Multi-core recommended for tile building | Any |\n\n### Quick Start\n\n```bash\ngit clone https://github.com/GeiserX/pumperly.git\ncd pumperly\ncp .env.example .env\n# Edit .env — see \"Configuration\" below\ndocker compose -f docker/docker-compose.yml up -d\n```\n\nOpen `http://localhost:3000` once all services are healthy. Station data will begin populating automatically.\n\n### Helm Chart (Kubernetes)\n\nA Helm chart is also available for Kubernetes deployments. See the [chart documentation](charts/pumperly/README.md) for the full values reference.\n\n```bash\nhelm repo add pumperly https://geiserx.github.io/Pumperly\nhelm install pumperly pumperly/pumperly\n```\n\n### What Happens on First Start\n\nEach service has a one-time initialization step. Subsequent starts are fast.\n\n| Service | First start | Time | Subsequent starts |\n|---|---|---|---|\n| **PostGIS** | Creates database + extensions | Instant | Ready immediately |\n| **App** | Runs Prisma migrations, starts scraping stations | ~1 min | Ready immediately |\n| **Valhalla** | Downloads OSM PBF extracts + builds routing tiles | 3-6 hours | Loads pre-built tiles (~2 GB RAM) |\n| **Photon** | Downloads Photon JAR + country geocoding dumps, imports them | 20+ hours | Starts with existing index (~3 GB RAM) |\n\n\u003e **Tip**: Photon imports countries sequentially. The first country (Spain by default) is imported before the server starts, so geocoding works within ~30 minutes. Remaining countries are imported in the background while the server runs.\n\n### Valhalla Setup (Routing)\n\nValhalla builds routing graph tiles from OpenStreetMap PBF extracts. The docker-compose uses [gis-ops/docker-valhalla](https://github.com/gis-ops/docker-valhalla) which handles everything automatically.\n\n**How it works:**\n1. On first start, Valhalla downloads the PBF file(s) specified in `tile_urls`\n2. It merges multiple PBFs using osmium-tool (if more than one)\n3. It builds routing tiles, admin data, and timezone data\n4. Tiles are persisted in the volume — subsequent starts skip the build\n\n**Customizing countries:**\n- The `tile_urls` environment variable accepts a comma-separated list of PBF URLs from [Geofabrik](https://download.geofabrik.de/)\n- Example for just Spain + France:\n  ```\n  tile_urls=https://download.geofabrik.de/europe/spain-latest.osm.pbf,https://download.geofabrik.de/europe/france-latest.osm.pbf\n  ```\n- For all of Europe: `tile_urls=https://download.geofabrik.de/europe-latest.osm.pbf` (requires ~50 GB RAM for tile build)\n- After changing `tile_urls`, delete the valhalla volume to trigger a rebuild\n\n**Resource usage:**\n- Tile build: ~15-24 GB RAM (proportional to PBF size), 3-6 hours for 15 countries\n- Runtime: ~2 GB RAM, sub-second route calculations\n\n### Photon Setup (Geocoding)\n\nPhoton provides address autocomplete and geocoding, built on OpenStreetMap data via [Komoot](https://github.com/komoot/photon).\n\n**How it works:**\n1. On first start, the entrypoint script downloads the Photon 1.0.1 JAR\n2. It downloads per-country geocoding dumps from [Graphhopper](https://download1.graphhopper.com/public/europe/)\n3. It imports the first country (configurable), then starts the server\n4. Remaining countries are imported in the background while serving requests\n5. Data is persisted in the volume — subsequent starts skip the import\n\n**Customizing countries:**\n- Edit the `COUNTRIES` variable in the Photon entrypoint to match your enabled countries\n- Available dumps: see [download1.graphhopper.com/public/europe](https://download1.graphhopper.com/public/europe/)\n- The `LANGS` variable controls which languages are indexed (affects search quality and disk usage)\n\n**Resource usage:**\n- Import: ~3-8 GB RAM per country import batch, 20+ hours for 30 countries\n- Runtime: ~3 GB RAM, sub-100ms geocoding queries\n- Disk: ~250 GB for 30 European countries (OpenSearch index)\n\n### Docker Compose Services\n\nThe provided `docker/docker-compose.yml` includes a minimal setup (PostGIS only). For a full production deployment, use this complete configuration:\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eFull production docker-compose.yml\u003c/strong\u003e\u003c/summary\u003e\n\n```yaml\nservices:\n  db:\n    image: postgis/postgis:17-3.4\n    container_name: pumperly-db\n    restart: unless-stopped\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U pumperly\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n    environment:\n      TZ: Europe/Madrid          # Your timezone\n      POSTGRES_DB: pumperly\n      POSTGRES_USER: pumperly\n      POSTGRES_PASSWORD: changeme # CHANGE THIS\n    volumes:\n      - pumperly-pgdata:/var/lib/postgresql/data\n    deploy:\n      resources:\n        limits:\n          memory: 2G\n\n  valhalla:\n    image: ghcr.io/gis-ops/docker-valhalla/valhalla:3.5.1\n    container_name: pumperly-valhalla\n    restart: unless-stopped\n    environment:\n      TZ: Europe/Madrid\n      use_tiles_ignore_pbf: \"False\"\n      serve_tiles: \"True\"\n      build_elevation: \"False\"\n      build_admins: \"True\"\n      build_time_zones: \"True\"\n      build_transit: \"False\"\n      server_threads: \"4\"        # Adjust to your CPU count\n      # Comma-separated PBF URLs from https://download.geofabrik.de/\n      # Add/remove countries as needed:\n      tile_urls: \u003e-\n        https://download.geofabrik.de/europe/spain-latest.osm.pbf,\n        https://download.geofabrik.de/europe/france-latest.osm.pbf,\n        https://download.geofabrik.de/europe/portugal-latest.osm.pbf,\n        https://download.geofabrik.de/europe/italy-latest.osm.pbf,\n        https://download.geofabrik.de/europe/austria-latest.osm.pbf,\n        https://download.geofabrik.de/europe/germany-latest.osm.pbf,\n        https://download.geofabrik.de/europe/great-britain-latest.osm.pbf,\n        https://download.geofabrik.de/europe/slovenia-latest.osm.pbf,\n        https://download.geofabrik.de/europe/netherlands-latest.osm.pbf,\n        https://download.geofabrik.de/europe/belgium-latest.osm.pbf,\n        https://download.geofabrik.de/europe/luxembourg-latest.osm.pbf,\n        https://download.geofabrik.de/europe/romania-latest.osm.pbf,\n        https://download.geofabrik.de/europe/greece-latest.osm.pbf,\n        https://download.geofabrik.de/europe/ireland-and-northern-ireland-latest.osm.pbf,\n        https://download.geofabrik.de/europe/croatia-latest.osm.pbf,\n        https://download.geofabrik.de/europe/switzerland-latest.osm.pbf,\n        https://download.geofabrik.de/europe/poland-latest.osm.pbf,\n        https://download.geofabrik.de/europe/czech-republic-latest.osm.pbf,\n        https://download.geofabrik.de/europe/hungary-latest.osm.pbf,\n        https://download.geofabrik.de/europe/bulgaria-latest.osm.pbf,\n        https://download.geofabrik.de/europe/slovakia-latest.osm.pbf,\n        https://download.geofabrik.de/europe/denmark-latest.osm.pbf,\n        https://download.geofabrik.de/europe/sweden-latest.osm.pbf,\n        https://download.geofabrik.de/europe/norway-latest.osm.pbf,\n        https://download.geofabrik.de/europe/serbia-latest.osm.pbf,\n        https://download.geofabrik.de/europe/finland-latest.osm.pbf,\n        https://download.geofabrik.de/europe/estonia-latest.osm.pbf,\n        https://download.geofabrik.de/europe/latvia-latest.osm.pbf,\n        https://download.geofabrik.de/europe/lithuania-latest.osm.pbf,\n        https://download.geofabrik.de/europe/bosnia-herzegovina-latest.osm.pbf,\n        https://download.geofabrik.de/europe/macedonia-latest.osm.pbf\n    volumes:\n      - pumperly-valhalla:/custom_files\n    deploy:\n      resources:\n        limits:\n          memory: 24G   # 24 GB for tile build, ~2 GB at runtime\n        reservations:\n          memory: 4G\n\n  photon:\n    image: eclipse-temurin:21-jre\n    container_name: pumperly-photon\n    restart: unless-stopped\n    working_dir: /photon\n    entrypoint: [\"/bin/bash\", \"-c\"]\n    command:\n      - |\n        set -e\n        LANGS=\"es,en,fr,de,it,pt,sl,nl,ro,el,ga,hr,pl,cs,hu,bg,sk,da,sv,no,sr,fi\"\n        BASE=\"https://download1.graphhopper.com/public/europe\"\n        if [ ! -f /photon/photon.jar ]; then\n          echo \"Downloading Photon 1.0.1 JAR...\"\n          apt-get update -qq \u0026\u0026 apt-get install -y -qq --no-install-recommends wget zstd \u003e/dev/null 2\u003e\u00261\n          wget -q \"https://github.com/komoot/photon/releases/download/1.0.1/photon-1.0.1.jar\" -O /photon/photon.jar\n        fi\n        # Phase 1: Import first country so search works quickly\n        if [ ! -f /photon/.imported_spain ]; then\n          apt-get update -qq 2\u003e/dev/null; apt-get install -y -qq --no-install-recommends wget zstd \u003e/dev/null 2\u003e\u00261\n          echo \"Downloading Spain dump...\"\n          wget -q -O /photon/spain.jsonl.zst \"$BASE/spain/photon-dump-spain-1.0-latest.jsonl.zst\"\n          zstd -dc /photon/spain.jsonl.zst \u003e /photon/spain.jsonl\n          rm -f /photon/spain.jsonl.zst\n          echo \"Importing Spain...\"\n          java -Xmx3g -jar /photon/photon.jar import -import-file /photon/spain.jsonl -languages $LANGS\n          rm -f /photon/spain.jsonl\n          touch /photon/.imported_spain\n          echo \"Spain import done.\"\n        fi\n        # Phase 2: Import remaining countries in background after server starts\n        if [ ! -f /photon/.import_done ]; then\n          apt-get update -qq 2\u003e/dev/null; apt-get install -y -qq --no-install-recommends wget zstd \u003e/dev/null 2\u003e\u00261\n          (\n            sleep 5\n            # Add/remove countries to match your PUMPERLY_ENABLED_COUNTRIES:\n            COUNTRIES=\"france-monacco portugal italy austria germany british-islands slovenia netherlands belgium luxemburg romania greece ireland croatia switzerland poland czech-republic hungary bulgaria slovakia denmark sweden norway serbia finland estonia latvia lithuania bosnia-herzegovina macedonia\"\n            for country in $COUNTRIES; do\n              if [ -f /photon/.imported_$country ]; then continue; fi\n              echo \"[bg] Downloading $country...\"\n              wget -q -O \"/photon/$country.jsonl.zst\" \"$BASE/$country/photon-dump-$country-1.0-latest.jsonl.zst\"\n              zstd -dc \"/photon/$country.jsonl.zst\" \u003e \"/photon/$country.jsonl\"\n              rm -f \"/photon/$country.jsonl.zst\"\n              echo \"[bg] Importing $country...\"\n              java -Xmx3g -jar /photon/photon.jar import -import-file \"/photon/$country.jsonl\" -languages $LANGS\n              rm -f \"/photon/$country.jsonl\"\n              touch \"/photon/.imported_$country\"\n              echo \"[bg] $country done.\"\n            done\n            touch /photon/.import_done\n            echo \"[bg] All countries imported.\"\n          ) \u0026\n        fi\n        exec java -jar /photon/photon.jar serve -languages $LANGS -listen-ip 0.0.0.0 -cors-any\n    volumes:\n      - pumperly-photon:/photon\n    deploy:\n      resources:\n        limits:\n          memory: 8G\n        reservations:\n          memory: 2G\n\n  app:\n    image: drumsergio/pumperly:latest\n    container_name: pumperly\n    restart: unless-stopped\n    depends_on:\n      db:\n        condition: service_healthy\n    environment:\n      TZ: Europe/Madrid\n      DATABASE_URL: postgresql://pumperly:changeme@pumperly-db:5432/pumperly\n      PUMPERLY_DEFAULT_COUNTRY: ES\n      PUMPERLY_ENABLED_COUNTRIES: ES,FR,PT,IT,AT,DE,GB,SI,NL,BE,LU,RO,GR,IE,HR,CH,PL,CZ,HU,BG,SK,DK,SE,NO,RS,FI,EE,LV,LT,BA,MK\n      VALHALLA_URL: http://pumperly-valhalla:8002\n      PHOTON_URL: http://pumperly-photon:2322\n      PUMPERLY_CLUSTER_STATIONS: \"true\"\n      PUMPERLY_PRICE_MIN: \"0.30\"\n      PUMPERLY_PRICE_MAX: \"4.00\"\n      # API keys — get your own:\n      # TANKERKOENIG_API_KEY: \"\"      # https://creativecommons.tankerkoenig.de\n      # PUMPERLY_OCM_API_KEY: \"\"      # https://openchargemap.org (free, for EV data)\n      # FUELPRICES_DK_API_KEY: \"\"     # Denmark fuel prices\n    ports:\n      - \"3000:3000\"\n    deploy:\n      resources:\n        limits:\n          memory: 512M\n\nvolumes:\n  pumperly-pgdata:\n  pumperly-valhalla:\n  pumperly-photon:\n```\n\n\u003c/details\u003e\n\n### Configuration\n\n| Variable | Description | Default |\n|---|---|---|\n| `DATABASE_URL` | PostGIS connection string | **Required** |\n| `PUMPERLY_DEFAULT_COUNTRY` | ISO code for initial map view | `ES` |\n| `PUMPERLY_ENABLED_COUNTRIES` | Comma-separated ISO codes to enable | All |\n| `PUMPERLY_DEFAULT_FUEL` | Override default fuel type | Per-country |\n| `PUMPERLY_CLUSTER_STATIONS` | Enable map marker clustering | `true` |\n| `PUMPERLY_PRICE_MIN` / `PUMPERLY_PRICE_MAX` | Price bounds for scraper validation (EUR/L) | `0.30` / `4.00` |\n| `PUMPERLY_SCRAPE_INTERVAL_HOURS` | Global scrape interval override (hours, 0=disable) | Per-country |\n| `PUMPERLY_EV_ENABLED` | Enable EV charger scraping (`0` to disable) | `1` |\n| `VALHALLA_URL` | Valhalla routing endpoint | — |\n| `PHOTON_URL` | Photon geocoding endpoint | — |\n\n### API Keys\n\nSome data sources require API keys (all free):\n\n| Key | Source | How to get it |\n|---|---|---|\n| `TANKERKOENIG_API_KEY` | Germany fuel prices | Register at [creativecommons.tankerkoenig.de](https://creativecommons.tankerkoenig.de) |\n| `PUMPERLY_OCM_API_KEY` | EV charging stations | Register at [openchargemap.org](https://openchargemap.org), go to My Profile \u003e My API Keys |\n| `FUELPRICES_DK_API_KEY` | Denmark fuel prices | Contact [fuelprices.dk](https://fuelprices.dk) |\n\nMost countries work without any API key — they use open government data.\n\n### Supported Countries\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eAll 36 supported countries\u003c/strong\u003e\u003c/summary\u003e\n\n**Europe (31):** ES (Spain), FR (France), DE (Germany), IT (Italy), GB (United Kingdom), AT (Austria), PT (Portugal), SI (Slovenia), NL (Netherlands), BE (Belgium), LU (Luxembourg), RO (Romania), GR (Greece), IE (Ireland), HR (Croatia), CH (Switzerland), PL (Poland), CZ (Czech Republic), HU (Hungary), BG (Bulgaria), SK (Slovakia), DK (Denmark), SE (Sweden), NO (Norway), RS (Serbia), FI (Finland), EE (Estonia), LV (Latvia), LT (Lithuania), BA (Bosnia and Herzegovina), MK (North Macedonia)\n\n**Other regions (5):** TR (Turkey), MD (Moldova), AU (Australia), AR (Argentina), MX (Mexico)\n\n\u003c/details\u003e\n\n### Running Without Valhalla/Photon\n\nValhalla and Photon are optional. Without them:\n- Route planning and geocoding are disabled\n- The map still shows all stations with prices\n- All scraping works normally\n\nJust omit `VALHALLA_URL` and `PHOTON_URL` from your environment.\n\n## Development\n\n```bash\ngit clone https://github.com/GeiserX/pumperly.git\ncd pumperly\nnpm install\ncp .env.example .env\n# Start PostGIS:\ndocker compose -f docker/docker-compose.yml up -d\n# Generate Prisma client + push schema:\nnpx prisma generate \u0026\u0026 npx prisma db push\n# Seed data for one country:\nnpm run scraper:run -- --country=ES\n# Start dev server:\nnpm run dev\n```\n\nOpen `http://localhost:3000`.\n\n### Available Scripts\n\n| Script | Description |\n|---|---|\n| `npm run dev` | Start Next.js dev server |\n| `npm run build` | Production build |\n| `npm run start` | Start production server |\n| `npm run lint` | Run ESLint |\n| `npm run scraper:run -- --country=XX` | Run scraper for a country (or `--country=all`) |\n\n### Tech Stack\n\n| Layer | Technology |\n|---|---|\n| Frontend | [Next.js](https://nextjs.org) 16, [React](https://react.dev) 19, [MapLibre GL JS](https://maplibre.org), [Tailwind CSS](https://tailwindcss.com) |\n| Backend | Next.js API routes, [Prisma](https://prisma.io) ORM |\n| Database | [PostGIS](https://postgis.net) 17 (PostgreSQL + spatial) |\n| Routing | [Valhalla](https://github.com/valhalla/valhalla) 3.5.1 |\n| Geocoding | [Photon](https://github.com/komoot/photon) 1.0.1 |\n| Map tiles | [OpenFreeMap](https://openfreemap.org) (OpenStreetMap) |\n| Deployment | Docker, GitHub Actions CI/CD |\n\n## Roadmap\n\nSee [ROADMAP.md](ROADMAP.md) for the full development plan.\n\n## Ecosystem\n\n| Project | Type | Description |\n|---------|------|-------------|\n| [pumperly-mcp](https://github.com/GeiserX/pumperly-mcp) | MCP Server | Query fuel and EV prices from AI assistants via the Model Context Protocol |\n| [pumperly-ha](https://github.com/GeiserX/pumperly-ha) | Home Assistant Integration | Fuel and EV charging price sensors for your smart home dashboard |\n| [n8n-nodes-pumperly](https://github.com/GeiserX/n8n-nodes-pumperly) | n8n Community Node | Automate fuel price workflows in n8n |\n\n## Contributing\n\nContributions are welcome. Please open an issue first to discuss what you'd like to change.\n\n## License\n\n[GPL-3.0](LICENSE) — free to use, modify, and distribute. If you distribute a modified version, you must also release the source code under GPL-3.0.\n\n---\n\n\u003cp align=\"center\"\u003e\n  Made by \u003ca href=\"https://github.com/GeiserX\"\u003eSergio Fernandez\u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeiserx%2Fpumperly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgeiserx%2Fpumperly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeiserx%2Fpumperly/lists"}