TILES_REGIONS auf germany/austria/switzerland + france/italy/czech-republic/
poland/slovakia/hungary/slovenia/netherlands/belgium/luxembourg/denmark/
liechtenstein erweitert. Output bleibt dach.pmtiles (Frontend-Name stabil).
Nach time-filter werden History + Einzel-PBFs gelöscht → ~27 GB weniger
Spitzen-Plattenplatz vor planetiler.
Mitglieder-Karte (forum.js): L.map/L.tileLayer(OSM) → UI.map.create, Cluster
+ Marker über die Facade (UI.map.clusterGroup/svgMarker), eigenes Leaflet-/
MarkerCluster-Nachladen raus. destroy() gibt Karte+Gruppe beim Verlassen frei.
Headless verifiziert: GL-Canvas, 2 Mitglieder-Marker, keine Fehler.
places.js (separate 'Hundefreundliche Orte'-Seite) war verwaist — in keiner
Navigation/keinem pages-Registry, nicht erreichbar. Die hundefreundlichen Orte
laufen längst als POI-Marker auf der zentralen GL-Karte (map.js). Auf Renés
Entscheidung gelöscht (JS + CSS-Block in components.css).
Damit laufen ALLE erreichbaren Karten der App auf MapLibre GL.
Eigentliche Ursache von 'Detailkarte zoomt nicht auf die Route': die Karte war
auf dem Gerät gar keine GL-Karte mehr, sondern der Leaflet+OSM-RASTER-Fallback.
Grund: _detailMap (GL-Kontext) wurde beim Schließen des Modals NIE freigegeben —
jede geöffnete Route leakte einen WebGL-Kontext. Nach ~8 wirft MapLibre, und
UI.map.create fällt auf Leaflet+OSM zurück. Genau die Mapnik-Kacheln aus Renés
Screenshots (und die OSM-Attribution, die wir doch loswerden wollten).
Fixes:
- _detailMap modulweit + im onClose des Detail-Modals freigeben.
- routes.js destroy(): _detailMap/_suggestMap/_searchMap + Mini-Maps beim
Verlassen der Seite freigeben.
- ui.js: Offscreen-Snapshot-Kontext nach 15s Leerlauf freigeben (hielt dauerhaft
einen Kontext; Cache bleibt → kein Neu-Rendern).
- _fitRouteMap fittet jetzt aufs 'load'/'idle'-Event der Karte (iOS verwirft ein
fitBounds VOR dem ersten Render) statt nur auf feste Timeouts.
Verifiziert (headless): 12 Detail-Öffnungen in Folge bleiben ALLE GL
(Leaflet:false), GL-Canvas-Zahl bleibt bei 1–2 statt zu wachsen. Vorher leakte
jede Öffnung einen Kontext.
Punkt 3 (Zoom auf die Route): feste Timeouts (0/200/500ms) griffen auf iOS oft
zu früh — der Modal-Container war noch nicht final vermessen, die Karte blieb
beim Start-Zoom (zoom 14, center=Start) hängen statt auf die ganze Route zu
zoomen. Jetzt _fitRouteMap mit ResizeObserver: fittet erneut, SOBALD der
Container seine endgültige Größe hat (Detail + Vorschläge). Facade-fitBounds
prüft jetzt auch clientHeight>0 (0-Höhe ergab schlechten Fit).
Punkt 5 (Navigations-Sperrbildschirm): der 2-Sek-Halten-Handler hing am ganzen
Dim-Overlay → Halten IRGENDWO entsperrte. Jetzt ein eigener Fingerabdruck-Knopf
(rk-nav-unlock-btn) wie beim Aufzeichnen-Dim; nur dort entsperrt es, mit
setPointerCapture. Tippen daneben tut bewusst nichts.
Verifiziert (headless): Detail fittet die ganze Route (v1204, 0 Fehler);
Dim-Hintergrund 2,2s halten → bleibt gesperrt, Knopf 2,2s halten → entsperrt.
Punkt 2 (Routen-Übersicht 'Karte'): _renderRoutesOnMap crashte, weil die
Polyline-Facade kein bindTooltip/on/setStyle/getLatLngs kannte. In
map-gl-mini.js ergänzt — inkl. breiter, fast unsichtbarer Hit-Linie, damit
Routen auf dem Handy gut antippbar sind (Klick → Detail). Hover-Tooltip
(Name+km) + Hover-Highlight.
Punkt 4 (Tagebuch): beide Leaflet/OSM-Karten (Standort-Übersicht +
Einzeleintrag) auf UI.map.create + Facade-Marker migriert. popupopen-Wiring
(kennt die GL-Facade nicht) → Klick-Delegation auf dem Karten-Container.
Karten-Instanzen werden beim View-Wechsel/Verlassen freigegeben (destroy +
_clearDiaryMaps) gegen WebGL-Kontext-Leak. Detail/Übersicht fitten mehrfach
(Container-Timing).
Nebenbei: _loadPraise warf NotFoundError (insertBefore) — #diary-list liegt
in #diary-view-content, nicht direkt in _container. Jetzt vor der Liste in
deren echtem Elternknoten einfügen.
Verifiziert (headless, eingeloggt, echte Daten): Routenkarte 8 Marker klickbar
→ Detail; Detail+Vorschläge zoomen auf die Route; Tagebuch-Karte GL mit 108
Markern, Popup-Klick → Eintrag, keine Fehler.
In der Routenliste fehlte der geografische Kontext — man sah nur die Routen-
form auf grünem Grund, nicht WO sie liegt oder wo sie entlangführt.
Lösung: UI.map.snapshot() rendert pro Track ein PNG aus EINEM geteilten
Offscreen-GL-Kontext (gleicher Style wie die echte Karte: Straßen, Orte,
Wald, Gewässer), zeichnet Route + Start/Ziel-Marker ein und cached das
Ergebnis. So bekommt jede Karte ihren Kontext, ohne bei vielen Listen-
einträgen das WebGL-Kontextlimit (iOS ~8) zu sprengen.
- ui.js: Offscreen-Singleton + serielle Render-Queue + Cache (_glSnapshot)
- routes.js: _buildMiniMap zeigt sofort SVG, upgradet dann aufs PNG
- GL aus → null → SVG-Platzhalter bleibt (Produktion/Flag aus unverändert)
Ein transienter Init-Fehler (Netz-Blip, SW-Update mitten in der Navigation,
Race) setzte page.module={} — der Guard 'if (page.module)' lud die Seite
danach nie mehr nach. Auf einer iOS-PWA, die nie ganz neu lädt, blieb 'Die
Seite funktioniert nicht mehr' damit tagelang hängen, obwohl der eigentliche
Bug (Routen-GL) längst gefixt war.
- echten Fehler nicht mehr verschlucken (console.error)
- page.module bei Exception NICHT mehr tot stellen → nächster Aufruf versucht neu
- 'Erneut versuchen'-Button im Fehler-State
- Routen v1199 in Chromium+WebKit headless verifiziert (Liste/Entdecken/Detail ok)
- Pfeile: rotate als SVG-Pfad-Attribut statt CSS-transform am Element (maplibregl.Marker
überschrieb das transform → Pfeile zeigten alle nach Norden)
- Filter-Panel + Badge: doppeltes class-Attribut (class=X class=hidden) → Browser ignorierte
'hidden' → Filter immer offen + roter Badge immer an. Zu 'X hidden' gemergt.
- transportation nach class: Pfade/Tracks dünn+gestrichelt; Straßen weiß, Breite nach Klasse
(motorway/trunk breit … minor schmal) — Pfade sehen nicht mehr wie Straßen aus
- neue Label-Layer: poi (Kinderspielplatz/Schule… ab Z15) + housenumber (ab Z17), name:de
- Label-Reihenfolge = Kollisions-Priorität (Orte zuerst)
- main.py: /fonts-Mount (Glyph-PBFs aus data/tiles/fonts), Open Sans Regular self-hosted
- map-gl-style.js: glyphs-URL + Label-Layer (Ortsnamen/Straßen/Gewässer, name:de)
- map.js _initMapGL: ScaleControl entfernt (überdeckte die Zoom/Wetter/Zecken-Pill)
Ortsnamen für Orientierung (René), auch bei kleinem Zoom.
_loadOsmLayers verwarf Scan-Anfragen, die während eines laufenden Scans kamen (return).
Bei langsamem Overpass (Handy) ging so der finale Z14-Scan verloren → Marker leer.
Jetzt: _scanQueued merkt die Anfrage vor, finally holt sie nach → letzte Ansicht wird garantiert gescannt.
René: 'geclusterte Marker haben kein Symbol'. Jeder Cluster ist genau eine Kategorie →
weißes Phosphor-Icon in der Cluster-Mitte (icon-size skaliert mit point_count). Keine Glyphs nötig.
René: 'wo die Karten-Buttons auftauchen ist eine Zone die Kartenbedienung verhindert'.
.map-statusbar/.map-speed-dial/.map-crosshair/.map-search-wrap(inactive)/.map-rec-panel(inactive)
fingen Touch in ihrer Bounding-Box → tote Zonen. Jetzt pointer-events:none, nur Buttons auto.
Erklärt die 'reagiert nach kurzer Zeit'-Verzögerung (Drag startet tot, greift erst im Karten-Bereich).
Gilt für beide Engines (verbessert auch Leaflet).
- _loadOsmLayers: kein _map.resize() für GL (löste move→moveend→scan-Loop aus, 'pausenlos')
- _initMapGL: touchZoomRotate.disableRotation() + touchPitch.disable() + container touch-action:none
→ Pinch=reines Zoom, bleibt in der Karte (kein iOS-Page-Zoom), keine ungewollte Drehung
Eigenständiges Modul: per-Kategorie GeoJSON-Cluster, rasterisierte Phosphor-Icons,
Danger-Polygone, Sichtbarkeit, Click→Popup. /maplibre-markers-test zum headless-Verifizieren
VOR dem Einbau in map.js (auth-gated).
map.js: _useGL()/loadMapLibre()/_initMapGL() + engine-neutrale Facade
(_mapFlyTo/_mapSetView/_mapGetZoom/_mapResize/_mapGetCenter/_mapPaddedBounds, kapselt
[lat,lon]↔[lng,lat]). init() verzweigt auf GL bei Flag 'by_map_gl'/?mapgl=1. Basemap+
Controls+Dark(setStyle)+Scan-Wiring+Crosshair. POI-Layer/Marker = Runde 2. Flag default AUS.
Main-Thread-Rendering von protomaps-leaflet + App-Map-Logik blockiert UI-Thread.
Greift auch bei localStorage-Flag=1. Performance erst lösen, dann reaktivieren.
Spike-Befund: app-weit kommen nur 200 ohne Accept-Ranges zurück, FileResponse-Range
wird von der BaseHTTPMiddleware gebrochen. MapLibre/pmtiles braucht aber Byte-Ranges.
Route gibt 206 als normales Response (Byte-Slice) zurück. Produktion: nginx/NPM direkt.
Der alte delete_account löschte nur ~6 Tabellen und scheiterte am finalen
DELETE FROM users, sobald der User Zeilen in Non-Cascade-Tabellen hatte
(routes, places, walks, events, forum_threads, invoices …). Jetzt:
PRAGMA defer_foreign_keys + foreign_key_list-Introspektion (CASCADE automatisch,
NO-ACTION-Eigentum löschen, Actor/SET-NULL-Spalten nullen) plus user_id/owner_id-
Scan für Tabellen ohne formale FK. Regressionstest test_account_deletion.py.
Relevant für App-Store-Gl. 4 (In-App-Konto-Löschung muss zuverlässig funktionieren).