feat: add Docker/OpenTofu deployment and DE/NL routing

This commit is contained in:
BuTzZ
2026-07-24 23:10:17 +02:00
parent 57f7b4dedb
commit 12eee8d211
59 changed files with 4452 additions and 148 deletions
+116 -9
View File
@@ -22,18 +22,37 @@ iPhone-taugliche Browser-PWA für Bootsfahrer: Karte, GPS, Kompass, Wetter/Welle
## Start
Dieses Projekt benötigt Node `>=20.19`. In dieser Arbeitskopie liegt eine lokale Node-Version unter `.tools/`; nutze sie so:
Der reguläre lokale Betrieb läuft als einzelner Produktionscontainer. Der
gemeinsame Fahrwasserindex für Deutschland und die Niederlande muss einmalig
vorhanden sein:
```bash
npm run setup:local-routing
npm run docker:up
```
Web und API: `http://localhost:5173`<br>
Healthcheck: `http://localhost:5173/health`
Die sichtbaren Kartenkacheln kommen weiterhin von den konfigurierten externen
Kartendiensten. Lokal gespeichert werden nur die OSM-Rohdaten und der daraus
erzeugte Routingindex.
Stoppen:
```bash
npm run docker:down
```
Für die Entwicklung ohne Container benötigt das Projekt Node `>=20.19`:
```bash
export PATH="$PWD/.tools/bin:$PATH"
npm install
npm run build
npm run test
npm run dev
```
Web: `http://localhost:5173`<br>
API: `http://localhost:5174`
Dev-Web: `http://localhost:5173`<br>
Dev-API: `http://localhost:5174`
Für GPS-Tests auf dem iPhone muss die App über HTTPS laufen. Starte dafür:
@@ -43,13 +62,75 @@ npm run dev:https
Web HTTPS: `https://localhost:5173` bzw. die von Vite ausgegebene `https://192.168...:5173`-Adresse im gleichen WLAN. Beim lokalen Dev-Zertifikat muss Safari die Zertifikatswarnung einmal akzeptieren; falls iOS Geolocation danach weiterhin blockiert, nutze ein vertrauenswürdiges lokales Zertifikat oder einen HTTPS-Tunnel.
## Hetzner-Deployment mit OpenTofu
Die produktive Infrastruktur besteht aus einem Hetzner-Server, einer festen
IPv4, Firewall und einem persistenten Volume. Der Docker-Stack enthält nur die
App, Nginx/Certbot und den Wartungscontainer für Deutschland- und
Niederlande-Routendaten; Kartenkacheln werden nicht selbst gehostet.
Die beiden lokalen, von Git ignorierten Konfigurationsdateien sind bereits
angelegt:
- `infra/opentofu/terraform.tfvars`: hier den Hetzner-Cloud-Read/Write-Token
eintragen und `admin_cidrs` bei Bedarf auf die aktuelle öffentliche IP
aktualisieren.
- `deploy/.env.production`: hier eine echte E-Mail-Adresse für Let's Encrypt
als `WATERMAPS_ACME_EMAIL` eintragen.
Danach wird die Infrastruktur erzeugt:
```bash
cd infra/opentofu
tofu init
tofu plan -out=watermaps.tfplan
tofu apply watermaps.tfplan
tofu output server_ipv4
cd ../..
```
Sobald `server_ipv4` ausgegeben wurde, kann der manuelle DNS-A-Record
`watermaps.incoso.eu` auf diese IPv4 gesetzt werden. Das erste Deployment darf
bereits vor der DNS-Propagation laufen:
```bash
./deploy/scripts/upload-and-deploy.sh \
--identity ~/.ssh/watermaps_hetzner_ed25519
```
Dabei werden die vollständigen Geofabrik-Extrakte für Deutschland und die
Niederlande auf dem persistenten Server-Volume geladen und der lokale
Routingindex erstellt. Vor dem SSL-Livegang liefert Port 80 außer
ACME-Challenges nur 404.
Erst wenn der DNS-A-Record propagiert ist, wird HTTPS mit dem finalen manuellen
Befehl aktiviert:
```bash
./deploy/scripts/remote-go-live.sh \
--identity ~/.ssh/watermaps_hetzner_ed25519
```
Das Skript prüft DNS, beide Länder im Routingindex sowie Testrouten, fordert
das Zertifikat an und schaltet anschließend dauerhaft auf HTTPS um.
Ausführliche Hinweise stehen in
[`infra/opentofu/README.md`](infra/opentofu/README.md) und
[`deploy/README.md`](deploy/README.md).
## Datenstatus
Die freie Datenstrategie ist bewusst als Fahr- und Planungshilfe umgesetzt. Die App zeigt Attribution und den Status `Nicht amtlich`, weil freie Karten-/Modelldaten keine amtlich zugelassene Seekarte ersetzen.
## Routingstatus
`POST /api/routes` nutzt zuerst lokale PostGIS-Fahrwasserdaten aus `marine_fairway_edges`. Wenn in der Datenbank kein passender Graph liegt, versucht die API live extrahierte OSM/OpenSeaMap-Fahrwasserdaten für die Bounding Box zwischen Start, Wegpunkten und Ziel. Lokale und Live-Fragmente werden topologisch zusammengeführt. Berücksichtigt werden unter anderem `navigation_line`, `recommended_track`, `fairway`, navigierbare Kanäle und explizit für Boote oder Schiffe freigegebene Flüsse. Gesperrte, private, stillgelegte oder im Bau befindliche Wege werden ausgeschlossen.
`POST /api/routes` kann Fahrwasserdaten aus PostGIS, dem lokalen
Geofabrik-Dateiindex und wenn explizit aktiviert live aus Overpass
zusammenführen. Die Produktionskonfiguration verwendet ausschließlich den
lokalen Deutschland-/Niederlande-Index; sie benötigt weder PostGIS noch eine
laufende Overpass-Verbindung. Berücksichtigt werden unter anderem
`navigation_line`, `recommended_track`, `fairway`, navigierbare Kanäle und
explizit für Boote oder Schiffe freigegebene Flüsse. Gesperrte, private,
stillgelegte oder im Bau befindliche Wege werden ausgeschlossen.
Wenn freie Laufzeitdaten fehlen, stehen zwei klar als nicht amtlich markierte Fallback-Korridore bereit:
@@ -112,7 +193,7 @@ Die Küsten-PBFs lassen sich reproduzierbar von Geofabrik laden und ohne lokal i
```bash
./scripts/download-geofabrik.sh
docker compose up -d postgres redis martin
docker compose --profile postgis up -d postgres redis martin
DATABASE_URL=postgres://seacompass:seacompass@localhost:55432/seacompass \
./scripts/import-geofabrik-docker.sh \
data/geofabrik/germany-latest.osm.pbf \
@@ -206,11 +287,37 @@ Der lokale PostGIS-Container nutzt standardmäßig Host-Port `55432`, damit er n
## Lokale Infrastruktur
```bash
docker compose up -d postgres redis martin
docker compose --profile postgis up -d postgres redis martin
```
Danach `.env` aus `.env.example` ableiten und für echte PostGIS-Features `WATERMAPS_DEMO_DATA=false` setzen. Die frühere Variable `SEA_COMPASS_DEMO_DATA` wird übergangsweise weiterhin akzeptiert.
### Dateibasiertes Deutschland-/Niederlande-Routing
Wenn Docker/PostGIS nicht verfügbar ist, kann die API den vollständigen
Geofabrik-Extrakt beider Länder als kompakte lokale Fahrwasserdatei verwenden:
```bash
npm run setup:local-routing
```
Der Aufbau liest beide PBFs in Streaming-Durchläufen, führt überlappende
OSM-Wege zusammen und erzeugt
`data/local/germany-netherlands-fairways.json`. Für einen ausschließlich
lokalen Betrieb:
```dotenv
DATABASE_URL=
REDIS_URL=
WATERMAPS_LOCAL_FAIRWAYS_PATH=data/local/germany-netherlands-fairways.json
WATERMAPS_LIVE_FAIRWAYS=false
```
Damit benötigen Routen innerhalb des heruntergeladenen Datenstands weder
PostGIS noch eine laufende Overpass-Verbindung. Nach einem neuen
Geofabrik-Snapshot prüft `npm run setup:local-routing` die Prüfsummen und baut
den Index bei Bedarf atomar neu.
## APIs
- `GET /api/config`