baustelle-pwa/ROADMAP.md
Eddy 4a53ab0ebe Textnotizen, echte Thumbnails, eigene Dialoge, Bild-Cache
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>
2026-08-22 18:12:09 +02:00

7 KiB
Raw Blame History

ROADMAP — Baustelle PWA

Stand: 2026-08-22 · Gegenstück: data/bericht (Modul-Version 1.5.1)

Die PWA hat kein eigenes Backend — alles läuft über custom/bericht/api/. Punkte, die eine API-Änderung brauchen, sind mit [API] markiert und stehen zusätzlich in der ROADMAP des Bericht-Moduls.


1. Nachgezogen aus Bericht 1.5.0 (2026-08-22, Modul 1.5.1)

Das Modul hatte mit 1.5.0 Infrastruktur bekommen, von der die PWA nichts hatte. Die Beschreibungen unten schildern jeweils den Zustand davor.

1.1 Echte Thumbnails statt Vollbilder [API]

Bis dahin lud die PWA für jede Kachel das komplette Foto:

  • loadThumbs() ruft api.getPhotoBlobUrl(rel, 'small') auf → photo.php?size=small
  • photo.php liefert nur dann ein Thumbnail, wenn Dolibarr eines unter thumbs/<name>_small.<ext> vorgefertigt hat
  • Die PWA lädt ihre Fotos aber per orders.php?action=upload_photo hoch, und dort wird nie vignette() aufgerufen → es existiert nie ein Thumb → es kommt immer das Original
  • Bei 30 Baustellenfotos sind das im Mobilfunknetz 30 × 0,51 MB (bei über die Dolibarr-Oberfläche hochgeladenen Originalen entsprechend mehr)

Das Modul kann das seit 1.5.0 längst: bericht_attachment_thumb($full, $maxside) in lib/bericht.lib.php (GD, Cache unter bericht/thumbs/, EXIF-Rotation, Speicher-Notbremse). api/photo.php lädt diese lib bereits.

  • [API] photo.php um size=thumb&w=<px> erweitern → bericht_attachment_thumb(), mit ETag aus mtime und Cache-Control: private, max-age=…, immutable
  • loadThumbs() umbauen: <img src="…api/photo.php?…&size=thumb"> direkt setzen statt fetch → Blob → ObjectURL. Damit greifen HTTP-Cache und loading="lazy" wirklich; heute sind beide wirkungslos, weil der Blob schon vorher komplett geladen wird.
  • Sequenzielle Schleife auflösen — for (const t of thumbs) { await … } lädt Foto für Foto nacheinander. Beim <img>-Weg erledigt der Browser das parallel von selbst.
  • Doppel-Ladung entfernen: schlägt size=small fehl, wird das Original noch einmal geladen.

1.2 Aufnahmezeit statt Dateidatum [API]

1.5.0 hat einen eigenen EXIF-Parser bekommen (bericht_jpeg_taken_at() / bericht_file_taken_at()), weil im Prod-Container das exif-Modul fehlt. Der Editor sortiert Anhänge damit nach Aufnahmezeit. orders.php?action=photos lieferte nur filemtime.

  • [API] taken_at je Datei ausgeben
  • Fotoliste nach Aufnahmezeit sortieren (Auswahl gemerkt, wie im Editor)

1.3 Seiten-Titel kommt nie an [API]

api/pages.php kann title einer Seite setzen, die PWA rendert ihn (page-title-badge, openPageActionsModal(…, title)) — aber api/reports.php gibt title im pages-Array nicht aus. Ein im Editor gesetzter Titel ist in der PWA also unsichtbar, und ein in der PWA gesetzter Titel scheint nach dem Neuladen verschwunden.

  • [API] 'title' => $p->title in reports.php ergänzen (eine Zeile)

1.4 Bearbeitete Seiten und Raster-Layouts [API]

Seit 1.5.0 hat eine Seite composite_path (das im Editor gebaute Seitenbild) und layout (single, grid_2, grid_4, before_after, title_only, …). Die PWA zeigt stur source_path:

  • Nach Bearbeitung im Desktop-Editor zeigt die PWA weiter das Rohbild ohne Anmerkungen

  • Bei einer Rasterseite ist source_path nur eines von bis zu sechs Bildern

  • Bei title_only gibt es gar keine Quelle → -Kachel

  • [API] composite_path in reports.php mit ausgeben

  • PWA zeigt composite_path, wenn vorhanden, sonst source_path

  • Layout-Kennzeichen an der Kachel (z. B. „⊞ 4er-Raster"), damit klar ist, warum dort mehr drauf ist als das eine Foto


2. Verbesserungen unabhängig vom Modul

2.1 Browser-Dialoge raus (10 Stück)

confirm() / alert() / prompt() widersprechen der Hausregel und sehen in der Standalone-PWA auf Android wie ein Systemfehler aus. Ein sauberes Muster liegt schon vor: das „Bericht löschen"-Modal in router.on('/reports/:id').

Stelle Zeile (vor dem Umbau)
PIN stimmt nicht überein alert 295
Bericht finalisieren confirm 1111
PIN-Schutz deaktivieren confirm 1264
Material-Eintrag löschen confirm 1432
Seite aus Bericht entfernen confirm 1809
Foto löschen confirm 2701
Nicht hochgeladenes Foto löschen confirm 3019
Mess-Skala: Länge eingeben prompt 3409
Ungültiges Längenformat alert 3419
„Zuerst kalibrieren" alert 3440
  • Eine confirmDialog({title, text, danger})-Hilfsfunktion (Promise) + inputDialog() für die Längeneingabe, alle zehn Stellen darauf umstellen

2.2 Fotos offline sichtbar halten

Der Service Worker reichte alles unter /custom/bericht/api/ ungecacht durch. Auf der Baustelle ohne Netz ist damit kein einziges schon angesehenes Foto verfügbar.

  • Eigener Runtime-Cache baustelle-media für photo.php-GETs, cache-first mit Größenbegrenzung (LRU, z. B. 200 Einträge). Die Thumb-URLs aus 1.1 sind dafür der richtige Kandidat — klein und unveränderlich.
  • Vom App-Shell-Cache getrennt halten, damit ein Deploy die Medien nicht wegräumt

3. Textnotizen (2026-08-22)

Getippte Notiz zum Auftrag — für alles, was man lieber schreibt als diktiert: Zählernummern, Absprachen, Maße.

  • 📝 Notizen (n)" am Auftrag, direkt unter der Sprachnotiz
  • Liste mit Betreff, zweizeiliger Vorschau und Zeitstempel; Antippen öffnet zum Lesen und Ändern, 🗑 löscht (mit Rückfrage)
  • Editor: Betreff-Feld + Textfeld über die volle Höhe, Speichern über ✓ in der Kopfzeile, Rückfrage beim Verlassen mit ungespeicherten Änderungen
  • Ablage als notiz_<betreff>_<datum>.txt im Auftragsordner (api/note.php) — genau der Weg der Sprachnotiz. Damit auch im Dolibarr-Auftrag und in der Anhänge-Spalte des Bericht-Editors sichtbar.
  • Notizen sind aus „Weitere Dokumente" ausgefiltert — sie haben ihre eigene Sektion und stünden dort sonst doppelt

Nicht umgesetzt (und bewusst verworfen): eine Zeichenfläche für echte Handschrift. Am Handy ohne Stift ist das unbrauchbar.

Erledigt

2026-08-22

Abschnitte 1, 2 und 3 vollständig. Dazu nebenbei behoben:

  • .modal-header, .close-btn und .modal-body hatten überhaupt kein CSS, obwohl das Markup sie seit Längerem nutzt (u. a. beim Löschen eines Berichts) — der Schließen-Knopf saß dadurch unter der Überschrift statt daneben.
  • Das Laden eines Thumbnails überschrieb den kompletten Kachel-Inhalt (t.innerHTML = …) und nahm die Overlays mit: Auswahl-Häkchen in der Mehrfachauswahl und Seitennummer der Bericht-Seiten waren weg, sobald das Bild da war.
  • Beim Abmelden bleiben keine Kundenfotos mehr auf dem Gerät (CLEAR_MEDIA an den Service Worker + clearPhotoCache()).

Davor

Siehe README (Feature-Liste) und die Commit-Historie: SSO-Migration auf awlauth, WebAuthn-Login, Neuer-Auftrag-Formular, Live-Kamera mit Persist-First-Queue, Lieferschein-Unterschrift.