Mehrtägige Rennrad- und Radreisen strukturiert planen – mit Basecamps, Sterntouren, Unterkünften, Transfers und automatisch erzeugter Reiseroute.
VeloHub ist keine klassische Trainings-, Tracking- oder reine Routenplanungs-App. Die zentrale Idee der Anwendung ist es, komplette mehrtägige Radreisen strukturiert planbar zu machen – insbesondere Reisen, bei denen man an mehreren Standorten übernachtet, von dort aus Sterntouren fährt und zwischendurch Transfers organisiert.
Viele bestehende Tools konzentrieren sich entweder auf:
- die Planung einer einzelnen Route
- das Aufzeichnen und Auswerten sportlicher Aktivitäten
VeloHub setzt an einer anderen Stelle an: Die App betrachtet nicht nur die einzelne Ausfahrt, sondern die gesamte Reise als zusammenhängendes Planungskonstrukt.
-
Basecamp-orientierte Planung statt rein routenorientierter Planung
Touren werden nicht isoliert betrachtet, sondern einem konkreten Aufenthaltsort zugeordnet. -
Unterstützung von Sterntouren
Mehrere Ausfahrten können rund um denselben Standort geplant und logisch gruppiert werden. -
Reiseplanung statt nur Streckenplanung
Unterkünfte, Transfers, Ruhetage und Tagesrouten sind Teil desselben Modells. -
Ganzheitlicher Überblick über die Reise
Statistiken, Itinerary und Kartenansicht helfen dabei, nicht nur einzelne Touren, sondern die gesamte Struktur der Reise zu erfassen. -
Integration von GPX-Daten in einen größeren Planungskontext
Importierte Routen stehen nicht für sich allein, sondern werden in die Gesamtplanung eingebettet.
Kurz gesagt: VeloHub verbindet Routenplanung, Reiseorganisation und visuelle Strukturierung in einer Anwendung.
- Öffentliches Frontend: velo-hub.app
- Repository: XDMINT/VeloHub
Das Frontend ist öffentlich deployt. Das Backend wird containerisiert ausgeliefert und über einen GitHub-Workflow via Docker Hub auf einen VPS ausgerollt.
- Reisen anlegen und verwalten
- Basecamps mit Aufenthaltszeitraum definieren
- Unterkünfte je Basecamp hinterlegen
- Radrouten je Basecamp planen
- GPX-Dateien importieren
- Höhenprofile abrufen und visualisieren
- Transfers zwischen Standorten verwalten
- Transferdaten durch das Backend neu berechnen lassen
- Ruhetage pflegen und sortieren
- Ein Itinerary für die gesamte Reise erzeugen
- Aggregierte Trip- und Basecamp-Statistiken anzeigen
- Orte über MapTiler bzw. Nominatim suchen
- Reisedaten auf einer interaktiven Karte darstellen
- React 19
- TypeScript
- Vite
- Tailwind CSS 4
- TanStack React Query für Server-State
- Zustand für lokalen UI-/App-State
- Axios für die Kommunikation mit dem Backend
- MapLibre GL / react-map-gl für Karten
- Recharts für Diagramme
- Radix UI für UI-Primitives
- dnd-kit für Reordering per Drag & Drop
Das Frontend bezieht seine API-Basis über VITE_API_URL oder VITE_API_BASE_URL und fällt andernfalls auf /api zurück.
- Kotlin
- Spring Boot
- Spring Web
- Spring Data JPA
- Spring Validation
- springdoc OpenAPI / Swagger UI
- Hibernate Spatial
- JTS / PostGIS-Unterstützung
- Jackson XML für GPX-nahe Verarbeitung
Das Backend ist in klassische Schichten unterteilt, unter anderem controller, service, repository, dto, entity, mapper, config und exception.
- PostgreSQL 16
- PostGIS 3.4
Für lokale Setups wird eine PostGIS-fähige PostgreSQL-Instanz über Docker Compose bereitgestellt.
VeloHub folgt einer getrennten Frontend-Backend-Architektur:
[ Browser / Nutzer ]
↓
[ React + Vite Frontend ]
↓ HTTP / JSON
[ Spring Boot Backend ]
↓
[ PostgreSQL + PostGIS ]
Ergänzend dazu werden externe Dienste eingebunden:
Frontend
├─ Karten / Geocoding
│ ├─ MapTiler (bevorzugt bei vorhandenem API-Key)
│ └─ Nominatim als Fallback
│
Backend
└─ Routing-Dienst über VELOHUB_ROUTING_API_KEY
Die Aufgabentrennung ist dabei klar:
- Das Frontend übernimmt Interaktion, Visualisierung, Kartenansicht und State-Handling.
- Das Backend übernimmt Persistenz, Validierung, Aggregation, Ableitungen und fachliche Logik.
- Die Datenbank speichert strukturierte Reisedaten sowie räumliche Informationen.
VeloHub/
├── .github/workflows/
│ └── deploy-backend.yml
├── client/
│ ├── public/
│ ├── src/
│ │ ├── api/
│ │ ├── components/
│ │ ├── hooks/
│ │ ├── lib/
│ │ ├── stores/
│ │ ├── types/
│ │ ├── App.tsx
│ │ └── main.tsx
│ ├── Dockerfile
│ └── nginx.conf
├── server/
│ ├── src/main/kotlin/privat/velohub/
│ │ ├── config/
│ │ ├── controller/
│ │ ├── dto/
│ │ ├── entity/
│ │ ├── exception/
│ │ ├── mapper/
│ │ ├── repository/
│ │ ├── service/
│ │ ├── util/
│ │ └── VeloHubApplication.kt
│ ├── Dockerfile
│ ├── build.gradle.kts
│ └── gradlew
├── API_DOCUMENTATION.md
└── docker-compose.yml
Das Frontend ist als moderne SPA aufgebaut und trennt klar zwischen:
- UI-Komponenten
- API-Modulen
- Server-State-Hooks
- lokalem App- und UI-State
Die gesamte Kommunikation mit dem Backend ist in client/src/api gekapselt. Dort gibt es separate Module für die fachlichen Bereiche, unter anderem:
trips.tsbasecamps.tsaccommodations.tscycling-routes.tstransfers.tsitinerary.tsgeocoding.ts
Dadurch bleibt die eigentliche UI von HTTP-Details weitgehend entkoppelt.
Für den Server-State wird TanStack React Query verwendet. Das ist besonders passend für VeloHub, weil viele Screens auf persistierten Backend-Ressourcen basieren, die:
- zwischengespeichert werden sollen
- nach Mutationen gezielt aktualisiert werden müssen
- auch bei temporären Verbindungsproblemen stabil bleiben sollen
UI-naher und nicht persistenter Zustand wird über Zustand organisiert, zum Beispiel in:
app-store.tsmap-store.tsui-store.ts
So bleibt die Trennung zwischen fachlichen Backend-Daten und lokalem UI-State sauber.
Die Kartenansicht basiert auf MapLibre. Wenn ein VITE_MAPTILER_KEY vorhanden ist, werden MapTiler-Dienste verwendet. Andernfalls greift das Frontend bei Geocoding-Anfragen auf Nominatim zurück.
Das Backend folgt einer klassischen Spring-Boot-Struktur mit fachlich getrennten Controllern und einer üblichen Schichtung aus API, Service, Persistenz und Mapping.
controller/– REST-Endpunkteservice/– fachliche Logikrepository/– Datenzugriffentity/– Datenbankmodelledto/– Request- und Response-Modellemapper/– Umwandlung zwischen Entity und DTOexception/– Fehlerbehandlungconfig/– Konfiguration, unter anderem für OpenAPI, CORS und Routing
Das Backend stellt dedizierte Controller für folgende Bereiche bereit:
TripControllerBaseCampControllerAccommodationControllerCyclingRouteControllerTransferControllerItineraryController
Diese Struktur spiegelt direkt das Domänenmodell der Anwendung wider.
Da VeloHub mit geografischen Informationen arbeitet, kommen im Backend unter anderem folgende Technologien zum Einsatz:
- Hibernate Spatial
- JTS Core
- PostGIS
- XML-Verarbeitung für GPX-nahe Daten
Das ist insbesondere relevant für:
- räumliche Datenpunkte
- Streckenverläufe
- GPX-Import
- routenbezogene Berechnungen
Ein zentraler Aspekt von VeloHub ist, dass die API-Struktur die fachliche Hierarchie der Reise abbildet.
/trips und /trips/{id} bilden die oberste Ebene.
Darüber werden typischerweise folgende Aktionen ausgeführt:
- alle Reisen laden
- einzelne Reise laden
- Reise anlegen
- Reise aktualisieren
- Reise löschen
- Gesamtstatistiken über
/trips/{id}/statsabrufen
Wann wird diese API aufgerufen?
- beim Laden einer Übersicht aller Reisen
- beim Öffnen einer konkreten Reise
- nach dem Anlegen, Umbenennen oder Löschen einer Reise
- wenn aggregierte Kennzahlen für die gesamte Reise dargestellt werden sollen
Basecamps sind unter einer Reise verschachtelt und liegen unter /trips/{tripId}/basecamps.
Zusätzlich existieren Endpunkte für:
- Statistiken
- Ruhetage
- Reordering von Ruhetagen
- Reordering der Basecamps
Wann wird diese API aufgerufen?
- wenn ein neuer Aufenthaltsort angelegt wird
- wenn Reihenfolge oder Zeitraum der Basecamps angepasst werden
- wenn Ruhetage hinzugefügt oder sortiert werden
- wenn basecampbezogene Kennzahlen benötigt werden
Unterkünfte sind an ein Basecamp gebunden und werden unter
/trips/{tripId}/basecamps/{baseCampId}/accommodation verwaltet.
Wann wird diese API aufgerufen?
- beim Anlegen oder Bearbeiten einer Unterkunft
- wenn Detaildaten zum Aufenthalt gepflegt werden
- wenn pro Basecamp eine konkrete Übernachtung hinterlegt werden soll
Radrouten sind ebenfalls einem Basecamp zugeordnet und liegen unter
/trips/{tripId}/basecamps/{baseCampId}/routes.
Dazu gehören unter anderem:
- CRUD-Operationen
- GPX-Upload
- Höhenprofil-Abruf
- Reordering der Routen
Wann wird diese API aufgerufen?
- beim Anlegen einer Tour
- beim Import einer GPX-Datei
- beim Anzeigen eines Höhenprofils
- wenn mehrere Touren innerhalb eines Basecamps sortiert werden
Transfers liegen unter /trips/{tripId}/transfers.
Zusätzlich gibt es eine Aktion zur Neuberechnung.
Wann wird diese API aufgerufen?
- wenn ein Wechsel zwischen zwei Aufenthaltsorten geplant wird
- wenn Transferdaten gepflegt oder angepasst werden
- wenn sich die Reiseplanung verändert und Transferdaten neu berechnet werden sollen
Das Itinerary wird über /trips/{tripId}/itinerary abgerufen.
Wann wird diese API aufgerufen?
- wenn aus den vorhandenen Planungsdaten eine chronologische Gesamtansicht erzeugt werden soll
- wenn die Reise als durchgehender Ablauf statt als Einzelobjekte betrachtet werden soll
VeloHub verwendet externe APIs gezielt als Ergänzung zur eigenen Fachlogik.
Wenn VITE_MAPTILER_KEY gesetzt ist, verwendet das Frontend MapTiler für:
- Kartenstile
- Geocoding
Das ist insbesondere relevant bei:
- der Kartenanzeige
- der Suche nach Orten beim Anlegen oder Bearbeiten von Reisedaten
Falls kein MapTiler-Key vorhanden ist, greift das Frontend für Geocoding auf Nominatim zurück.
Das erleichtert lokale Entwicklung und einfache Deployments ohne zwingende Drittanbieter-Konfiguration.
Das Backend nutzt einen Routing-bezogenen API-Key über VELOHUB_ROUTING_API_KEY.
Dadurch lassen sich routing- oder transferbezogene externe Dienste in die Backend-Logik einbinden, während Persistenz, Datenmodell und Orchestrierung in der Anwendung selbst verbleiben.
Für die detaillierte Beschreibung der Backend-Endpunkte ist bereits eine eigene Dokumentation im Repository vorhanden:
Laut vorhandener Dokumentation stehen lokal außerdem zur Verfügung:
- Base URL:
http://localhost:8080 - Swagger UI:
http://localhost:8080/swagger-ui.html - OpenAPI JSON:
http://localhost:8080/api-docs
Diese README dient vor allem als Produkt-, Architektur- und Betriebsübersicht, während API_DOCUMENTATION.md die ausführlichere API-Referenz bildet.
Trip
├── BaseCamp[]
│ ├── Accommodation[]
│ ├── CyclingRoute[]
│ └── RestDay[]
├── Transfer[]
└── Itinerary / Statistics
Dieses Modell bildet die praktische Struktur einer mehrtägigen Radreise ab.
- Node.js (vorzugsweise aktuelle LTS-Version)
- Java 21 für das Backend
- Docker & Docker Compose
Die docker-compose.yml unterstützt verschiedene Betriebsmodi.
docker compose upDadurch werden standardmäßig gestartet:
dbauf Port5432appauf Port8080
docker compose up dbDas ist nützlich, wenn das Backend lokal per Gradle gestartet werden soll.
docker compose --profile full up --buildDamit wird zusätzlich das Frontend auf Port 3000 bereitgestellt.
cd server
./gradlew bootRuncd client
npm install
npm run devBeispielhafte Frontend-Konfiguration:
VITE_API_URL=http://localhost:8080
VITE_MAPTILER_KEY=your_maptiler_keyDas Frontend prüft VITE_API_URL, dann VITE_API_BASE_URL und fällt andernfalls auf /api zurück.
Im Compose-Setup werden unter anderem folgende Variablen verwendet:
SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/velohub
SPRING_DATASOURCE_USERNAME=velohub
SPRING_DATASOURCE_PASSWORD=velohub
VELOHUB_ROUTING_API_KEY=...
VELOHUB_CORS_ALLOWED_ORIGINS=http://localhost:5173,http://localhost:3000
JAVA_TOOL_OPTIONS=-Xms256m -Xmx512m -XX:+UseContainerSupportFür produktive Deployments sollten Secrets und API-Keys ausschließlich über die jeweilige Laufzeitumgebung bereitgestellt werden.
Das Frontend-Dockerfile verwendet einen Multi-Stage-Build:
- Build mit
node:22-alpine - Auslieferung über
nginx:1.27-alpine
Der Build unterstützt unter anderem VITE_MAPTILER_KEY als Build-Argument.
Auch das Backend wird per Multi-Stage-Build erzeugt:
- Build mit
eclipse-temurin:21-jdk-alpine - Laufzeit mit
eclipse-temurin:21-jre-alpine
Dabei wird:
- der Gradle Wrapper verwendet
- mit einem nicht-root Benutzer gearbeitet
- die Anwendung als
app.jarauf Port8080ausgeführt
Das Deployment ist in zwei klar getrennte Bereiche aufgeteilt:
- Frontend: Netlify
- Backend: GitHub Actions → Docker Hub → VPS
Diese Trennung erlaubt es, das statische Frontend unabhängig vom Backend auszuliefern und das Backend weiterhin vollständig containerisiert zu betreiben.
Der Workflow .github/workflows/deploy-backend.yml bildet die Backend-Auslieferung ab.
Der Ablauf ist im Wesentlichen:
- Trigger bei Änderungen im
server/-Bereich - Checkout des Repositories
- Setup von Java
- Build des Backends mit Gradle
- Login bei Docker Hub
- Build und Push des Backend-Images
- SSH-Verbindung zum VPS
- Aktualisierung des laufenden Containers per Docker Compose
Auf dem VPS wird dabei sinngemäß Folgendes ausgeführt:
cd ~/app
docker compose pull app
docker compose up -d appDamit ist GitHub Actions die Automatisierungsschicht, Docker Hub die Registry und der VPS die eigentliche Laufzeitumgebung des Backends.
Aktuell ist im Repository ein Workflow für das Backend-Deployment vorhanden.
Die technische Basis dafür umfasst bereits:
- automatisierten Build
- automatisierten Image-Build
- Push zur Registry
- automatisiertes Update auf dem VPS
Die derzeitige Projektstruktur konzentriert sich insbesondere auf:
- eine getrennte Frontend-Backend-Architektur
- eine domänenorientierte REST-Struktur
- Server-State-Handling über React Query
- dedizierte API-Module im Frontend
- räumliche Datenverarbeitung über PostGIS
- GPX-Import
- OpenAPI- und Swagger-Unterstützung
- containerisierte lokale und öffentliche Betriebsumgebungen
- automatisierte Backend-Auslieferung
Die bestehende Architektur lässt sich sinnvoll in folgende Richtungen weiterentwickeln.
- Benutzerkonten und Authentifizierung
- Teilen von Reisen mit Mitreisenden oder Trainingspartnern
- Kollaboratives Bearbeiten
- Exportfunktionen, z. B. PDF oder GPX-Bundles
- Wetterintegration pro Basecamp oder Tourtag
- Erweiterte Transferarten wie Bahn, Fähre oder ÖPNV
- Versionierte Image-Tags zusätzlich zu
latest - Staging-Umgebung
- Automatisierte Tests in CI/CD
- Health-Checks nach Deployments
- Erweiterte Observability und Monitoring
git clone https://github.com/XDMINT/VeloHub.git
cd VeloHubdocker compose up# Backend
cd server
./gradlew bootRun
# Frontend
cd ../client
npm install
npm run devIm Repository ist aktuell keine explizite Lizenzdatei im Root-Verzeichnis ersichtlich. Falls das Projekt als Open-Source-Projekt veröffentlicht werden soll, sollte eine passende Lizenz ergänzt werden.
VeloHub ist darauf ausgelegt, Radreisen nicht nur als Sammlung einzelner Strecken zu betrachten, sondern als strukturierten Gesamtablauf. Diese Ausrichtung zeigt sich im Datenmodell, in der REST-API, in der Frontend-Architektur und im Deployment-Setup.
Dadurch entsteht eine Anwendung, die Routenplanung, Reiseorganisation und visuelle Strukturierung in einem gemeinsamen Modell zusammenführt.