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

149 lines
7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.
- [x] **[API]** `photo.php` um `size=thumb&w=<px>` erweitern → `bericht_attachment_thumb()`,
mit ETag aus mtime und `Cache-Control: private, max-age=…, immutable`
- [x] `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.
- [x] 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.
- [x] 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`.
- [x] **[API]** `taken_at` je Datei ausgeben
- [x] 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.
- [x] **[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
- [x] **[API]** `composite_path` in `reports.php` mit ausgeben
- [x] PWA zeigt `composite_path`, wenn vorhanden, sonst `source_path`
- [x] 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 |
- [x] 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.
- [x] 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.
- [x] 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.
- [x] „📝 Notizen (n)" am Auftrag, direkt unter der Sprachnotiz
- [x] Liste mit Betreff, zweizeiliger Vorschau und Zeitstempel; Antippen öffnet zum Lesen
und Ändern, 🗑 löscht (mit Rückfrage)
- [x] Editor: Betreff-Feld + Textfeld über die volle Höhe, Speichern über ✓ in der Kopfzeile,
Rückfrage beim Verlassen mit ungespeicherten Änderungen
- [x] 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.
- [x] 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.