Eddy: „ja mach die Leiste unten mal fest". Sie stand seit v1.0.0 am
Seitenende — in einem Auftrag unter allen Fotos und Dokumenten, also
praktisch nie im Bild.
- #bottom-nav: position sticky, bottom 0, feste Höhe --nav-h (56 px).
- „Geteiltes ablegen" klebt genau darüber, der FAB sitzt darüber.
- Banner mit Teilen-Symbol statt Emoji und „2 Fotos und 1 Video"
statt „3 Bilder".
Im Android-Emulator gemessen: Leiste oben wie gescrollt am Rand,
Banner und FAB ohne Überlappung.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eddy: „im Auftrag … die Symbole alle linksbündig" — die farbigen Kreise
stehen in einer Spalte, der Text beginnt immer an derselben Stelle.
Gilt für alle Knöpfe mit Symbol; der kleine „Auswählen"-Knopf bleibt mittig.
Im Android-Emulator angesehen, Eddy: „lass das mal so".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eddy: „so dass es gut aussieht", zu rein weißen Symbolen dann
„viel zu schlicht". Emojis erscheinen je nach Handy als Kästchen.
- icon() in app.js (Material-Symbole), Farbe je Symbol in app.css
(.ikon-<name>): große Knöpfe = weißes Symbol im farbigen runden
Feld (Kamera blau, Galerie grün, Sprachnotiz rot, Notizen gelb,
Material orange, Bericht lila, Lieferungen türkis …), kleine
Knöpfe = farbiges Symbol (Teilen blau, Löschen rot, Stift/Blitz/
Hilfe gelb, Download/Telefon grün).
- Untere Leiste: farbiges Symbol über dem Wort, Heute als Sonne,
Zahnrad heißt „Einstellungen".
- Titel und Überschriften ohne Emoji; Telefonnummer lesbar.
- .icon-btn[hidden] bleibt versteckt (inline-flex hätte hidden ausgehebelt).
Im Android-Emulator angesehen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eddy: „Bei Fotos aufnehmen auch Videos unterstützen bitte".
- Kamera: Umschalter Foto | Video, roter Aufnahmeknopf, Laufzeit mit
Höchstlänge (5 min bzw. passend zur Servergrenze), Ton, Licht/Zoom/
Antippen-Fokus auch beim Filmen; MP4 (H.264/AAC), sonst WebM.
Schließen oder App-Wechsel während der Aufnahme sichert das Video.
- Warteschlange: Videos wie Fotos (Persist-First). Gesichert wird der
Blob statt eines ArrayBuffers; Zeitlimit und Lease wachsen mit der
Größe (api.js/sw.js gleiche Formel); 413 → sofort Quarantäne.
- Auftrag: Abschnitt „Videos" mit erstem Bild, Player (spult per Range),
Teilen, Löschen; „Warten auf Upload" zeigt Videos mit.
- Galerie und Teilen nehmen Videos, zu große lehnt die App gleich ab.
- Überschriften fett in normaler Schreibweise statt Versalien.
- ROADMAP: Funkloch, Display aus, 10 Fotos aus der Galerie und
PDF-Zoom im Emulator geprüft und abgehakt.
Braucht Bericht 1.8.0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Zwei Finger im Sucher zoomen (nur wenn die Kamera Zoom meldet), Anzeige
„1×"/„2,5×" unten im Sucher, Antippen der Anzeige setzt auf 1× zurück.
Während der Geste geht immer nur ein Aufruf an die Kamera; das Ende
der Geste zählt nicht als Fokus-Tipp.
- Hinweis beim Öffnen: „Antippen stellt dort scharf · zwei Finger zoomen".
- Kein eigener Helligkeitsregler: Chrome setzt mit der Tippstelle auch
Belichtung und Weißabgleich (im Emulator gemessen).
Im Android-Emulator mit echter Zwei-Finger-Geste geprüft; das Foto bei
2,5× zeigt genau den Sucher-Ausschnitt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Im Android-Emulator (Chrome 153, echter Camera2-Weg, dumpsys media.camera)
gegengeprüft: Blitz Aus/Auto/An und Licht kommen richtig bei der Kamera an.
Beim Antippen-Fokus waren zwei Fehler:
- Chrome rechnet pointsOfInterest ungedreht auf den quer liegenden Sensor um,
das Sucherbild steht aber hochkant. Ein Tipp rechts unten landete an
falscher Stelle. sensorPunkt() dreht die Tippstelle jetzt in Sensorlage
zurück (hochkant, quer 90° und 270° gemessen).
- focusMode single-shot nimmt Chrome auf Android an, setzt es aber nicht um
(kein AF-Trigger). Der Hinweis „Fokus fest“ war damit falsch und ist weg;
Antippen = Dauer-Autofokus auf die Tippstelle.
Knopf „Kamera wechseln“: weißes Symbol statt 🔄-Emoji (blaues Kästchen),
nur sichtbar, wenn das Gerät mindestens zwei Kameras hat.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eddy: „beim Fotografieren kann man den Blitz nicht einstellen und den Fokus auch nicht".
Knopf oben schaltet reihum, was das Gerät meldet (fillLightMode über takePhoto, Dauerlicht über
torch); Auswahl bleibt gemerkt. Antippen stellt an der Stelle scharf (pointsOfInterest +
focusMode single-shot) und hält den Fokus, „Fokus fest · zurück auf Auto" löst ihn wieder.
Ohne gemeldete Fähigkeiten (Frontkamera, Tablet-Webcam) bleibt alles wie bisher.
Lokal mit nachgebildeter Kamera geprüft, Gegenprobe am Handy steht in ROADMAP Punkt 9.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eddy: der Knopf soll unten am Rand liegen und die Aufträge nicht
überdecken. Er steht jetzt in der App-Spalte direkt über der Navigation
(sticky am unteren Rand), der FAB rückt solange eine Leistenhöhe hoch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Gemeldet 18.09.2026: nach "Fertig" in der Kamera stand die App auf der
Auftragsliste, und im Auftrag war von den Fotos nichts zu sehen.
Ursache Rauswurf (Prod-Log 17.09., Auftrag 111): closeModal() ruft
history.back() (asynchron), direkt danach setzt router.go() den Hash.
Der Ruecksprung laeuft erst nach dem Hash-Wechsel und springt hinter
den neuen Eintrag zurueck - angezeigt wird der Auftrag, in der Adresse
steht '#/orders'. Das naechste router.navigate() (Kamera "Fertig")
zeichnet dann die Liste. Betraf nur in derselben Sitzung ueber den
Plus-Knopf angelegte Auftraege.
- closeModal(): Zaehler _pendingBacks statt Boolean (KB #1209), History-
Eintrag wird vor dem Cleanup zurueckgenommen
- router.go() und pushModal() warten ueber historySettled() auf
ausstehende Ruecksprunge (Schutzzeit 1,5 s)
- Kamera und Galerie-Auswahl steuern nach dem Sichern ausdruecklich
'#/orders/<id>' an statt den Hash der Adresszeile
- Auftragsseite: Block "Warten auf Upload (n)" mit Vorschaubildern aus
der Warteschlange und Klartext; zieht nach photo-uploaded selbst nach
- Hinweis-Toast beim Schliessen der Kamera, wenn noch Fotos warten
Verifiziert lokal in Chromium mit echtem Offline-Modus; die Kamera
selbst (getUserMedia) am Handy ist noch nicht getestet. Kein Deploy.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Gemeldet: die App zeigte beim Oeffnen nur "Failed to fetch", waehrend das
Teilen aus WhatsApp weiter ging. Deploy und API waren in Ordnung — die
Meldung ist die rohe Browserausgabe eines fetch(), das gar nicht bis zum
Server kam, und stand 1:1 im UI, weil die Routen im catch e.message
anzeigten. Das Teilen fiel nicht auf, weil share.html sich die letzten
Auftraege seit eaad796 lokal merkt; die Hauptapp hatte fuer die Listen
keinen Offline-Fallback.
- api.js uebersetzt Netzfehler in einen eigenen Fehler mit offline=true
und deutschem Text; 4xx/5xx bleiben Serverfehler
- isTransient() in offline.js erkannte Netzfehler an "instanceof TypeError".
Ohne Anpassung waere ein Foto aus dem Funkloch als dauerhaft
fehlgeschlagen gewertet und nach sechs Versuchen in Quarantaene gelandet
- Datenspiegel in IndexedDB: Auftrags-, Kunden- und Berichtsliste sowie
geoeffnete Details (letzte 30). Ohne Netz wird der Stand angezeigt,
mit Band "Kein Netz — Stand von HH:MM Uhr", und die Suche filtert darin
- beim Abmelden wird der Spiegel geloescht (geteiltes Geraet)
- sw.js: der Same-Origin-Zweig endete auf caches.match(); fand der Cache
nichts, wurde respondWith(undefined) aufgerufen und die Anfrage
scheiterte erneut mit genau der Meldung, die verhindert werden sollte.
Jetzt immer eine echte Response, nur vollstaendige Antworten im Cache
- Precache nach Deploy: die Seite meldet dem Worker ihre echten Asset-URLs,
sonst ist der Cache direkt nach einem Deploy leer (?v=<mtime>)
Muster aus KB #1037 und #1041. Verifiziert auf der lokalen Testinstanz
inklusive echtem Funkloch (setOffline + reload): App startet aus dem
Cache, zeigt Band und Auftragsliste, keine JS-Fehler.
Jeder Teilen-Vorgang endete bisher in einer Sackgasse — Login-Hinweis oder
"Keine geteilten Fotos gefunden", und danach war das Geteilte weg. Zwei Ursachen:
1. share.html prüfte api.getToken() — ein JWT in IndexedDB, das es seit der
SSO-Umstellung nicht mehr gibt (api.login() legt nur noch 'user' ab, die
Sitzung steckt im HttpOnly-Cookie awl_sso). Der Wert war immer leer, also kam
IMMER "Bitte zuerst anmelden"; der Weg "Zur App" verwarf das Geteilte.
Jetzt: Cookie-Prüfung über api/verify.php wie in ensureAuth(), und die
Anmeldung (Passwort + Passkey) läuft IN der Teilen-Seite — das Geteilte bleibt
dabei gesichert und der Ablauf geht danach direkt weiter.
2. Der Service Worker sicherte nur Dateien. Titel, Text und Link aus dem
share_target wurden weggeworfen, ein reiner Text-Share schrieb gar nichts.
Jetzt wird das ganze Paket gesichert und immer weitergeleitet (absolute
Redirect-URL, leere File-Platzhalter fliegen raus).
Die Teilen-Seite zeigt Bildvorschau, Betreff und Text zum Nachbessern und eine
Auftragssuche (ohne Suchbegriff die offenen Aufträge, mit Suchbegriff alle).
Beim Ablegen gehen die Bilder über die normale Upload-Queue (Persist-First),
der Text wird als notiz_*.txt über api/note.php gespeichert. Scheitert die
Notiz (kein Netz), bleibt der Text gesichert und der Vorgang ist wiederholbar.
Dazu ein Banner in der App, wenn noch ein Paket unabgelegt bereitliegt —
abgebrochene Vorgänge findet sonst niemand wieder. share.html liest auch den
alten IndexedDB-Schlüssel, damit der erste Share nach dem Deploy (noch alter
Service Worker) nicht verlorengeht.
Lokal durchgespielt: Bild+Text, nur Text, und abgemeldet teilen.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Textnotizen: neuer Punkt "Notizen (n)" am Auftrag, direkt unter der Sprachnotiz.
Liste mit Betreff, Vorschau und Zeitstempel; antippen oeffnet die Notiz zum Lesen und
Aendern, loeschen mit Rueckfrage. Gespeichert wird ueber api/note.php als
notiz_<betreff>_<datum>.txt im Auftragsordner - derselbe Weg wie bei der Sprachnotiz,
damit die Notiz auch im Dolibarr-Auftrag und in der Anhaenge-Spalte des Bericht-Editors
auftaucht. In "Weitere Dokumente" sind Notizen ausgefiltert, sie haetten dort doppelt
gestanden.
Fotokacheln laden jetzt serverseitige Thumbnails (photo.php?size=thumb) statt der
Originale: rund 10 KB statt mehrerer hundert KB je Kachel. Das <img> haengt direkt an
der URL statt an einer Blob-URL - damit greifen HTTP-Cache und loading="lazy"
tatsaechlich und der Browser laedt parallel. Vorher lief eine sequenzielle Schleife, die
jedes Foto komplett holte, bevor das naechste anfing, und im Fehlerfall ein zweites Mal.
Bericht-Seiten zeigen composite_path, wenn vorhanden - also das im Editor gebaute
Seitenbild mit Anmerkungen statt der Rohdatei. Raster-Layouts bekommen ein Kennzeichen
("4"); Seiten ohne Bildquelle zeigen keine Fehlerkachel mehr.
confirm/alert/prompt sind an allen zehn Stellen durch eigene Modale ersetzt
(confirmDialog/alertDialog/inputDialog). Browser-Dialoge zeigen in der installierten PWA
die Herkunfts-URL und wirken wie ein Systemfehler. Der Hardware-Zurueck-Button schliesst
sie als Abbruch.
Service Worker: eigener Cache baustelle-media (cache-first, LRU 300) fuer Thumbnails.
Vorher war ohne Netz kein einziges schon angesehenes Foto verfuegbar. Der Cache ueberlebt
Deploys bewusst und wird beim Abmelden geleert (CLEAR_MEDIA), damit keine Kundenfotos auf
dem Geraet zurueckbleiben.
Nebenbei behoben:
- .modal-header, .close-btn und .modal-body hatten ueberhaupt kein CSS, obwohl das Markup
sie nutzt (u. a. beim Loeschen eines Berichts) - der Schliessen-Knopf sass unter der
Ueberschrift statt daneben.
- Das Laden eines Thumbnails ueberschrieb den ganzen Kachel-Inhalt und nahm die Overlays
mit: Auswahl-Haekchen und Seitennummer verschwanden, sobald das Bild da war.
- manifest.webmanifest: share_target.action war eine absolute URL auf den Prod-Host und
lag damit ausserhalb des Scopes - der Browser verwarf das share_target komplett. Jetzt
relativ ("share.html"), funktioniert lokal und auf Prod.
ROADMAP.md neu angelegt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Kamera bleibt nach jedem Schnappschuss offen (getUserMedia Live-Video statt
native capture-Input, der nach jedem Foto schliesst)
- Filmstreifen mit Status-Badges pro Foto (💾 gesichert → ⏳ lädt hoch → ✓ fertig)
- Persist-First: Foto zuerst in IndexedDB schreiben, Upload erst danach
- Foto verlässt Queue NUR nach HTTP-2xx mit gültigem relpath
- 2xx-HTML (abgelaufene Session, Proxy-Loginseite) wird als Fehler erkannt
- HTTP-Status auf Error-Objekt: 5xx/429/408 sind transient (nicht quarantänisiert)
- 45-Sekunden-Upload-Timeout via AbortController
- Quarantäne nach 6 Fehlversuchen, Recovery via Status-Badge-Tipp
- Beforeunload-Warnung wenn Fotos noch nicht gesichert
- idb.queueUpdate() für state-preserving ItemUpdates ohne Datenverlust
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Neue Route #/orders/:id/shipments: Lieferungen zum Auftrag laden und anzeigen
- Neue Route #/shipments/🆔 Lieferschein-PDF inline (alle Seiten via PDF.js), Button Unterschreiben
- Vollbild-Landscape-Signatur-Modal: Fullscreen-API + screen.orientation.lock, HiDPI-Canvas
- Canvas transparent (kein fillRect), trimCanvasToInk() schneidet auf bemalte Fläche
- Name des Unterzeichners vorausgefüllt mit Kundenname aus Order
- POST api/shipments.php?action=confirm: Signatur-PNG + signer_name + GPS
- GPS-Abfrage (timeout 3s, graceful bei Verweigerung)
- Signed-PDF direkt nach Bestätigung anzeigen (?variant=signed)
- Fehlermeldung im Modal (kein hinter Fullscreen versteckter Toast)
- lib/api.js: listShipments, getShipment, getShipmentPdfBlobUrl, confirmShipment
[deploy]
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- PDFs/Dokumente lassen sich jetzt auch im Auswahl-Modus markieren und
mitteilen (bisher öffnete der Tap immer den Viewer)
- ☑ Auswählen-Button erscheint auch wenn nur Dokumente vorhanden sind
- Android-Zurück-Button im Select-Modus: hebt die Auswahl auf und
beendet den Auswahl-Modus (statt die Seite zu verlassen)
- ✕ Abbrechen-Button nutzt denselben History-Back-Pfad
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Modal-Stack mit History-API: jedes Modal pusht einen History-Eintrag,
Android-Zurück schließt das Modal statt die App zu beenden
- Top-Level-Routen: "Nochmal drücken zum Beenden"-Toast (2s Fenster)
- shareFile()/shareFiles(): native Android-Share-Sheet für Fotos, PDFs, Dokumente
- Multi-Select in Fotogalerie: Mehrere Fotos gleichzeitig auswählen und teilen
- PDF-Teilen: auto-.pdf-Extension damit Android-Apps die Datei akzeptieren
- openPdfModal: Share-Button neben Download-Button
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- otherDocs-Sektion mit gestylten doc-items (Icon, Name, Größe, Datum)
- getFileBlobUrl() in api.js ohne Mime-Filter
- PDF/Bilder: Fullscreen-Modal mit iframe/img + Download-Button
- Andere Dateitypen: direkter Download
- CSS analog zu .audio-item
Co-Authored-By: Claude Haiku 4.5 <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>
- ref_client wird neben Auftragsnummer angezeigt (wenn vorhanden)
- CSS-Styling für .ref-client
[deploy]
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
PWA:
- Checkbox in /orders Route hinzugefügt
- Filter in localStorage persistiert
- CSS für .filter-toggle
Doku:
- README.md komplett aktualisiert mit allen Features
- API-Dokumentation erweitert
[deploy]
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- openPageActionsModal bekommt Titel-Feld (wird im PDF groß oben auf
der Seite gedruckt, wenn gesetzt) zusätzlich zur Notiz
- Save sendet beide Felder zusammen via api.request POST
- Seiten-Thumbs zeigen Titel als Badge unten (ellipsis bei langem
Text)
- lib/api.js exposed request() als Low-Level-Funktion für
Spezialfälle wie dieses Update
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
Schnell-Bericht-Modal (Phase 4.a + 4.i):
- '📑 Neuen Bericht anlegen…' Button im Auftrags-Detail
- openNewReportModal: Titel, Format/Orientation, Vorlage-Dropdown,
ODT-Deckblatt-Dropdown
- Auto-Select der Default-ODT-Vorlage aus Admin-Config
- api.createReport() als Wrapper für /reports.php?action=create
- api.listTemplates() + api.listOdtTemplates()
Whisper-Transkription (Phase 5.7):
- Neuer 📝-Button je Audio-Item
- Tap → api.transcribeAudio(relpath) → Server ruft Whisper-Endpoint
- Transkribierter Text erscheint direkt unter dem Audio-Player
- Text ist wählbar und kann kopiert werden
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]
Bericht-Detail-Ansicht:
- Tap auf Seiten-Thumb → openPageActionsModal mit:
- Vorschaubild
- Textarea für Seiten-Notiz (wird im PDF unter der Seite gedruckt)
- '💾 Notiz speichern' → api.updatePageNote
- 🗑️ im Header → api.deletePage mit Confirm
- Seiten-Thumbs haben Nummer-Badge oben links (1, 2, 3…)
- Neuer '👁 PDF-Vorschau'-Button öffnet openPdfModal (iframe mit
Blob-URL) für Final-PDF oder on-the-fly Preview
- Neuer '✍️ Kunden-Unterschrift hinzufügen'-Button öffnet
openSignatureModal: Touch-Canvas 2:1, Clear, Save → PNG wird als
neue Bericht-Seite mit note='Unterschrift Kunde' angelegt
Web Share Target API:
- manifest.webmanifest: share_target mit photos array
- share.html: empfängt geteilte Fotos aus IDB (vom SW befüllt),
zeigt Auftragsliste, Tap → Upload aller Fotos
- Service Worker v5: fängt POST /share.html ab, schreibt Files in
IDB Key 'shared_files', redirected 303
Cache-Version bumpt damit neue Files geladen werden.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
- Bericht-Detail: Button ist jetzt immer da, bei Final heißt er
'PDF neu erzeugen'. Bei 0 Seiten disabled statt versteckt, mit
Hinweis-Empty-State darüber.
- Auftrags-Detail: Audio-Files (webm/mp3/ogg/m4a/wav) werden aus
'Weitere Dokumente' rausgefiltert und in eine eigene Sektion
'🎙 Sprachnotizen' mit Play-Button je Eintrag gelegt. Tap auf ▶
lädt die Datei als Blob (mit JWT) und setzt einen <audio>-Player
inline ein.
- Service Worker v3.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
Der Reports-Tab listet alle Berichte des Users mit Status-Badge,
Quell-Referenz und Seitenzahl. Klick → Bericht-Detail mit:
- Meta (Titel, Format, Status, Seiten)
- Seiten-Thumbnails
- 'Bericht finalisieren' Button (triggert PDF-Generierung via API)
- 'Im Desktop-Editor öffnen' Link
Auftrags-Detail erweitert:
- Tap auf Foto-Thumb → Vollbild-Modal mit Löschen-Button und
'Zeichnen'-Button (öffnet Skizzen-Editor)
- '🎙 Sprachnotiz aufnehmen' Button → Voice-Modal mit MediaRecorder,
Live-Timer, Preview, Upload
Skizzen-Editor (Touch-fähig):
- Bild wird in canvas geladen, max 1600px
- Werkzeuge: Pen, Pfeil mit Spitze, Rechteck, Ellipse
- Farbe + Linienstärke
- Undo + Clear
- Speichern → rendert als JPEG und lädt als neue Bericht-Seite hoch
Service Worker Cache-Version auf v2 gebumpt.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
- photo-grid: max-width 600px, thumb max 160px (vorher riesig auf Desktop)
- auto-fill Grid statt fixes repeat(3)
- api.getPhotoBlobUrl loggt Content-Type + Body bei Fehler, um
API-Probleme in der Konsole sichtbar zu machen
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
<img src> kann keine Authorization-Header schicken. Wir holen die
Bilder jetzt via fetch() mit Bearer-Token und setzen Blob-URLs in die
Thumbnails ein (mit Cache für wiederholte Abrufe). Vorher zeigte die
PWA leere Bild-Placeholder weil document.php eine Session verlangt.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
[deploy]
Mobile Progressive Web App für Baustellen-Doku, spricht die REST-API
des Dolibarr-Bericht-Moduls.
MVP-Features:
- Vanilla JavaScript, kein Build-Step nötig
- Login mit Dolibarr-Credentials → JWT (7 Tage)
- Auftragsliste mit Suche und Multi-User-Filter
- Auftragsdetail mit Kunde, Adresse, Click-to-Call
- Foto-Aufnahme via Kamera oder Galerie (multiple)
- Clientseitige Bildverkleinerung (max 2000px, JPEG q=0.85)
- Offline-Queue in IndexedDB für Uploads ohne Netz
- Auto-Sync bei Online-Event mit Status-Badge
- Service Worker für App-Shell-Cache
- PWA-installierbar (Manifest, Icons, Theme-Color)
Hosting: awl.data-it-solution.de/baustelle/ via Apache-Alias
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>