- Neue Seite #breeder-dashboard (Welten-Chip 'Züchter' role:breeder in HUND,
ersetzt die Einzel-Chips Zuchtkartei + Wurfverw.; beide FABs wandern an den
neuen Chip; Läufigkeit bleibt eigener Chip in HUND, Rene-Vorgabe):
Zwinger-Karte (Name, verifiziert-Badge, Profil-Editor), Wurfverwaltung mit
Wurf-Anzahl, Zuchtkartei mit Hunde-Anzahl. Einzelseiten bleiben erreichbar.
- Settings: Partner-Karte entfernt — der 🤝-Welten-Chip ist der Einstieg.
- Admin 'Aktive Codes': 👥 zeigt jetzt ALLE Einlösungen eines Codes mit
Kanal-Badge (QR #seq aus Kontingent vs. Link/manuell), Datum und
Bestätigt-Status — Endpoint /admin/partner/codes/{id}/registrations.
Suite: 55 passed.
1. QR-URL verrät den Code nicht mehr: /q/{token} → /?qr=TOKEN (vorher stand
der tippbare Code in der Adresszeile jedes Scanners). Registrierung löst
den Code server-seitig aus dem Token auf (auch ohne ref_code).
2. Notbremse: partner_codes.active — Admin kann Codes pausieren (Einlösung
gesperrt, Info-Endpoint 404, Historie/QR-Kontingente bleiben) und
reaktivieren. UI: ⏸/▶-Toggle + pausiert-Badge in der Codes-Tabelle.
3. max_uses im Anlege-Formular standardmäßig 50 statt unbegrenzt.
Tests: QR-only-Registrierung, Pause→keine Einlösung→Reaktivierung,
Redirect ohne Klartext-Code. Suite: 54 passed.
Code-Karte: nur noch Registrierungen gesamt + diesen Monat, mit Hinweis dass
alle Wege zählen (Link, eingetippter Code, QR) — erklärt warum Code-Zahl >
QR-Zahl sein kann. QR-Kontingente: 'X von Y genutzt' statt Scans/Registr./
Versuche; Einzel-Code-Liste nur noch ● genutzt (N×) / ○ frei.
Admin behält die Detail-Sicht (Scans, Versuche, Account-Liste).
Rene: QR-Stats gehören nicht ins öffentliche Profil, eigene Seite fehlte.
Neue Seite 'Partner-Bereich' (Welten-Chip 🤝 zwischen Moderation und Admin,
role:partner — sichtbar für is_partner + Admin; _mergeDefaults reicht den
Chip an bestehende Welt-Configs nach):
- Einladungscode groß + Link-kopieren-Button
- Kacheln: Registrierungen gesamt / diesen Monat / unbestätigt
- QR-Kontingente mit Einzel-Code-Status (aus partner-profil.js hierher verschoben)
- Profil-Status-Karte (Entwurf/Prüfung/frei) mit Sprung zum Editor
Backend: GET /partner/my-stats (Codes mit Zahlen + Profil-Status).
Settings-Partner-Karte: zwei Buttons (Partner-Bereich primär, Profil sekundär);
Dank-Mail-CTA zeigt auf #partner-dashboard. Suite: 52 passed.
Trigger ist die E-Mail-Bestätigung des Geworbenen (nicht die rohe
Registrierung — konsistent zur Registrierungen/Versuche-Zählung) und nur
beim ersten Verify (Doppelklick auf den Link = keine zweite Mail).
Inhalt: Dank + Bilanz (bestätigte Registrierungen gesamt + diesen Monat),
bei QR-Herkunft der Sticker (#seq, Kontingent-Label), bei Gründer-Codes
die offenen Plätze; CTA zur Partner-Statistik. Versand über das
partner@-Konto, Fehler landen in failed_emails (context partner_thank_you).
Env-Fund dabei: SMTP_PASS fehlte in BEIDEN .env (nur SMTP_SUPPORT_PASS da)
— Partner-Konto-Versand wäre fehlgeschlagen; auf der DS ergänzt.
Test: Mail-Capture per monkeypatch, prüft Statistik + Sticker-Nr +
Einmaligkeit. Suite grün.
Rene: 'wo sieht der Partner welche QR-Codes er hat und wieviele verbraucht
sind?' Neu in 'Meine QR-Codes':
- Kontingent-Zeile zeigt 'X/Y verbraucht' (Codes mit ≥1 bestätigter Registrierung)
- Listen-Button klappt Einzel-Codes auf: #Nr, Kurz-URL, Scans und Status
● verbraucht (mit Registrierungs-Datum) / ◐ gescannt / ○ frei
- Endpoint /partner/my-qr/{id}/codes (owner-gated, keine personenbezogenen
Daten — nur Zähler + Zeitstempel)
Rene: Statistik zählte alles in einen Topf (3 statt 2) und zeigte nicht,
WER sich registriert hat. Jetzt:
- registrations = email_verified=1, attempts = unbestätigte Versuche —
Versuche werden bei späterer Bestätigung automatisch zu Registrierungen
- Admin: 👥-Button pro Kontingent klappt Account-Liste auf (Name, E-Mail,
Datum, ✓ bestätigt/⏳ Versuch, Sticker-Nr #seq) — lazy geladen, admin-only
(personenbezogene Daten); Partner sehen weiter nur Zahlen (Registr. +N)
- Test deckt Versuch→Bestätigung-Übergang und Detail-Endpoint ab
Rene: 'kann nichts prüfen — ich würde den Output erwarten, der auf der
Partner-Seite zu sehen sein wird'. Freigabe-Zeile hat jetzt einen
Vorschau-Toggle, der die Karte 1:1 wie auf #partner rendert (Logo/Initial,
Slogan, Website, Instagram, Bio, Medien-Grid).
Mail-Ursache gefunden: Staging-.env fehlte SMTP_SUPPORT_USER → Code-Default
support@banyaro.de → 535 Auth-Fehler, vom Silent-Catch verschluckt.
.env ergänzt (partner@banyaro.app wie Prod); Submit loggt SMTP-Fehler jetzt
über _log_smtp_failure in failed_emails statt still zu schlucken.
Rene reichte ein Partner-Profil ein und sah als Admin nirgends einen Hinweis:
1. Action-Items kannten Partner-Profile nicht — partner_profiles_pending
(submitted_at gesetzt, approved=0) jetzt im Endpoint + Chip im Admin-Kopf
(Klick -> Partner-Tab). Test ergänzt (7 passed).
2. ADMIN_EMAIL fehlte in BEIDEN .env auf der DS (Prod+Staging) — damit wurden
auch Upgrade-Anfragen-Mails still verschluckt (bekanntes Silent-Skip-Muster).
Auf der DS nachgetragen; greift je beim nächsten Deploy.
Logo-Pfad akzeptierte .heic, öffnete aber direkt mit Pillow (kein HEIF-Opener)
— iPhone-Fotos schlugen fehl. Jetzt convert_media-Vorstufe wie im Foto-Pfad.
Fehlgeschlagene Konvertierungen (HEIC→JPEG, MOV→MP4) brechen mit klarer
Meldung ab statt rohe Dateien zu speichern (MOV wäre als <img> kaputt gerendert).
Test: echter HEIC-Roundtrip (pillow-heif) für Logo + Foto.
Rene: 'Tagebuch Kalenderansicht/Karte nicht mehr da' — Root-Cause: 459cd42
ersetzte style="display:none" durch class="hidden", aber die Show-Pfade
setzten weiter style.display. .hidden hat !important und gewinnt immer
(gleiche Klasse wie Filter-Panel-Hotfix v1242). Prod-Logs bewiesen: kein
einziger /diary/calendar- oder /locations-Request kam je an.
Unsichtbar seit v1102, jetzt per classList gefixt:
- diary: Stats-Bar mit View-Switcher (Liste/Medien/Kalender/Karte) + Medien-Grid neuer Eintrag
- health: KI-Tierarzt-Ergebnis erschien nie
- walks: Challenge-/Stamm-Gassi-Tabs leer
- welcome: iOS-Panel der Desktop-Install-Anleitung
- wiki: Fotos-Mod-Badge + Foto-Fallback (via app.js data-fb show-el/sibling-Handler)
- routes: Filter-Badge; breeder: Fotos-Section
Zweite Fehlerklasse aus demselben Sprint: doppelte class-Attribute
(class="x" id=… class="hidden") — Browser verwirft das zweite Attribut.
87 Vorkommen in 23 Dateien zusammengeführt; betroffene Show/Hide-Pfade
(ev-map, rk-mine/nearby-group, chat-partner-dot, eh-panel, zh-section)
auf classList umgestellt.
Praxistest Rene (Gassirunde Siegenhofen, Loop Start=Ende): _closestIdx suchte
GLOBAL -> am Start war der END-Index genauso nah -> Fortschritt sprang ans
Track-Ende: nie Abbiege-Bellen (keine Turns mehr 'vor' einem), done-Linie
malte sofort alles gruen, 99%.
- _closestIdx: Fenster um den aktuellen Index (-15/+80), global nur beim
ersten Fix (mit Start-Praeferenz bei Quasi-Gleichstand <25m) oder wenn
verloren (>300m). Simulation auf der echten Route: 13/13 Turns feuern
bei 41-49m Vorlauf.
- Gelaufener Weg als BREADCRUMB: gruen = auf der Route, rot = daneben
(Segment-Wechsel nahtlos); done-Linie (Track-Slice-Malen) entfernt —
nie gelaufene Abschnitte bleiben jetzt orange
- Off-Route-Schwelle 50->35m (Klaeffen kam ~5m zu spaet), Abbiege-Ansage 45->50m
Bump v1250
- Standort-Punkt zeigt jetzt einen Kompass-KEGEL (wie Google Maps): CSS-Kegel
im loc-icon (GL + Leaflet), deviceorientation mit webkitCompassHeading (iOS)
bzw. 360-alpha (Android), Glaettung ueber kuerzesten Winkelweg, rAF-throttled.
iOS-Permission via User-Geste (Follow-/Standort-Button startet den Kompass).
- Follow pant nur noch bei brauchbarem Fix (accuracy < 75m) — ungenaue
Positionen liessen die Karte zappeln; GPS-Fixes frischer (maximumAge 2s
statt 5s). Marker aktualisiert weiterhin jeden Fix.
Bump v1249
Rene: aktiviertes Crosshair pannt alle paar Sekunden -> jedes moveend
startete den Scan. Scans aus KARTENBEWEGUNG laufen jetzt erst, wenn sich
das Zentrum >= 20% der Viewport-Breite bewegt hat oder der Zoom wechselt
(bei Z16 ~ alle 100-150m Fussweg). Alle anderen Trigger (Marker
gespeichert, Layer-Toggle, Retry, Init, Scan-Queue) ungebremst.
Bump v1247
position:fixed + safe-area (+70px) wie das Offline-Icon (+110px) statt
absolute im Karten-Container — sitzt jetzt exakt in der Luecke; Offline-
Puls bleibt unveraendert an seinem Platz.
Bump v1246
Wunsch Rene: sichtbarer Follow-Schalter direkt auf der Karte statt nur ueber
das Speed-Dial. Crosshair links unter den Zoom-Reglern (unterhalb des
Offline-Puls-Icons): Tipp = zentrieren + folgen (Button farbig), Karte
ziehen = pausiert (grau). Synchron mit Standort-Speed-Dial-Button und
Aufzeichnungs-Start (beide aktivieren Follow ebenfalls).
Bump v1245
HTMLAudio+preload laedt auf iOS lazy (canplaythrough feuert nie) und verlor
beim ersten Einschalten das Rennen gegen den Probe-Wuff -> Game-Boy-Fallback.
Jetzt: fetch + decodeAudioData in den bestehenden AudioContext (praezises
Timing via BufferSource, offline via SW-Precache); Probe-Wuff 450ms verzoegert.
Synthese bleibt Fallback bei 404/Decode-Fehler.
Bump v1244
Kaputt seit 27a3f95 (2026-06-05, 'Filter standardmaessig zu' setzte die
hidden-KLASSE ins Markup, der Toggle blieb aber auf style.display='').
.hidden = display:none !important (design-system.css) -> Klick wirkte nie.
Import funktionierte weiter (Label+File-Input nativ) — dadurch gemeldet
als 'Filter geht nicht mehr' (Angie + Rene).
Fix: classList.toggle('hidden') im Toggle + konsistent im Suggest-Tab.
Bump v1242
- NavSound (routes.js): WebAudio-Wuff-Synthese (Saegezahn-Sweep + Tiefpass,
kein Asset, laeuft offline); echte Aufnahmen unter /sounds/wuff.mp3 +
klaeffen.mp3 (z.B. von Yaro) werden automatisch bevorzugt
- Abbiege-Erkennung: Turns einmalig aus dem Track (Peilung ueber 15-m-
Stuetzpunkte gegen GPS-Zickzack, >=40 Grad), Ansage bei <=45 m davor,
einmal pro Abbiegepunkt
- Falscher Weg (>50 m, bestehende Warnung): Klaeffen beim Abkommen +
Erinnerung alle 30 s; zurueck auf Route reset
- Toggle im Navi-Header (Lautsprecher-Icon, by_nav_sound, Default AN),
iOS-Audio-Unlock beim Navi-Start + Toggle (Probe-Wuff als Bestaetigung)
Bump v1241
Vorher zaehlte NUR eine aufgezeichnete Tour der letzten 48h (<=50m am POI,
>=2 Punkte) — die aktuelle Geraeteposition floss gar nicht ein.
- DogFriendlyIn: optional user_lat/user_lon (Frontend schickt _userPos mit)
- Beleg-Weg a): Geraetestandort <= 75m am POI (50m Radius + GPS-Toleranz)
-> route_id=None markiert Live-Beleg; Weg b) Tour-Beleg unveraendert
- Fehlermeldung nennt jetzt beide Wege (hin gehen ODER Standort aktivieren)
- pytest 39 passed
Bump v1239
- MapGLMini-Polyline hatte KEIN addLatLng (nur setLatLngs) -> TypeError im
Rec-Overlay: Strecke unsichtbar, Marker fror ein, kein Folgen. Facade
ergaenzt (Leaflet-kompatibel).
- Rec-Overlay (routes.js): Follow-Mode default AN — Karte wandert mit dem
Standort, Drag pausiert, Crosshair-Button (unten rechts) reaktiviert;
erster Fix setzt Zoom 16, danach bleibt der Zoom erhalten
- Zentrale Karte (map.js): Standort-Button aktiviert Follow (+Toast),
dragstart beendet es (beide Engines); GPS-Tracking folgt sanft (easeTo);
Aufzeichnung startet im Follow-Mode, _updateRecMap pant nur noch im Follow
Bump v1238
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
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
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
Geraetetest: Karte offline 'nicht verfuegbar' obwohl Pfote ready zeigte —
activate loeschte die alten Static-Caches, waehrend der neue erst im
Hintergrund befuellt wurde; der GL-Stack (maplibre/pmtiles/map-offline)
war zudem nie im Precache, nur nach erster Online-Kartenoeffnung.
- activate: _migrateStaticCaches uebernimmt fehlende Eintraege der alten
Caches unter nacktem Key (Online-Refresh ueberschreibt sie sauber),
DANN erst loeschen
- PRIORITY_PAGES + GL-Karten-Stack (maplibre-gl.js/.css, pmtiles,
map-gl-style, map-offline, map-gl-markers, map-gl-mini)
- generischer Cache-First-Pfad: ignoreSearch-Fallback fuer eigene /js/+/css/
(?v=APP_VER zeigt sonst am Carry-Over/bare-Bestand vorbei)
Bump v1233
Bei schwachem Empfang blieb die App beim Start SEHR LANGE weiss: CSS +
Kern-JS + index.html waren Network-First OHNE Timeout — der Cache griff
nur bei hartem Fetch-Fehler, nicht bei troepfelnder Verbindung.
Jetzt: Promise.race(Netz, 2,5s) -> Cache-Fallback (stale-while-revalidate,
Netz aktualisiert den Cache im Hintergrund weiter). Versions-Updates laufen
weiter ueber x-app-version + controllerchange.
Bump v1232
- 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
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
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