Files
Live_Navi/README.md
T
2026-09-01 13:12:52 +02:00

243 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ÖPNV Navi – Frontend
Vanilla-JS-Webapp für Live-Abfahrten, Routenplanung und eine Live-Karte im
VBB-Verbund (Berlin/Brandenburg) mit Anbindung an echte DB-Bahnhöfe. Kein
Build-Schritt, kein Framework – reines HTML/CSS/JS, läuft direkt als
statische Website.
## Tech-Stack
- Reines HTML5, CSS3, ES2020+ JavaScript (keine Frameworks, kein Bundler)
- [Leaflet](https://leafletjs.com/) für die Live-Karte (per CDN eingebunden)
- Google Fonts: IBM Plex Mono / Sans / Sans Condensed
- Service Worker für Web-Push-Benachrichtigungen
## Ordnerstruktur
```
frontend/
├── index.html Einzige HTML-Seite (Single Page App über Tabs)
├── styles.css Komplettes Stylesheet ("Solari-Anzeigetafel bei Nacht"-Theme)
├── sw.js Service Worker (Web-Push) - MUSS im Root liegen, nicht unter js/
├── manifest.json PWA-Manifest
└── js/
├── config.js Zentrale Konfiguration (API_BASE-URL des Backends)
├── api.js Schlanker fetch()-Wrapper für alle Backend-Endpunkte
├── i18n.js Mehrsprachigkeit (DE/EN), Wörterbuch + Sprachumschaltung
├── app.js Hauptlogik: Tabs, Suche, Abfahrtstafel, Favoriten, Routenplaner
├── splitflap.js Flip-Animation der Abfahrtstafel (+ Screenreader-Textalternative)
├── modefilter.js Wiederverwendbare Verkehrsmittel-Filter-Chips
├── livemap.js Live-Karte (Leaflet): Radar-Modus, Trip-Tracking, Isolations-Modus
├── tripmodal.js Fahrt-Detail-Modal (Zwischenhalte, Mini-Karte, Verspätungsstatistik)
├── tripalarm.js Fahrtalarm ("wecke mich X Stationen vorher")
└── push.js Web-Push: Service-Worker-Registrierung, Abo-Verwaltung
```
## Einrichtung / Deployment
Keine Installation nötig – es sind statische Dateien. Einfach den kompletten
Ordnerinhalt auf einen Webserver (nginx, Apache, Vercel, o.ä.) legen.
**Wichtig:**
- `sw.js` muss im **Root** des ausgelieferten Verzeichnisses liegen (dort, wo
auch `index.html` liegt), nicht unter `js/`. Der Geltungsbereich eines
Service Workers ist standardmäßig auf sein eigenes Verzeichnis und alles
darunter beschränkt.
- Web Push (und Service Worker generell) funktionieren nur über **HTTPS**
(oder `localhost` während der Entwicklung).
- In `js/config.js` die Backend-URL eintragen:
```js
window.APP_CONFIG = {
API_BASE: 'https://dein-server.example/live_navi',
};
```
## Features im Überblick
- **Abfahrten**: Live-Abfahrtstafel (VBB + echte DB-Bahnhöfe), Verkehrsmittel-Filter,
Gleiswechsel-Hinweis, Störungen & Aufzugsstatus direkt unter der Tafel
- **Route**: Routenplanung über eine selbst gehostete OTP2-Instanz, konfigurierbarer
Umstiegszeit-Puffer, rollstuhlgerechte Verbindungen, Route teilen (Link)
- **Karte**: Live-Fahrzeugpositionen, Fahrt isolieren/verfolgen, display-breite
Darstellung auf jeder Bildschirmgröße
- **Favoriten**: eigener Tab, Live-Vorschau der nächsten Abfahrt, Störungs-Badges
- **Fahrtalarm**: weckt X Stationen vor dem Ziel (Ton, Vibration, Vollbild-Overlay)
- **Push-Benachrichtigungen**: funktionieren auch bei geschlossenem Tab/Browser
(Service Worker + Web Push, siehe `js/push.js`)
- **Verlauf**: zuletzt gesuchte Haltestellen, direkt als Vorschläge im Suchfeld
- **Mehrsprachigkeit**: Deutsch/Englisch, automatische Browsersprache-Erkennung
- **Barrierefreiheit**: Tastaturbedienung überall (inkl. Suche), ARIA-Tab-Pattern,
Fokus-Fallen in Dialogen, Screenreader-Textalternative zur Flip-Animation,
`aria-live`-Regionen für Störungen/Ergebnisse
## Browser-Unterstützung
Moderne Evergreen-Browser (Chrome, Firefox, Safari, Edge). Nutzt u. a.
`fetch`, `IntersectionObserver`-freies Vanilla-DOM, Service Worker, Push API,
CSS Custom Properties und `dvh`-Einheiten (mit `vh`-Fallback). Kein IE11-Support.
## Bekannte Grenzen
- Die Live-Karte ist für blinde Nutzer naturgemäß eingeschränkt zugänglich
(Leaflet-Karten sind visuell) – Abfahrtstafel und Routenplaner liefern
dieselben Informationen barrierefrei.
- Störungstexte kommen direkt von VBB/HAFAS auf Deutsch – eine Übersetzung
ins Englische findet nicht statt (nur die App-Oberfläche selbst ist zweisprachig).
- Fahrtalarm-Ton und Vollbild-Overlay funktionieren nur bei offenem Tab; bei
geschlossenem Browser zeigt ein Push nur die Systembenachrichtigung.
# ÖPNV Navi – Backend
Node.js/Express-Backend für die ÖPNV-Navi-App: bündelt VBB-HAFAS,
DB-IRIS (echte Bahnhöfe), eine selbst gehostete OTP2-Instanz für die
Routenplanung sowie Web-Push-Benachrichtigungen hinter einer gemeinsamen API.
## Tech-Stack
- Node.js, Express
- [hafas-client](https://github.com/public-transport/hafas-client) (VBB-Profil)
- DB-IRIS (XML, via `fast-xml-parser`) für echte DB-Bahnhöfe
- OTP2 (GraphQL GTFS API) für die Routenplanung – **eigene, extern laufende
OTP2-Instanz vorausgesetzt**, wird hier nicht mitgeliefert
- `better-sqlite3` für Favoriten, Verspätungsstatistik und Web-Push-Subscriptions
- `web-push` für Browser-Push-Benachrichtigungen
- `helmet`, `cors`, `express-rate-limit`, `morgan`
## Einrichtung
```bash
npm install
```
### Umgebungsvariablen (`.env`)
| Variable | Pflicht | Beschreibung |
|---|---|---|
| `PORT` | nein | Port, auf dem der Server lauscht (Standard siehe `server.js`) |
| `HAFAS_USER_AGENT` | nein | User-Agent für HAFAS-Anfragen |
| `DB_PATH` | nein | Pfad zur SQLite-Datenbankdatei (Standard: `./data/oepnv-navi.sqlite`) |
| `VAPID_PUBLIC_KEY` | für Web-Push | Öffentlicher VAPID-Schlüssel |
| `VAPID_PRIVATE_KEY` | für Web-Push | **Geheim!** Privater VAPID-Schlüssel |
| `VAPID_SUBJECT` | für Web-Push | `mailto:deine@email.de` |
VAPID-Keys einmalig erzeugen:
```bash
npx web-push generate-vapid-keys
```
Ohne `VAPID_PUBLIC_KEY`/`VAPID_PRIVATE_KEY` bleibt Web-Push deaktiviert
(Warnung im Log beim Start), der Rest der App läuft normal weiter.
**Wichtig:** `VAPID_PRIVATE_KEY` ist ein echtes Geheimnis – nicht ins
Git-Repo committen, `.env` gehört in die `.gitignore`.
### Start
```bash
npm start # node src/server.js
npm run dev # mit --watch (Node 18+)
```
## Ordnerstruktur
```
backend/
├── package.json
└── src/
├── server.js Express-App, Middleware, Routen-Mounting, Hintergrund-Jobs
├── db/
│ └── database.js SQLite-Setup + Schema (Favoriten, Verspätungen, Push)
├── middleware/
│ └── apiKey.js X-API-Key-Schutz (nur für /push/register, APNs)
├── routes/
│ ├── locations.js / stations Haltestellen-/Adress-/POI-Suche
│ ├── departures.js VBB-Abfahrten (+ Störungen)
│ ├── dbTimetables.js DB-IRIS-Abfahrten für echte Bahnhöfe (+ Störungen)
│ ├── summary.js Sammel-Endpunkt für mehrere Haltestellen (Favoriten)
│ ├── trip.js Fahrt-Details (Zwischenhalte, Live-Position)
│ ├── otpJourneys.js Routenplanung über die eigene OTP2-Instanz
│ ├── journeys.js Ältere HAFAS-basierte Routenplanung (Legacy)
│ ├── radar.js Fahrzeugpositionen im Kartenausschnitt
│ ├── disruptions.js Ortsbezogene Störungen
│ ├── remarks.js Netzweite Störungsmeldungen
│ ├── fares.js VBB-Tarifzonen + BVG-Preise
│ ├── favorites.js Server-seitige Favoriten (Legacy/optional)
│ ├── delayStats.js Verspätungsstatistik pro Linie
│ ├── webPush.js Web-Push: Subscribe/Unsubscribe/Fahrtalarm
│ ├── push.js APNs-Registrierung für die separate iOS-App
│ └── health.js Health-Dashboard (/health/full, /health/dashboard)
└── utils/
├── hafas.js Zentraler HAFAS-Client
├── vbbDepartures.js VBB-Abfahrten-Kernlogik + Verspätungs-Aufzeichnung
├── dbIris.js / dbDepartureMerge.js / dbDeparturesService.js
│ DB-IRIS-Kernlogik (Planwerte + Echtzeit-Änderungen mergen)
├── dbStations.js ~5.400 echte DB-Bahnhöfe (dynamischer Import, ESM)
├── otpClient.js OTP2-GraphQL-Client (Routenplanung, Umstiegszeit, Rollstuhl)
├── disruptionFilter.js "Echte Störung" vs. Rauschen, Gleisänderungs-Anreicherung
├── delayStats.js Aggregation der Verspätungsstatistik
├── tripInfo.js Gemeinsame Fahrt-Detail-Logik (Route + Push-Job)
├── webPush.js web-push-Wrapper (VAPID, Versand, Fehlerbehandlung)
├── pushStore.js DB-Zugriff für Push-Subscriptions/Favoriten/Fahrtalarme
├── pushJobs.js Hintergrund-Jobs: Störungs-Check (60s) & Fahrtalarm-Check (20s)
├── lineColors.js Linienfarben (vbb-line-colors + Fallback-Heuristik)
├── products.js Verkehrsmittel-Filter-Mapping
├── vbbFareZones.js / bvgPriceScraper.js
│ Tarifzonen + Preise, täglich automatisch aktualisiert
├── cache.js Einfacher In-Memory-TTL-Cache
└── hafasErrors.js Nutzerfreundliche Fehlermeldungen für HAFAS-Fehler
```
## API-Endpunkte (Übersicht)
Alle Pfade relativ zum konfigurierten Basis-Pfad (z. B. `/live_navi`).
| Bereich | Endpunkte |
|---|---|
| Suche | `GET /locations`, `GET /stations` (Alias) |
| Abfahrten | `GET /departures/:stationId`, `GET /db/departures/:evaNo` |
| Sammel-Abfahrten | `POST /summary/departures` |
| Fahrt-Details | `GET /trip/:id` |
| Routenplanung | `GET /otp/journeys` (OTP2), `GET /journeys` (Legacy/HAFAS) |
| Live-Karte | `GET /radar` |
| Störungen | `GET /disruptions/nearby`, `GET /remarks` |
| Tarife | `GET /fares` |
| Favoriten | `GET/POST/DELETE /favorites` |
| Verspätungsstatistik | `GET /stats/delays/:line` |
| Web-Push | `GET /webpush/public-key`, `POST /webpush/subscribe`, `POST /webpush/unsubscribe`, `POST/DELETE /webpush/trip-alarm` |
| APNs (iOS-App) | `POST /push/register` |
| Health | `GET /health/full`, `GET /health/dashboard` |
## Datenbank (SQLite)
Automatisch angelegt beim ersten Start (`db/database.js`):
- `favorites` – server-seitige Favoriten (optional, Client nutzt primär `localStorage`)
- `push_tokens` – APNs-Geräte-Tokens (iOS-App)
- `delay_samples` – Verspätungs-Rohdaten pro Fahrt, passiv befüllt bei jeder
normalen Abfahrten-Abfrage; alte Einträge (>90 Tage) werden täglich automatisch gelöscht
- `push_subscriptions` – Web-Push-Abos (ein Datensatz pro Browser/Gerät)
- `push_favorite_stations` – Kopie der Favoriten-Haltestellen je Abo (für den Störungs-Job)
- `push_trip_alarms` – höchstens ein aktiver Fahrtalarm je Abo
## Hintergrund-Jobs
Beim Start (`server.js`) registriert:
- Vorwärmen des DB-Bahnhofs-Caches
- Tägliches Neuladen der VBB-Tarifzonen und BVG-Preise
- Tägliches Aufräumen alter Verspätungs-Samples
- **Störungs-Check** (alle 60s): prüft für jede Web-Push-Subscription die
verknüpften Favoriten-Haltestellen auf neue Störungen, verschickt bei Bedarf Push
- **Fahrtalarm-Check** (alle 20s): prüft aktive, per Push gespiegelte Fahrtalarme
und löst bei Erreichen der Zielhaltestelle aus
## Abhängigkeiten außerhalb dieses Repos
- Eine laufende **OTP2-Instanz** (VBB-GTFS + Berlin/Brandenburg-OSM) für die
Routenplanung – Adresse in `utils/otpClient.js` konfigurieren
- Ein Reverse Proxy (z. B. NPM/nginx), der den gewünschten Pfad (z. B.
`/live_navi`) auf diesen Node-Prozess weiterleitet