Commit graph

81 commits

Author SHA1 Message Date
2cdb743ce7 Selektives Loeschen: auch Funkloch-Gebiete bleiben + Keep-Set haertung
Rene: Funkloecher + Routen waren nach 'Alles loeschen' weiter weg.
- Funkloch-Regionen jetzt im Keep-Set (geloescht wird NUR Manuelles);
  Zonen behalten ihren Fuellstatus (Komplett-Wipe setzt weiter zurueck)
- Korridor-Migration beim Loeschen: keepTracks=[{name,track}] schreibt
  Tracks in Alt-Eintraege ohne r.track (Bestand vor v1236) bzw. legt
  fehlende Korridor-Regionen an — kein Warten auf Self-Healing
- clear() liefert Summary; Toast zeigt 'behalten: Standort, X Routen,
  Y Funkloch-Gebiete' — Diagnose-Sichtbarkeit fuer Geraetetests
Bump v1237
2026-06-06 13:55:37 +02:00
ca97613938 Fix: Selektives Loeschen griff auf Geraet nicht — Keep-Set jetzt selbsttragend aus der Meta
Renes Befund: 'Alles loeschen' wischte weiter alles. Ursachen: (a) Bestands-
Gebiete hatten keine standort-Region (ensureHomeArea legt nur bei FEHLENDER
Kachel los), (b) Korridor-Keys waren nur aus API-Tracks ableitbar -> leeres
Keep-Set = Komplett-Wipe.
- downloadCorridor speichert vereinfachten Track (<=60 Pkt) in der Region-Meta;
  clear() baut Korridor-Keep daraus — ohne API/Login/GPS
- Standort-ADOPTION: clear() mit center legt fehlende standort-Region
  synthetisch an (Bestandsdaten vor Runde 6)
- map.js: center-Fallback auf by_last_position wenn GPS noch keinen Fix hat
- Test r7 erweitert (clear ohne Optionen haelt Korridor aus Meta), alle gruen
Bump v1236
2026-06-06 13:44:01 +02:00
29cd489287 Offline-Karten Runde 7: 'Alles loeschen' selektiv — Standort + Routen-Korridore bleiben
Idee Rene (spart Vorladezeit + Daten): statt loeschen-und-neu-laden bleiben
- Standort-Gebiete (Regionen type 'standort')
- Korridore der gespeicherten Routen (clear({keepTracks}) aus preview_track)
- 5-km-Umkreis der aktuellen Position + Basis-Zooms 0-9
- Marker/Warnungen (p/) + Glyphs (f/)
Geloescht: manuelle Gebiete/Ausschnitte + Funkloch-Kacheln (Zonen bleiben
gemerkt, Nahe laden automatisch neu). Ohne Keep-Kandidaten: Komplett-Wipe.
Batch-Delete in einer Transaktion. Tests r7 neu, r6 angepasst, Regression gruen.
Bump v1235
2026-06-06 13:35:18 +02:00
94a6ce49ba Offline-Karten Runde 6: Standort-Grundversorgung — aktuelles Gebiet bleibt immer geladen
Renes Modell Punkt 1 war zu eng interpretiert (nur Funkloecher): das Gebiet
um die aktuelle Position gehoert zur Grundversorgung.
- ensureHomeArea(lat,lon): Zentrums-Kachel-Check -> bei Luecke Budget-Download
  (type 'standort', Cap-gated)
- Start-Check: Standort raw pruefen (ohne GL-Stack) und bei Bedarf laden
- 'Alles loeschen': Standort-Gebiet wird SOFORT neu geladen (+ Toast) —
  vorher war die Offline-Funktionalitaet genau am wichtigsten Ort weg
- Pfote Segment 5: Standort-Kachel da UND Zonen im 50-km-Umkreis gefuellt
  (ferne Zonen zaehlen nicht mehr — sie laden erst vor Ort)
- Tests r6 + Regression r1/r3/r4/r5 gruen
Bump v1234
2026-06-06 13:23:33 +02:00
6c313aca05 Offline-Karten Runde 5: Geraetetest-Feedback (Indikator, Flugmodus-Signal, Ent-Funklochen, Warnungs-Aktualitaet, Routen-Start-Check)
- Indikator links unter die Zoom-Regler (rechts verdeckte Legenden-Chips)
- Flugmodus bei offener App -> Position raw als Funkloch-Zone (offline-Event)
- Ent-Funklochen: Zonen-Liste im Offline-Modal mit X (removeDeadZone)
- Warnungs-Aktualitaet: _mergeStore Bbox-Replace (aufgehobene Giftkoeder/
  gefundene Hunde verschwinden; Fetch-Kreis deckt Bbox via sqrt2 ab;
  fresh=null merged nie) + 24h-Refresh im 50km-Umkreis beim Start
- Routen offline nutzbar halten: ensureRouteCorridors beim Start-Check
  (Stichproben-Verify, Re-Download aus preview_track, Region-Dedupe)
- Stub-Tests ins Repo: tests/js/ (r1/r3/r4/r5, alle gruen)
Bump v1231
2026-06-06 13:00:20 +02:00
53bc27faa3 Offline-Karten Runde 4: Minimal-Speicher-Modell (Modell Rene)
Funkloch-Gedaechtnis = Quelle der Wahrheit, Kacheln = ableitbarer Cache:
- Ephemeres Vorausladen: Prefetch-Kacheln werden bei Aufzeichnungsende
  geloescht, wenn die Runde kein Funkloch hatte (nur neue Keys)
- Netz-Probe bei Aufzeichnung (~2min, 6s-Timeout): erkennt Funkloecher auch
  in bereits gespeicherten Gebieten (dort kein Remote-Miss als Signal)
- clear() behaelt Zonen (filled=false) -> naechster Online-Start laedt
  Funkloch-Gebiete automatisch neu, auch nach 'Alles loeschen'
- Start-Check mit Position: nur Zonen im 50-km-Umkreis, naechste zuerst,
  Coverage-Verify (faengt Eviction ab); Pfote Segment 5 = alle Zonen gefuellt
- Coverage-Layer zweifarbig: Funkloch orange, manuell blau + Modal-Legende
- Stub-Tests Runde 4 (Prune/Probe/clear/Naehe/Verify/Faerbung) bestanden
Bump v1230
2026-06-06 12:46:12 +02:00
763108fa7c Offline-Karten Runde 3: Puls-Icon, rollendes Vorausladen, Ausschnitt-Download, Speicher-Cap
- Offline-Indikator: pulsierendes 32px-Icon oben rechts (unter Kopfzeilen-Hoehe)
  statt Leiste ueber die volle Breite — verdeckte '<- Zurueck' in der
  Routennavigation (Geraetetest Rene)
- Rollendes Vorausladen: setGps laedt alle ~400m still fehlende z14+-2-Kacheln
  um die Position — deckt den Weg schon beim ERSTEN Funkloch-Besuch ab
- Bereichsauswahl light: 'Sichtbaren Ausschnitt speichern' im Offline-Modal
  (downloadBbox, Cap 40 MB, Zu-gross-Schutz)
- Speicher-Cap 250 MB als Soft-Guard fuer automatische Pfade + totalBytes-Zaehler
  + navigator.storage.persist() best-effort; echte LRU vertagt (Refcounting noetig)
- Auto-OSM-Raster-Prefetch entfernt (manueller Leaflet-Pfad bleibt)
- Logik-Tests (Node-Stubs) fuer Bbox/Cap/Throttle/persist bestanden
Bump v1229
2026-06-06 12:34:48 +02:00
a600ca1dec Offline: Giftkoeder + vermisste Hunde offline sichtbar, Korridor auf Detailkarte
Geraetetest-Befunde Runde 2:
- Giftkoeder verschwanden offline: /api/places kam aus dem SW-Cache (feste URL)
  und verhinderte den allFailed-Fallback, waehrend /api/poison?lat=... (Bbox-URL)
  scheiterte -> jetzt faellt jede Quelle EINZELN auf den letzten guten Stand
  zurueck (localStorage) + Merge aus dem Offline-Region-Snapshot
- Region-Download speichert jetzt auch /api/poison + /api/lost der Gegend
  (p/_poison, p/_lost, anonym; MapOffline.alerts(kind,bbox) als Reader) —
  Sicherheitsdaten muessen auch am vorab gespeicherten Urlaubsort da sein
- lost.js Offline-Pfad merged den Region-Snapshot in Cache- und Leer-Fall
- Routen-Korridor war 'unsichtbar' (lag im schon gespeicherten Gebiet):
  nach dem Speichern werden die gespeicherten Bereiche blau auf der
  Detailkarte eingeblendet; Logik per Node-Stub-Test verifiziert
Bump v1227
2026-06-06 12:15:34 +02:00
42a04ec405 Offline-Karten Runde 2: adaptives Modell (Budget, Funkloch-Gedaechtnis, Korridor, Coverage)
Design Rene 2026-06-06:
- Budget-Download: z14-Ringe um den Standort bis 5 MB gespeicherte Bytes
  (Stadt klein, Land gross — passend zur Funknetzdichte); client-seitig,
  Server-Region-Extract entfaellt
- Funkloch-Gedaechtnis: Tile-Miss bei aktivem GPS-Recording -> Zone gemerkt
  (lokal, nie hochgeladen); Auto-Download offener Zonen sobald online
- Routen-Korridor: 'Offline'-Button im Routen-Detail, Kacheln +-1km um den
  Track + Marker (Cap 50 MB) — fuer mehrtaegige Unternehmungen
- Coverage-Layer: gespeicherte Bereiche als blauer Layer; Offline-Button
  oeffnet Verwaltungs-Modal (Stats, speichern, anzeigen, loeschen)
- Flag-Logik zentral in boot.js BY.offlineTiles() (war 3x dupliziert)
Bump v1226
2026-06-06 12:00:43 +02:00
45534aa8ee Sweep: r.ok-Check bei allen direkten fetch('/api/...')-Aufrufen (SW-503-JSON-Falle)
5 Fundstellen nach dem Marker-Bug-Muster (v1224) gefixt:
- landing-init.js: Stats-Zahlen waeren offline NaN geworden
- social.js: Medien-Upload-Fehler wurde verschluckt (kein ok-Check, kein catch)
- routes.js: Unterwegs-POIs — {detail:...}.filter warf statt sauber []
- map.js: Marker-Melden zeigte Erfolgs-Toast obwohl Request fehlschlug
- settings.js: Update-Check meldete offline faelschlich 'ist aktuell'
Rest geprueft: api.js-Wrapper, wiki/uebungen/trainingsplaene-Helper checken ok,
externe Dienste (Nominatim etc.) laufen nicht ueber den SW-/api/-Zweig.
Bump v1225
2026-06-06 11:42:05 +02:00
e6d6a3e697 Fix: Marker verschwanden offline beim Kartenbewegen — SW-503-JSON als Fehler werten
Der SW beantwortet nicht-cachebare API-GETs offline mit 503 + JSON-Body,
r.json() wirft dann NICHT -> Erfolgs-Pfad ersetzte Marker durch {detail:...}.
_fetchPois prueft jetzt r.ok + Array.isArray, dadurch greift der
IndexedDB-Fallback (MapOffline.pois) in Phase 1 und Phase 2 behaelt den Bestand.
Bump v1224
2026-06-06 11:35:03 +02:00
e2c75f04bc Offline-Karten: POI-Marker offlinetauglich + Offline-Banner klappt ein (Geraetetest-Befunde)
- MapOffline.downloadAround speichert zusaetzlich /api/osm/pois je Typ fuer die
  Region-Bbox in IndexedDB (Key-Praefix p/, Merge per id — zweite Region loescht
  die erste nicht); MapOffline.pois(type,bbox) filtert fuer den Ausschnitt
- map.js Phase-1-Fallback: Fetch fehlgeschlagen (offline) -> gespeicherte
  Region-POIs statt leerer Karte; Download-Toast zeigt Marker-Anzahl
- Offline-Banner: nach 5s auf schmale Icon-Leiste eingeklappt (verdeckte die
  Karten-Legende); Inline-Styles nach components.css konsolidiert
- Bump v1223
2026-06-06 11:25:40 +02:00
70a1f5856a Offline-Karten Follow-ups: Staging-Default AN, Karten-Download-Button, Glyph-Persistenz
- by_offline_tiles Default AN auf staging.banyaro.app (localStorage/?tilesoffline=1/0 uebersteuert)
- Speed-Dial 'Karte offline speichern': GL -> MapOffline.downloadAround(Kartenmitte, 5km),
  Leaflet -> alter Raster-Prefetch (_cacheTiles war seit FAB-Redesign verwaist)
- Glyphs in IndexedDB (Key-Praefix f/) + byt://f/-Protokoll: ueberlebt App-Updates
- OSM-Raster-Prefetch im Offline-Tiles-Modus uebersprungen (GL nutzt das Raster nicht)
- Button-Sichtbarkeit gated: GL ohne Offline-Flag (= Production) zeigt ihn nicht
2026-06-06 11:03:46 +02:00
939e48b0c7 Karten: GL als Default auf Production freigeschaltet (Hostname banyaro.app/.de)
MapLibre-GL-Migration ist verifiziert (Staging) → GL jetzt Default auf allen
deployten Hosts statt nur staging.banyaro.app. localhost/LAN bleibt OSM-Raster
(keine lokalen Tiles), by_map_gl=0 erzwingt weiterhin den Leaflet-Fallback.
Tiles (dach.pmtiles, 15 Länder) + Glyphs liegen nun auch im Prod-Data-Volume.
SW-Bump 1219→1220.
2026-06-05 21:12:24 +02:00
ac187dc740 Radar-Timeline: Slider-Scrubbing gefixt + Breite/Höhe an Status-Pill
- Scrub-Bug: _radarPause() setzte slider.value zurück, BEVOR der gezogene Wert
  gelesen wurde → sprang immer auf 'jetzt'. Jetzt Wert zuerst lesen. Scrubben
  stoppt Play + zeigt den Frame der Position (verifiziert: Klick 20%→Frame 2,
  Setter→5→Frame 5).
- Breite per JS an .map-statusbar angeglichen (gleiche linke + rechte Kante),
  Höhe/Optik an die Pill (kleinerer Play-Button, flacher).
2026-06-05 20:39:41 +02:00
bcbf9a9645 Regenradar: abspielbare Zeitleiste (RainViewer ~2h Verlauf + Nowcast)
Bisher nur der neueste Frame; jetzt alle ~13-16 RainViewer-Frames (past+nowcast,
10-Min-Schritte) mit Play/Pause + Slider + Zeitstempel (jetzt / +N / -N Min,
Vorhersage-Frames bläulich) — RainToday-artig. Frame-Wechsel smooth via
raster setTiles (kein Flackern), Loop, _radarNowIdx = letzter Vergangenheits-Frame.
Timeline unten-mittig, wird bei Radar-AUS entfernt. Pro-Feature wie das Radar.
Headless verifiziert: 13 Frames, Play scrubbt (12→0→1→2), keine Fehler.
2026-06-05 20:12:30 +02:00
aefdac87ad Wetter-Pill: Niederschlag = Höchstwert der nächsten 3 Std statt Tages-Max
weather.py get_weather_for_location: precip = max(h_precip[now_h:now_h+3])
(Fallback Tages-Max). map.js Pill zeigt '💧 X% (3h)'. Gilt auch fürs
Welten-Banner (geteiltes precip_prob-Feld) — behebt das 'ganzer Tag'-Problem
überall. Gespeicherte Tagebuch-Snapshots unberührt (historisch).
2026-06-05 20:01:32 +02:00
8f13f4d38d Offline-Karten: Kern implementiert (Region-Download → IndexedDB → Offline-Render)
map-offline.js (window.MapOffline): lädt Vektorkacheln eines Bereichs via pmtiles.getZxy
in IndexedDB + cacht die Glyphs mit (KRITISCH: ohne Glyphs lässt MapLibre offline die
ganze Kachel fallen). byt://-Protokoll bedient MapLibre IndexedDB-first, remote-Fallback.
- map-gl-style.js: build({offline}) nutzt byt-Source statt pmtiles:// (Flag by_offline_tiles,
  Default AUS bis gerätegetestet); glyphs bleiben /fonts (SW-gecacht)
- ui.js + map.js: map-offline.js mitladen + byt-Protokoll registrieren
- getZxy liefert bereits dekomprimierte MVT (kein gunzip) → ~15 MB/5km in IndexedDB

Headless bewiesen: Download 97 Tiles (5km München) → Netz AUS → 1903 Features gerendert,
nicht geladene Gegend (Paris) korrekt leer. Offen: Download-Button/FAB-Segment-5-Verdrahtung,
adaptives Lernen, Bereichsauswahl/Routen-Korridor (siehe docs/OFFLINE_MAPS_PLAN.md).
2026-06-05 19:46:18 +02:00
c7201aa07b Karten-Attribution: standardmäßig eingeklappt (nur ⓘ) + doppelten Hinweis entfernt
Punkt 6: MapLibre rendert die Compact-Attribution offen (maplibregl-compact-show
+ open) → voller Text '© OpenStreetMap contributors' immer sichtbar. Neuer Helper
MapGLStyle.collapseAttribution() entfernt die Klasse/open nach dem Hinzufügen →
nur noch das ⓘ, der Text erscheint erst auf Klick (rechtlich nach ODbL ausreichend).
In map-gl-mini.js (Seitenkarten) + map.js (zentrale Karte) verdrahtet.

Punkt 7: poison.js + lost.js hatten UNTER der Karte zusätzlich ein hartkodiertes
'© OpenStreetMap-Mitwirkende' — doppelt zum Karten-ⓘ. Entfernt (+ ungenutzte
.lost-map-attribution CSS-Klasse). Verifiziert: osmTextLeafCount 2-3 → 1, compactShown true → false.
2026-06-05 15:48:11 +02:00
3523a44a0b MapLibre: GL als Staging-Default + Feinschliff (Cluster-Zahlen, Theme-Robustheit)
- _useGL: Staging default-AN (Prod aus, ?mapgl=0 überschreibt) → Breitentest
- Cluster zeigen ZAHL (point_count) statt Icon (Glyphs vorhanden)
- Theme-Wechsel: Wetter-Raster + Rec-Track nach setStyle neu anlegen; Click-Handler nur einmal binden (keine doppelten Popups)
2026-06-05 11:26:55 +02:00
425f99effb MapLibre-Port 3b+3c: Wetter + GPS-Aufzeichnung für GL entgaten
3b Wetter: engine-neutrale Helfer (_wxAddRaster→raster-source unter den Markern, _mapOnMove,
   _wxAddTempMarker→maplibregl.Marker). _toggleRadar/_loadRadar/_toggleTemp/_loadTempLabels gebrancht.
3c GPS: _recTrackGL (geojson line-source), _updateRecMarker (maplibregl.Marker), _recCleanupMap.
   _updateRecMap/_startRecording-Resume/Cleanup gebrancht, Gates entfernt. panTo [lng,lat] für GL.
2026-06-05 11:19:40 +02:00
9c959dd632 GL-Karte: Ortsnamen-Labels (Glyphs self-hosted) + ScaleControl raus (lag unter der Status-Pill)
- 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.
2026-06-05 11:09:08 +02:00
4d0cd0f460 Karten-Fix: fraktionalen MapLibre-Zoom für Scan-Schwelle runden
MapLibre-Zoom ist kontinuierlich (13.7); Statusleiste rundet (zeigt Z14), Scan verglich roh
→ bei angezeigtem Z14 (echt 13.x) galt zoom<14 → Marker gecleart, erst ab Z15 sichtbar.
Jetzt Math.round(getZoom()) für die 10/14-Schwellen (wie die Anzeige). Leaflet unverändert (ganzzahlig).
2026-06-05 11:01:09 +02:00
980338d7f1 Karten-Fix: Scan-Race bei schnellen Zoom-Folgen (Z16→Z13→Z14 → keine Marker)
_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.
2026-06-05 10:56:08 +02:00
2d7eca16a7 MapLibre-Port 3a-Fix: Scanner-Endlosschleife (resize im Scan) + Pinch-Page-Zoom + Rotation
- _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
2026-06-05 10:26:35 +02:00
542106e77b MapLibre-Port Runde 3a: MapGLMarkers in map.js verdrahtet (flag-gated)
- _loadOsmLayers/_loadAll/_addPlaces/_addPoison/_addBreeders/_applyVisibility/_deleteUserPoi
  engine-neutral (GL: POI-DATEN statt Marker, MapGLMarkers.setLayer/setVisible)
- Standort-Dot, Place-Picker-Temp-Marker, Such-Marker als maplibregl.Marker
- engine-spez. Aufrufe über Facade (_mapFlyTo/_mapSetView/_mapResize)
- Wetter + GPS-Recording für GL vorerst gegated (Port in 3b/3c)
- Flag 'by_map_gl'/?mapgl=1, default AUS
2026-06-05 10:06:54 +02:00
63c9be68c6 MapLibre-Port Runde 1: Engine-Fundament (flag-gated, Default Leaflet)
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.
2026-06-05 09:37:59 +02:00
1d64dc5d70 Fix: zentrale Karte nutzte window.UI (undefined) statt bare UI → immer Raster-Branch
ui.js exponiert 'const UI' = globales lexikalisches Binding (bare UI), NICHT window.UI.
map.js _addBasemap prüfte window.UI → immer falsy → Vektor-Pfad nie genommen.
Jetzt: typeof UI-Check. (window.UI?.toast in boot/api/app sind separat tote No-Ops.)
2026-06-05 09:06:09 +02:00
647aa684db Vektor-Basemap: zentrale Karte (pages/map.js) integrieren — sie umging UI.map.create
- map.js _addBasemap: Vektor-Layer (Flag) mit Raster-Fallback, eigener Basemap-Code
- Theme-Wechsel baut Vektor-Layer mit passendem Flavor neu (kein CSS-Filter bei Vektor)
- ui.js: UI.map.vectorEnabled()/vectorLayer() exponiert für Karten mit eigenem Layer-Mgmt
- APP_VER bump
2026-06-05 08:28:11 +02:00
78866206b4 Feature: Routenaufzeichnung übersteht App-Updates (Guard + Persistenz)
Stufe 1 (Guard): Während aktiver Aufzeichnung wird der SW-/Force-Update-Reload
aufgeschoben (window._byRecording → boot.js/_bySwReload + app.js force-update);
nach Stop/Speichern via window._byReloadIfPending() nachgeholt.

Stufe 2 (Persistenz): Track wird gedrosselt nach localStorage (RecStore) gesichert
und beim nächsten Öffnen der Karten-/Routen-Seite als 'Aufzeichnung fortsetzen?'
angeboten (Resume seedet Track+km+Startzeit). Schützt auch bei Crash/OS-Kill/
manuellem Reload. Greift in map.js UND routes.js. SW v1167
2026-06-04 17:13:23 +02:00
9afbf24535 OSM-Beiträge: "Hund willkommen?" 👍/👎 (dog=yes/no) + Umdrehen
- dog=no zusätzlich zu dog=yes (Pächterwechsel → Ort nicht mehr hundefreundlich).
- Map-Popup: ein "Hund willkommen?"-Block mit Daumen hoch/runter statt zwei
  Buttons. Beide rufen /dog-friendly mit welcome=true|false.
- Backend generisch: tag_value yes|no; vorhandene Markierung mit anderem Wert
  wird umgedreht (Update statt 409); submit_dog_tag(value); Confirm/Revert prüft
  gegen den jeweiligen tag_value; Changeset-Kommentar wertabhängig.
2026-06-03 21:49:44 +02:00
57849515ea OSM-Beiträge: Map-Button (dog=yes), Changeset-Upload, Confirm/Pro-Job
- Map-Popup: "Hund war willkommen"-Button (dog=yes) für Restaurant/Hotel/
  Shop/Tierarzt/Hundesalon → POST /osm-contrib/dog-friendly.
- OSM-Changeset-Upload (write_api): Element holen (node/way) → dog=yes →
  Changeset create/upload/close; idempotent; best-effort beim Tap.
- OSM-Endpunkte konfigurierbar (OSM_OAUTH_BASE/OSM_API_BASE) — Staging gegen
  Dev-Sandbox, KEINE echten Edits auf Produktiv-OSM.
- Scheduler-Job (täglich 03:40): Pending-Retry + Revert-Überleben (7 Tage) →
  confirmed/rejected; Pro-Freischaltung (100 confirmed = 1 Jahr, idempotent via
  osm_pro_grants). HINWEIS: is_premium/subscription direkt gesetzt — vor Prod
  mit Billing abgleichen.
- Native Attestierung/Sensoren: bewusst NICHT (iOS-App-Thema, nicht PWA).
2026-06-03 21:40:50 +02:00
10e39ed135 Karten-Ausbau (OSM), Forum-Erweiterung, UI-Komponenten, Refactor Tagebuch/Gassi (DRY), Landing/SEO — APP_VER 1155 2026-06-03 17:24:47 +02:00
c517c9281d Refactor: 1167 _esc() → UI.escape() in 36 Dateien, SW by-v1113
Bündel 1 aus dem Duplikat-Audit: existierende zentrale Helper nutzen
statt lokale Duplikate.

Pure Migration ohne neuen Code:
- 1167 _esc()-Aufrufe in 36 Page-Modulen migriert auf UI.escape()
- 24 lokale _esc/_escape-Definitionen entfernt
- lost.js hatte _escape() (Variante) — 17 Aufrufe ebenfalls migriert
- jobs.js + breeder.js: tote Alias-Wrapper entfernt

UI.escape() existierte schon — wurde nur überall lokal nochmal
implementiert. Funktional identisch (gleiche 4-replace-chain für
& < > ").

Tests 19/19 grün. Frontend-LOC um ~120 Zeilen reduziert.

Hinweis: _emptyState (7 Stellen) und _icon (8 Stellen) wurden NICHT
migriert — sie haben abweichende Signaturen von UI.emptyState({...})
bzw. UI.icon(name). Eigener Sprint nötig.
2026-05-27 10:15:33 +02:00
459cd425f2 Design-System Sprint A: utilities.css + 948 Inline-Styles → Utility-Klassen, SW by-v1102
PHASE 1 — Sofort-Cleanup ohne Risiko:
- Neue Datei utilities.css mit ~25 Klassen für häufige Kombinationen:
  * text-xs-muted, text-xs-secondary, text-sm-muted, text-sm-secondary
  * flex-gap-2/3, flex-col-gap-2/3/4, flex-center-gap-1/2/3
  * flex-between, flex-1-min, mb-1/3, mt-1/3
  * icon-xs/sm/md/lg, label-block, caption
- index.html bindet utilities.css ein
- mb-3/mt-3 ergänzt (waren in design-system.css unvollständig)

PHASE 2 — .by-tab Modifier für Vereinheitlichung:
- .by-tabs.grid (mit --tab-cols Variable für Admin/Health/etc.)
- .by-tabs.sticky (Desktop vertikale Tabs für Admin)
- .by-tabs.wrap (Zuchthunde, flex-wrap statt scroll)
- .by-tabs.separated (Sitting, mit eigenem Hintergrund + Border)

PHASE 3 — Inline-Style → Klassen-Migration (Python-Script):
- 948 Inline-Styles entfernt (5101 → 4153, -18%)
- 962 Migrationen über 47 Page-Dateien
- Top-Treffer: admin.js (180), health.js (67), dog-profile.js (67),
  litters.js (62), settings.js (61), zuchthunde.js (51)
- Patterns: text-muted, text-secondary, text-danger, text-xs-muted,
  text-sm-muted, grid-2 (Duplikat-Bug behoben!), flex-col-gap-3,
  p-3/4, mb-2/3/4, hidden, w-full, flex-1, ...
- Bewahrt bestehende class-Attribute (mergt korrekt)

Alle 19 Tests grün. Kein visueller Diff erwartet (gleiche Property-Werte).
2026-05-27 07:11:27 +02:00
cc4f030fd0 Feature: Hundesalons in der Karte, SW by-v1098
- OSM-Query 'hundesalon' nutzt shop=pet_grooming + craft=pet_grooming
- map.js: neuer Layer 'hundesalon' mit Schere-Icon (#EC4899 Pink),
  in Layer-Liste, TYPEN, OSM_LAYER_MAP und PIN_TYPES eingetragen
- User können selbst Hundesalons als POI anlegen
  (places.py TYPEN + osm.py ALLOWED_TYPES erweitert)
2026-05-26 21:13:16 +02:00
19640af288 Style: Marker + Cluster Rand Tactical-Olive statt Weiß
rgba(255,255,255,0.7/.8) → rgba(52,68,36,0.55/.65)
Dezentes Dunkeloliv auf allen Marker-Icons und Cluster-Bubbles.
SW by-v1025, APP_VER 1025
2026-05-16 11:35:01 +02:00
2cf0bc0d97 Fix: Karte CSS-Filter statt CartoDB Dark, Social Wrapper 860px
Karte Dark-Mode:
- CSS-Filter statt CartoDB Dark Matter (war zu dunkel)
  invert(93%) hue-rotate(180deg) brightness(0.88) contrast(0.88) saturate(0.85)
  Gleiche OSM-Tiles, Marker bleiben unbeeinflusst (tilePane separater Layer)
- Filter sofort bei Init + bei Theme-Wechsel via MutationObserver

Social:
- Outer Wrapper width:100%;max-width:860px;margin:0 auto
  Header-Karte und Tabs sind jetzt konsistent gleich breit
SW by-v1023, APP_VER 1023
2026-05-16 11:19:37 +02:00
721e630a34 Fix: Dark-Mode Karte + Badge-Farben + --c-bg-secondary
Karte:
- Dark-Mode: CartoDB Dark Matter Tiles statt OSM Standard
- MutationObserver + matchMedia watchee für Live-Theme-Wechsel
- _buildTileLayer() / _applyTileTheme() / _isDarkMode()

Badges litters.js:
- Hardgekodete dunkle Hintergründe → CSS-Klassen (badge-warning/-success/-muted)
- Funktioniert jetzt in Light + Dark Mode korrekt

movies.css:
- .movie-tag-stirbt/.movie-tag-ueberlebt → CSS-Variablen (danger-/success-subtle)
- Kein weißer Hintergrund mehr in Dark Mode

--c-bg-secondary: Zoom-Control 30px bleiben aus dem letzten Commit
SW by-v1022, APP_VER 1022
2026-05-16 11:11:09 +02:00
e44414015a Fix: Karte — Zoom-Ausrichtung, 'Z14' kürzer, Marker-Count ausgeblendet
- leaflet-top padding-top 28→33px (Zoom-Buttons mittig zu 2 Filter-Reihen)
- Zoom-Anzeige: 'Zoom 14 · ab 14: alle Layer' → 'Z14' (Hinweis als title)
- #map-osm-status ausgeblendet (Marker-Anzahl nimmt Platz von Wetter etc.)
- components.css ?v=1012, SW by-v1019, APP_VER 1019
2026-05-16 10:39:12 +02:00
562d64979f Fix: Karte — Filter-Button mit Label, kürzere Chip-Texte
- #map-legend-all: 'Filter' Text neben dem List-Icon
- 'Hundefreundl. Café/Restaurant' → 'Café & Restaurant'
- 'Hundefreundl. Hotel' → 'Hotel'
- .map-legend-all: padding angepasst für Text-Label
- components.css ?v=1011, SW by-v1018, APP_VER 1018
2026-05-16 10:32:11 +02:00
53fcb61933 Offline-Fallbacks für diary, poison, map + SW-Erweiterung
- sw.js: /api/places, /api/breeder/map-markers, /api/gassi-zeiten in _CACHEABLE_GET; /api/lost/report und /api/walks in _QUEUEABLE
- diary.js: localStorage-Cache pro Hund, Fallback bei Offline mit Toast
- poison.js: localStorage-Cache, Fallback bei Offline mit Toast (sicherheitsrelevant)
- map.js: POI-Cache (places/poison/breeders) in localStorage, Offline-Toast + Fallback auf gecachte Daten
2026-05-15 17:02:26 +02:00
781e3383bd Fix: Karte lädt wieder + safe_media_path + Foto-Löschung (SW by-v932)
- map.js: appState→_appState im Template, addEventListener mit ?. (kein Crash ohne Buttons)
- media_utils.py: safe_media_path lstrip-Bug — 'dogs/' wurde zu 'ogs/' gekürzt;
  jetzt korrekte removeprefix-Logik → Altes Hundeprofil-Foto wird jetzt wirklich gelöscht
2026-05-14 11:58:00 +02:00
e7b6cb3c33 Fix: Karte — Regenradar- und Temperatur-FABs nur für Pro sichtbar (SW by-v931) 2026-05-14 11:50:43 +02:00
8f39c22a7f Fix: Wake Lock Re-Acquire nach unfreiwilligem Release + visibilitychange-Handler (routes.js + map.js, SW by-v885) 2026-05-12 18:03:35 +02:00
b818f85f36 Feature: Aktive Erinnerungen, Versicherung, Verhaltensprotokoll, Hundefreundliche Orte (SW by-v874) 2026-05-11 22:24:42 +02:00
bda61a0e40 Feature: Trauer-Feature, Futter-Verträglichkeit, Multi-Hund-Fixes, Wetter-Ort (Sprint 47)
- dog-profile.js: Verstorben-Button, Gedenkseite, KI-Abschiedstext
- database.py: futter_eintraege/reaktionen, route_dogs, exercise_progress.dog_id
- routes/ernaehrung.py: Futter-Verträglichkeit mit 20 Reaktionstypen + Analyse
- routes/routen.py: route_dogs Many-to-Many, Routen editierbar
- routes/training.py: exercise_progress per dog_id
- routes/ki.py: /ki/abschied Trauer-KI
- weather.py: Nominatim Ortsname parallel geladen
- ui.js: dogChip/bindDogChip, visualViewport-Modal
- api.js: gedenken, gedenkseite, futter-Methoden, route_dogs
- worlds.js: Ortsname im Wetter-Chip
- uebungen.js: _progressLoaded-Flag, dog-spezifischer Fortschritt
- trainingsplaene.js: dog_id Unterstützung
- diary.js/health.js: P-Badge Cleanup
- map.js: Wetter-Ort-Anzeige entfernt
- wetter.js: Ort in Wetter-Detail
2026-05-11 19:28:38 +02:00
79fa5684b9 Feature+Fix: Referral-Admin, Pro-Gates, Karten-Layer, onDogChange, Staging-Media (SW by-v855)
Features:
- Admin: Referral-Tab (Virality Factor, Top-Werber, letzte Einladungen)
- Karte: Regenradar (RainViewer, zoom→7, color=4), Temperatur-Layer (OWM) mit Zahlen-Grid + Legende
- Wetter-Chip: Umschwung-Warnung bei ≥40%-Sprung in Niederschlagswahrscheinlichkeit
- Freundschaftsanfragen: Accept/Decline direkt in Notifications (kein Pro nötig)
- Freunde-Seite für Standard-User freigeschaltet

Pro-Gates:
- KI-Trainer, Routenvorschläge, Regenradar, Temperatur-Layer jetzt Pro-Feature
- Pro-Badge (P) auf Chips für Admins/Mods in allen Welten + Welten-einrichten
- Oranger Banner auf Pro-Seiten für Admin/Mod/Manager

Bugfixes:
- onDogChange: uebungen.js (Cache leeren + _render), trainingsplaene.js (war leer)
- robots.txt vereinfacht (nur Disallow, kein Allow-Durcheinander)
- Hintergrund-Foto: Querformat-Filter korrigiert (kein Fallback auf Hochformat)
- Staging Media: FileResponse mit korrektem MIME-Type, no-cache statt immutable
- Staging Docker: MEDIA_DIR=/data/media + /prod-media:ro Fallback-Handler
- Staging-Fix: Bild-Upload auf zweitem Hund (war Read-only file system)
2026-05-11 17:23:29 +02:00
70af387147 Feature: User-Feedback, Regen-Uhrzeit im Wetter-Chip, Admin-Karten klickbar (SW by-v833)
- Feedback-Modal im Settings (Kategorie + Text → E-Mail an support@banyaro.app)
- Wetter-Chip (Karte + Gassi-Score): zeigt nächste Regenstunde ab ≥20% Wahrscheinlichkeit
- Gassi-Score-Chip: zweizeilige Wetter-Info, linksbündig, volle Chipbreite
- Admin-Übersicht: Stat-Karten anklickbar → navigiert direkt zum jeweiligen Tab
- ui.js: visualViewport-Listener hebt Modal über Tastatur (alle Modals)
- api.js: Pydantic v2 Array-Detail korrekt als Fehlermeldung extrahiert
- map.js: Wetter-Fallback über watchPosition wenn getCurrentPosition scheitert
- Update-Loop-Fix: index.html ?v= synchron mit APP_VER halten (alle 4 Stellen)
2026-05-10 12:52:55 +02:00
55069d246b Feature: Welten-Onboarding, Wetter-Motivation, UX-Fixes (SW by-v715)
Welten (worlds.js):
- Swipe-Hints beim ersten Öffnen (JETZT ← → WELT animiert, einmalig)
- Kein-Hund-Onboarding: Feature-Preview-Grid statt leerer Karte
- Hintergrund-Foto-Hint: Kamera-Karte wenn noch kein Tagebuchfoto
- worlds-back: navigiert zu Welcome wenn kein User eingeloggt
- Nach Logout: worlds-back Button sofort ausgeblendet

Wetter (wetter.js):
- Standort-Fehlerseite zu Motivations-Seite umgebaut
- Feature-Preview: Gassi-Score, 7-Tage, Regenradar, Rekorde
- CTA: Standort freigeben + Registrieren (nur für Gäste)

Settings (settings.js):
- Logo in Auth-Form: display:block + margin:0 auto zentriert
- Header bleibt sichtbar (FAB/Zurück-Navigation funktioniert)

Jobs (jobs.js):
- 2-Spalten-Grid auf Mobile: auto-fit statt festes 1fr 1fr
- Kein doppeltes Padding im Wrapper

Backend:
- weather.py, achievements.py: diary JOIN fix (d.user_id → dogs JOIN)
- Neue Wetter-Badges: wetter_tapfer, jahreszeiten, schnee
- Ernährungs-, Reise-, Ausgaben-Seite: diverse UX-Verbesserungen
- Presse-Seite erweitert
- Ban Yaro Foto-Assets (WebP + HIRES JPG)
2026-05-05 17:32:03 +02:00