- Der Service-Worker-Cache wurde nie invalidiert: die letzte Runde hat
offline.html in allen vier Zielen ersetzt, sw.js aber nicht angefasst.
Ein Browser installiert einen Service Worker nur neu, wenn sich sw.js
selbst aendert — bestehende Installationen haetten die alte, englische,
ungestaltete Offline-Seite dauerhaft behalten. CACHE_NAME hochgezaehlt.
Dabei faengt der Install jetzt einen fehlgeschlagenen Abruf ab; vorher
wurde bei einem Fehler der ganze Service Worker nicht aktiv.
- Die Leaflet-Marker kamen von cdnjs.cloudflare.com — in einer PWA, die im
Wald ohne Empfang benutzt wird, waren sie damit kaputt, und die IP jedes
Besuchers ging an ein fremdes CDN. Verwiesen wurde ausserdem auf Leaflet
1.7.1 bei installiertem 1.9.4. Die Bilder liegen im Paket und werden jetzt
gebuendelt; Vite bettet sie als data:-URI ein (zusammen ~4 KB).
- Die Adress-Autovervollstaendigung im Benutzerformular rief Nominatim
weiterhin direkt aus dem Browser auf, obwohl d9fecb6 dafuer einen Proxy
eingefuehrt hat — nur die PLZ-Suche nutzte ihn. Neu: searchAddresses() in
utils/geocode.js (teilt Wartezeit und Cache mit geocodeAddress) plus
GET /api/public/geocode/search unter demselben geocodeLimiter. Die Antwort
ist auf die Felder beschraenkt, die das Formular liest. Der Debounce steigt
von 400 auf 600 ms, weil die Anfragen jetzt durch die serverseitige
Mindestwartezeit laufen.
Geprueft: im Bundle kein cdnjs und kein nominatim mehr; der neue Endpunkt
liefert Treffer mit den erwarteten Feldern, zu kurze Begriffe 400.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ergänzt die Absicherung aus 8384ad9/d9fecb6 um die Lücken, die dort offen
geblieben sind.
- authenticateToken prüft jetzt die Rolle. Der C-01-Fix vergleicht nur
`decoded.app`, und genau den Claim tragen Handler-Tokens nicht
({ id, role: 'handler' }) – `if (decoded.app && ...)` lief bei ihnen
also ins Leere. Ein eingeloggter Hundeführer konnte seinen Bearer-Token
weiterhin gegen /api/users, /api/config und /api/audit-logs schicken und
hatte volle Admin-Rechte. Admin-Tokens tragen zusätzlich role: 'admin';
Tokens ohne role bleiben bis zum Ablauf gültig, niemand wird ausgeloggt.
- Logout wird als LOGOUT protokolliert statt als LOGIN, und die Route
liest den Benutzernamen über attachUserIfPresent (neu). Vorher lag gar
keine Auth-Middleware auf /logout, der Eintrag lautete immer "unknown".
- forgotPassword sucht case-insensitive wie der Login. Ein als "Thorsten"
angelegtes Konto konnte sich als "thorsten" anmelden, aber kein Passwort
zurücksetzen.
- CSV-Export escaped führende =, +, -, @ (neues utils/csv.js, von
userController und auditController gemeinsam genutzt). Ein Name wie
=HYPERLINK(...) wurde sonst von Excel als Formel ausgeführt.
- Massen-Operationen filtern soft-deleted Einträge; der pre(/^find/)-Hook
des Modells greift bei updateMany nicht.
- Die öffentliche Liste liefert wieder phone, landline, address und photo.
Die UI zeigt diese Felder seit jeher an, die API lieferte sie seit dem
PII-Commit nicht mehr – Anrufen war öffentlich nicht mehr möglich.
E-Mail, Hashes und Invite-Felder bleiben ausgeschlossen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Docker: bind all backend/frontend ports to 127.0.0.1 only (was 0.0.0.0)
- Docker: add shared jagd-network; portal uses container names instead of host ports
- Fix: set-password endpoints now require valid invite token (drohnenfuehrer, stoeberhunde)
- Fix: auth cookie secure flag enabled in production
- Fix: password reset token no longer logged in production
- Add: inviteLimiter (10/15min) on set-password routes in all three apps
- Add: importUsers capped at 500 entries to prevent DoS
- Refactor: rename handler -> drohnenfuehrer/stoeberhundefuehrer across all apps