diff --git a/README.md b/README.md index ceec1db..ed4f915 100644 --- a/README.md +++ b/README.md @@ -85,3 +85,158 @@ CSS Custom Properties und `dvh`-Einheiten (mit `vh`-Fallback). Kein IE11-Support 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