A full-stack geospatial web application for visualizing public electric-vehicle charging infrastructure across Germany.
The project combines a responsive OpenLayers frontend with GeoServer, PostgreSQL/PostGIS and Docker. Charging-station data from the German Federal Network Agency is imported into PostGIS, published through OGC services and rendered as an interactive map with server-side filtering.
The application demonstrates a complete geospatial data pipeline:
Bundesnetzagentur CSV
↓
PostgreSQL + PostGIS
↓
GeoServer (WMS / WFS / GetFeatureInfo)
↓
OpenLayers web application
The prepared dataset contains more than 100,000 charging-station records with valid point geometries in EPSG:4326.
- OpenStreetMap basemap
- GeoServer WMS charging-station layer
- AC and DC charging filters using
CQL_FILTER - Scale-dependent station rendering
- Station details through
GetFeatureInfo - Desktop hover tooltip
- Map reset and browser geolocation actions
- Live GeoServer connection status
- Full-screen dark geospatial dashboard
- Desktop control panel
- Mobile filter drawer
- Accessible keyboard navigation and focus states
- Reduced-motion support
- Non-blocking status and error messages
- PostgreSQL/PostGIS spatial storage
- GeoServer WMS and WFS publication
- Reproducible CSV import
- Automated GeoServer workspace, datastore, layer and style setup
- Safe and idempotent PowerShell setup scripts
- Validation for WMS, WFS, CQL filtering and
GetFeatureInfo
The GeoServer layer uses a scale-dependent SLD style:
- AC stations: blue circular markers
- DC stations: orange circular markers with slightly larger symbols
- Marker sizes increase from regional to local map scales
- Semi-transparent fills and thin dark outlines preserve readability in dense areas
The style is stored at:
geoserver/styles/ev-charging-points.sld
The local setup process installs or updates the workspace style ev:ev-charging-points and assigns it to ev:ladepunkte automatically.
- PostgreSQL
- PostGIS
- GeoServer
- OGC WMS
- OGC WFS
- CQL filters
- Docker Compose
- OpenLayers
- Vanilla JavaScript
- Vite
- HTML5
- CSS3
- OpenStreetMap
- PowerShell
- SQL
- Python
- CSV processing
The application uses public charging-infrastructure data from the Bundesnetzagentur Ladesäulenregister.
The repository includes the prepared file:
bnetza_min.csv
The larger raw export is intentionally not included. prepare_bnetza.py documents the preprocessing workflow used to create the reduced dataset.
- Docker Desktop
- Docker Compose
- A current Node.js LTS release
- npm
- Windows PowerShell or PowerShell 7
From the repository root:
docker compose up -d.\scripts\setup-local.ps1The setup script:
- verifies that Docker is available,
- waits for PostGIS and GeoServer,
- creates the PostGIS schema when required,
- imports
bnetza_min.csvonly when no valid rows exist, - configures the GeoServer workspace and datastore,
- publishes
ev:ladepunkte, - installs the custom SLD style,
- validates WMS, WFS, CQL and
GetFeatureInfo.
The script is safe to run repeatedly and does not duplicate imported data or GeoServer resources.
To intentionally rebuild the application table from the prepared CSV:
.\scripts\setup-local.ps1 -ResetDataThis option affects only the application table. It does not remove the database or Docker volumes.
cd web
npm install
npm run devOpen:
http://localhost:5173
GeoServer is available at:
http://127.0.0.1:8080/geoserver
The postgis_data and geoserver_data named volumes are machine-local. Copying the repository to another computer does not copy the database contents or GeoServer configuration.
Running scripts/setup-local.ps1 restores the required local resources from the files stored in the repository.
GeoServer connects to PostgreSQL through the Docker service name:
postgis
Using localhost or 127.0.0.1 inside the GeoServer container would point back to the GeoServer container itself.
The frontend forwards /geoserver requests to:
http://127.0.0.1:8080
The IPv4 address is used deliberately because localhost may resolve to IPv6 ::1 on Windows.
The frontend applies server-side CQL filters to the WMS layer:
AC only: anschlussart='AC'
DC only: anschlussart='DC'
AC and DC: anschlussart='AC' OR anschlussart='DC'
None: 1=0
For performance, AC stations are hidden below zoom level 9. The user's AC preference is preserved and restored when returning to a supported zoom level.
ev-charging-map/
├── docker-compose.yml
├── bnetza_min.csv
├── prepare_bnetza.py
├── geoserver/
│ └── styles/
│ └── ev-charging-points.sld
├── scripts/
│ ├── setup-local.ps1
│ ├── import-bnetza.ps1
│ ├── configure-geoserver.ps1
│ ├── configure-geoserver-style.ps1
│ ├── validate-local.ps1
│ └── sql/
│ ├── create-ladepunkte.sql
│ └── import-bnetza.sql
├── web/
│ ├── public/
│ ├── src/
│ ├── index.html
│ ├── package.json
│ ├── package-lock.json
│ └── vite.config.js
├── .gitignore
└── README.md
Check service status:
docker compose psInspect recent logs:
docker compose logs --tail=100 postgis
docker compose logs --tail=100 geoserverBuild the frontend:
cd web
npm run buildThe credentials in docker-compose.yml are intended only for local demonstration and development. They must not be reused in a production environment.
This application was developed as an academic geospatial-processing project and later extended into a reproducible, portfolio-ready WebGIS system.
It demonstrates:
- spatial database design,
- geospatial service publication,
- OGC web standards,
- responsive frontend engineering,
- automated environment configuration.
Developed by Ahmet Kislali.
No explicit open-source license has been assigned.
The repository is published for portfolio and educational presentation purposes.