Zweiter, gleichwertiger Login-Weg neben Passwort — nutzt die zentrale
awlauth-WebAuthn-JS (/custom/awlauth/js/awlauth-webauthn.js), analog zum
Stundenzettel-Pilot.
- Script-Einbindung nach app.js in index.php (same-origin, /custom/awlauth).
- Neuer Button "Mit Fingerabdruck anmelden" im Login-Template (app.js),
type="button", versteckt bis awlauthWebAuthn.isSupported() true ist.
- Klick-Handler: awlauthWebAuthn.login() -> bei Erfolg Profil aus dem
Login-Result in idb('user') ablegen (wie api.login es tut, sonst zeigt
Einstellungen nach reinem Passkey-Login "Unbekannt") -> showToast +
router.go('#/orders') wie der Passwort-Login-Pfad.
- Passkey ist domainweit (RP awl.data-it-solution.de): ein z.B. ueber
Stundenzettel registrierter Passkey funktioniert hier direkt mit.
Lokal verifiziert: php -l / node --check sauber, Playwright + Virtual-
Authenticator (CDP) — Button korrekt sichtbar/gestylt (eigene Dark-Palette),
Klick loest webauthn_login_options.php (200) aus, Fehlerpfad reaktiviert den
Button, bleibt auf #/login, 0 Console-Errors. Adversarialer Code-Review fand
1 kosmetischen Befund (fehlendes idb-Profil) — bereits gefixt.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Der FAB hing als Kind im #app Flex-Layout (display:flex, column) und hat
die bottom-nav nach unten gedrängt. Jetzt sitzt er auf Body-Ebene,
beeinflusst kein Flex mehr. Zusätzlich hat #main padding-bottom:90px
damit der letzte Listeneintrag nicht vom FAB verdeckt wird.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- FAB unten rechts (halbtransparent) öffnet Fullscreen-Modal zur
Auftrags-Anlage: Kundensuche mit Debounce und "Zuletzt verwendet"-
Quick-Pick aus IndexedDB → Anzeige der übernommenen Defaults →
Titel + optional Kunden-Ref → direkter Sprung auf #/orders/<id>
wo die Fotos aufgenommen werden können.
- appBoot() preloadet das JWT aktiv aus IndexedDB bevor der Router
läuft — fixt "nach App-Neustart immer wieder einloggen müssen".
- setNav() steuert zusätzlich die FAB-Sichtbarkeit mit.
- api.createOrder() als neuer Wrapper für POST /orders.php?action=create.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5.4 Mess-Werkzeug mit Skala-Kalibrierung:
- Zwei neue Sketch-Tools: 📏⚙ Kalibrieren + 📏 Messen
- Kalibrieren: 2 Punkte ziehen → reale Länge eingeben (cm/m/mm)
- Messen: 2 Punkte ziehen → Live-Distanz-Label mit berechnetem Wert
- pxPerUnit + unit werden im State gehalten, Linie im Canvas gezeichnet
5.9 Materialliste pro Auftrag:
- 📦 Materialliste-Button im Auftrags-Detail
- Modal: Bezeichnung + Menge + Einheit (Stk/m/m²/kg/l/Set/Pa/h) + Notiz
- Live-Liste mit Löschen pro Eintrag
5.8 Tages-Baustellen-Map:
- Neuer Bottom-Nav-Tab ☀️ Heute (ganz links)
- Filtert Aufträge nach heutigem Datum
- Route-Button öffnet Google Maps mit allen heutigen Adressen als Waypoints
- Darunter noch die offenen Aufträge als Backup
4.d Benachrichtigungen via ntfy (statt VAPID):
- Settings → Benachrichtigungen: ntfy-Server + Topic
- EventSource auf /topic/sse → native Browser-Notifications
- Test-Nachricht-Button sendet POST an das Topic
- Auto-Reconnect bei Fehlern nach 10s
- Auto-Start beim Boot wenn Topic gesetzt und Permission granted
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
Kundenkarten:
- Neuer Bottom-Nav Eintrag '👥 Kunden'
- /customers Route: Liste mit Suche, gefiltert über api/customers.php
- /customers/:id Route: Stammdaten mit Click-to-Call, Click-to-Mail,
Google-Maps-Route-Button, Listen für Aufträge/Berichte/Rechnungen
mit Mini-Card-Layout
- Mini-Cards navigieren zum jeweiligen Auftrag/Bericht
- formatDate + formatEur Helper (de-DE Locale)
Unterschriften-Härtung (Signature-Modal):
- Pflicht-Input für Signer-Name
- GPS-Checkbox (default an) — fragt navigator.geolocation ab
- Rechtstext als Hinweis
- Beim Save: Name + GPS werden an api.uploadSignature übergeben
- Server brennt Metadaten, Hash und GPS in die PNG ein
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
Chrome zeigt 'App installieren' im Menü erst nach mehrmaligem Besuch
mit User-Interaktion. Das ist die sog. Site-Engagement-Heuristik —
keine technische Voraussetzung, sondern UX-Gate.
Workaround: beforeinstallprompt-Event abfangen und manuell auslösen.
- 📲 Install-Button in Topbar (standardmäßig versteckt)
- Bei beforeinstallprompt: Event speichern, Button anzeigen
- Klick → prompt() aufrufen → Install-Dialog öffnet sich
- appinstalled-Event: Button wieder verstecken
- iOS-Fallback: Hinweis zum manuellen 'Zum Home-Bildschirm'
Damit ist die Install-Funktion jederzeit sichtbar und nutzbar,
unabhängig davon wie oft der User die Seite vorher besucht hat.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
Das bisherige 'CACHE = baustelle-vN' Pattern erforderte, dass ich bei
jeder Änderung drei Stellen synchron halte (sw.js, index.html ?v=,
manifest). Eddy hat klargestellt dass das nicht akzeptabel ist.
Fix nach KB #201 Pattern (referenz: dolibarr.stundenzettel v2.2.0):
1. index.html → index.php
PHP berechnet bei jedem Request filemtime() von app.css, app.js,
lib/*.js, manifest.webmanifest. Die mtimes kommen automatisch
beim Deploy (rsync preserviert sie default) und werden als ?v=
an alle Asset-URLs gehängt.
2. sw.js liest Version aus eigener URL-Query:
const SW_VERSION = (new URL(self.location.href)).searchParams.get('v')
const CACHE = 'baustelle-' + SW_VERSION
activate() löscht alle caches die mit 'baustelle-' anfangen aber
nicht der aktuelle sind.
3. Client-Registration mit Auto-Update:
- setInterval 60s reg.update()
- visibilitychange-Listener für Tab-Fokus
- updatefound → SKIP_WAITING postMessage
- controllerchange → einmaliger location.reload
4. SHELL pre-cache enthält nur statische Dateien (index.php, share.html,
icons). CSS/JS werden beim ersten fetch dynamisch gecached — so
gibt es keinen Mix zwischen alten und neuen ?v= Versionen.
5. manifest.webmanifest start_url auf /custom/baustelle/index.php
Ergebnis: Ich deploye → mtime ändert sich → neue URLs → Browser holt
frische Files → SW aktiviert automatisch beim nächsten Tab-Fokus.
Nie wieder manuelles Hochzählen.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]