bericht/ROADMAP.md
Eduard Wisch a8d8291c3a API 1.5.1: Thumbnails, Aufnahmezeit, Seitenfelder, Textnotizen
Die API-Seite zur Baustelle-PWA holt nach, was der Editor mit 1.5.0 bekommen hat.

photo.php kann jetzt size=thumb&w=<px> und rendert ueber bericht_attachment_thumb()
(GD, Cache, EXIF-Rotation) statt die Originaldatei auszuliefern. size=small konnte nur
ein von Dolibarr vorgefertigtes thumbs/<name>_small.<ext> liefern - fuer Uploads ueber
orders.php?action=upload_photo gibt es das nicht, dort laeuft kein vignette(). Die PWA
lud dadurch fuer jede Kachel das komplette Foto: gemessen 9,8 KB statt 235 KB je Kachel.
Antwort mit ETag aus der mtime, Folgeaufrufe enden mit 304.

orders.php?action=photos liefert taken_at (EXIF-Aufnahmezeit ueber bericht_file_taken_at,
sonst Dateidatum) und sortiert danach statt nach filemtime.

reports.php gibt je Seite title und composite_path aus. title konnte ueber pages.php
gesetzt werden, kam aber nie zurueck. composite_path ist das im Editor gebaute
Seitenbild - ohne das zeigen Clients nur das Rohbild ohne Anmerkungen, bei
Raster-Layouts eines von bis zu sechs Bildern und bei title_only gar keins.

Neu: api/note.php - Textnotizen zum Auftrag, aufgebaut wie die Sprachnotiz. Die Notiz
liegt als notiz_<betreff>_<datum>.txt im Auftragsverzeichnis und ist damit auch im
Dolibarr-Auftrag und in der Anhaenge-Spalte des Editors sichtbar. Liste, Lesen, Anlegen,
Aendern, Loeschen. Der file-Parameter wird gegen ^notiz_[A-Za-z0-9_.-]*\.txt$ geprueft;
gegen Pfad-Ausbrueche getestet.

ROADMAP.md wiederhergestellt - sie war mit eb37a4b geloescht worden, weil alle Punkte
abgehakt waren. Sie bleibt ab jetzt liegen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 18:11:42 +02:00

193 lines
12 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 — Modul Bericht
Stand: 2026-08-22 · Version im Repo: 1.5.1
> Diese Datei war mit `eb37a4b` gelöscht worden, weil alle Punkte abgehakt waren. Sie bleibt
> ab jetzt liegen — erledigte Punkte werden abgehakt, nicht entfernt.
---
## 0. API-Seite für die Baustelle-PWA ✅ 1.5.1
Die PWA (`data/baustelle-pwa`) spricht ausschließlich `api/`. Mit 1.5.0 war Infrastruktur
entstanden, die dort nicht ankam — mit 1.5.1 nachgezogen. Gegenstück: `ROADMAP.md` im PWA-Repo, Abschnitt 1.
- [x] **`api/photo.php`: `size=thumb&w=<px>`** ✅ 1.5.1 — bis dahin lieferte der Endpoint nur ein Thumbnail,
wenn Dolibarr schon eines unter `thumbs/<name>_small.<ext>` erzeugt hat. Fotos aus der PWA
kommen über `orders.php?action=upload_photo` herein, und dort läuft **kein `vignette()`**
es gibt also nie eins, und die PWA lädt für jede Kachel das volle Foto.
`bericht_attachment_thumb()` (1.5.0, GD + Cache + EXIF-Rotation) macht genau das Richtige
und ist über die bereits eingebundene `lib/bericht.lib.php` erreichbar.
Dazu ETag aus der mtime, damit wiederholte Aufrufe mit 304 enden.
- [x] **`api/orders.php?action=photos`: `taken_at`** ✅ 1.5.1 — sortiert wurde nach `filemtime`.
Der Editor nutzt seit 1.5.0 die EXIF-Aufnahmezeit (`bericht_file_taken_at()`, eigener
Parser weil im Prod-Container kein `exif`-Modul). Bei Uploads aus der Galerie ist die
Upload-Zeit die falsche Reihenfolge.
- [x] **`api/reports.php`: `title` im `pages`-Array** ✅ 1.5.1 — `api/pages.php` konnte den Seitentitel
setzen und die PWA rendert ihn, aber das Detail gab ihn nicht aus. Der Titel wirkte in der
PWA deshalb, als würde er nicht gespeichert.
- [x] **`api/reports.php`: `composite_path` im `pages`-Array** ✅ 1.5.1 — die PWA zeigte `source_path`,
also das Rohbild ohne Anmerkungen. Bei Raster-Layouts (`grid_2` … `grid_6`,
`before_after`) ist das nur eines von bis zu sechs Bildern, bei `title_only` gar keins
(die PWA zeigte dann eine ❌-Kachel).
- [x] **Neu: `api/note.php`** ✅ 1.5.1 — Textnotizen zum Auftrag (Liste, Lesen, Anlegen, Ändern,
Löschen). Ablage wie bei der Sprachnotiz: `notiz_<betreff>_<datum>.txt` im
Auftrags-Verzeichnis, damit die Notiz auch im Dolibarr-Auftrag und in der Anhänge-Spalte
des Editors auftaucht. Der `file`-Parameter ist gegen ein Muster geprüft (Pfad-Ausbruch).
Gegenstück in der PWA: siehe `ROADMAP.md` im Repo `baustelle-pwa`, Abschnitte 1 und 3 —
dort ebenfalls erledigt.
---
## 1. Anhänge-Spalte (links im Editor) — Hauptbaustelle
Ausgangslage (Eddy, 21.08.2026): *„die Dateinamen können in dem schmalen Fenster nicht ganz
angezeigt werden, ich habe Schwierigkeiten die richtigen Bilder auszusuchen."*
Die Spalte ist 260 px breit und zeigt pro Datei nur eine Zeile `🖼 langer_dateiname… 2,3 MB 🗑️`.
Bei 2040 Baustellenfotos mit Namen wie `IMG_20260812_141233_HDR.jpg` ist das unbrauchbar.
### 1.1 Miniatur-Vorschau statt Dateiname ✅ 1.5.0
- [x] Kachel-Raster (2 Spalten) statt Liste
- [x] Server-Thumbnails für Bilder (GD, gecacht) — Original-Handyfotos werden **nicht** mehr voll geladen
- [x] PDF-Anhänge: Seite 1 als Miniatur (PDF.js, clientseitig, lazy)
- [x] Klick auf Miniatur → Lightbox (Zoom/Pan/Swipe), `✕` bzw. Esc schließt — PDFs im Vollbild-Viewer
- [x] Dateiname zweizeilig unter der Kachel + voller Name als Tooltip
### 1.2 Auswahl bedienbar machen ✅ 1.5.0
- [x] Checkbox als Overlay auf der Kachel (großes Klickziel), Klick auf die Namenszeile wählt ebenfalls aus
- [x] Auswahl-Reihenfolge sichtbar (① ② ③) — bestimmt die Slot-Reihenfolge im Grid-Layout
(vorher: DOM-Reihenfolge, also nicht steuerbar)
- [x] „Alle / Keine" pro Herkunfts-Gruppe + Zähler „3 ausgewählt"
- [x] Bereits im Bericht verwendete Anhänge werden markiert (✓-Badge, ausgegraut)
### 1.3 Sortierung und Filter ✅ 1.5.0
- [x] Sortierung nach **Aufnahmezeit** (auf- und absteigend), Name, Größe — jeweils innerhalb der
Herkunfts-Gruppe, damit die Zuordnung zum Beleg erhalten bleibt
- [x] Filter: alle · nur Bilder · nur PDFs · noch nicht verwendet
- [x] Aufnahmezeit steht unter der Kachel (`12.08. 11:48 · 56 Kb`)
- [x] EXIF-Parser in PHP (`bericht_jpeg_taken_at`), weil das `exif`-Modul im Container
`90-Dolibarr-Prod-Custom` **nicht geladen** ist. Gegen das PHP-Modul geprüft: identische Werte.
Fallback auf das Dateidatum, wenn kein EXIF vorhanden ist.
- [x] Auswahl von Sortierung/Filter/Ansicht wird gemerkt (localStorage)
### 1.4 Spaltenbreite, Kachelgröße, Ziehen und Ablegen ✅ 1.5.0
- [x] **Spaltenbreite ziehbar** — Trennlinie zwischen Anhängen und Arbeitsfläche (150620 px),
Doppelklick setzt auf 260 px zurück; Breite wird gemerkt
- [x] **Ein-/ausklappbar** über „«" in der Kopfzeile — eingeklappt bleiben 26 px stehen
- [x] **Kachelgröße** klein / mittel / groß über „⤢" (in der kleinsten Stufe entfällt die Größenangabe)
- [x] **Kachel auf die Seitenliste ziehen** → neue Seite(n). Sind mehrere Kacheln angekreuzt und man
zieht eine davon, kommen alle mit.
- [x] **Kachel auf die Arbeitsfläche ziehen** → ersetzt das Bild der offenen Seite
- [x] **Kachel auf einen Raster-Platz ziehen** → setzt genau diesen Platz
- [x] **Dateien vom Rechner auf die Spalte ziehen** → Upload (nicht unterstützte Typen werden
benannt und übersprungen)
- [x] SortableJS bekam `group: {put: false}` — sonst streiten sich Sortierung und Ablegen um die
gleichen Ereignisse
---
## 2. Seitenansicht ("Arbeitstisch") ✅ 1.5.0
Vorher zeigte der Editor ein A4-Blatt, auf dem das Foto formatfüllend lag. Beim PDF wurde
dieses ganze Blatt **nochmal** in den Satzspiegel eingepasst — der Inhalt schrumpfte also ein
zweites Mal, und die Vorschau entsprach nicht dem Ergebnis. Seiten, die nie im Editor
gespeichert wurden, liefen zudem über den Kopfbereich (Logo/Titel) hinweg.
- [x] Eine gemeinsame Geometrie-Quelle: `bericht_page_geometry($format, $orientation, $has_note)`
in `lib/bericht.lib.php` — liefert Seitenmaß, Ränder (10 mm), Kopfbereich (30 mm),
Fußbereich (16 mm), Notizzone und den Inhaltsbereich. Editor **und** PDF rechnen damit.
- [x] Arbeitsfläche = Inhaltsbereich. Drumherum das Blatt mit schraffierter Kopf-/Fußzone
(das, was TCPDF selbst druckt) und einer Notizzone, sobald die Seite eine Notiz hat.
- [x] PDF setzt das Composite 1:1 in den Inhaltsbereich statt es erneut einzupassen
- [x] Alle Layout-Zweige der PDF-Erzeugung (Einzelbild, Raster, Vorher/Nachher, Notiz)
auf dieselbe Geometrie umgestellt — vorher rechneten sie mit `margin = 10` ab
Blattkante und schoben Bilder unter den Kopfbereich
- [x] Raster-Vorschau (`ajax/page_image.php`) rendert im Format des Inhaltsbereichs
- [x] Umschalter „📐 Rand" in der Werkzeugleiste (Zustand wird gemerkt)
- [x] Rückwärtskompatibel: Composites aus der Zeit davor haben Blatt-Proportion und werden
an der Proportion erkannt und proportional eingepasst statt verzerrt
---
## 3. Bild einer Seite austauschen ✅ 1.5.0
- [x] `ajax/replace_page_source.php` — tauscht die Quelle einer Seite; Reihenfolge, Notiz und
Anmerkungen bleiben erhalten (vorher: Seite löschen und hinten neu anhängen)
- [x] Raster-Seiten: einzelner Platz austauschbar (nutzt das vorhandene `set_slot_image.php`,
für das es bis dahin keine Bedienung gab)
- [x] Bedienung: „🔄" auf der Seitenminiatur → Statusleiste am unteren Rand → links auf das
Ersatzbild klicken. Esc bricht ab. Bei Rastern vorher den Platz (1…n) wählen.
- [x] Finalisierte Berichte werden serverseitig abgewiesen
---
## 4. Editor / Arbeitsablauf
- [x] **Kein `location.reload()` mehr** ✅ 1.5.0 — Hinzufügen, Löschen, Hochladen, Bildtausch und
der QR-Upload aktualisieren nur noch die betroffenen Listen. Neuer Endpoint
`ajax/fragments.php` liefert Seiten- und Anhängeliste als HTML; gerendert wird über
`bericht_print_page_list()` / `bericht_print_attachment_list()`, dieselben Funktionen wie beim
Seitenaufbau. Der Editor bleibt auf der bearbeiteten Seite, Zoom und Ansicht bleiben erhalten.
Einzige Ausnahme: nach dem Finalisieren wird bewusst neu geladen, weil der Bericht den Status
wechselt und die ganze Karte anders aussieht.
- [x] **Autosave** ✅ 1.5.0 — 4 Sekunden nach der letzten Änderung wird gespeichert, ebenso beim
Seitenwechsel und beim Wegschalten des Tabs. Zustand steht in der Fußleiste
(„● nicht gespeichert" / „✓ gespeichert"), beim Verlassen der Seite warnt der Browser.
Wichtig: das Aufbauen einer Seite (und Zoomen) löst Fabric-Events aus, zählt aber nicht als
Änderung — sonst stünde direkt nach dem Öffnen „nicht gespeichert" da.
- [x] **Tastenkürzel** ✅ 1.5.0 — V/P/R/K/A/T für die Werkzeuge, Entf löscht die Auswahl (das
Hintergrundbild ist ausgenommen), Strg+Z/Y, Strg+S, ↑/↓ blättert durch die Seiten.
In Eingabefeldern und bei offenem Dialog oder offener Großansicht greifen sie nicht.
Die Kürzel stehen in den Tooltips der Schaltflächen.
- [x] **Seitenliste: Mehrfachauswahl** ✅ 1.5.0 — Klick auf die Seitennummer markiert, Umschalt
erweitert bis dorthin. Sammelleiste mit Verdoppeln (⧉), Löschen (🗑️) und Aufheben (Esc).
Neuer Endpoint `ajax/page_bulk.php`; Kopien landen direkt hinter ihrem Original
(`bericht_reorder_with_copies()`), nach dem Löschen wird lückenlos neu nummeriert.
`composite_path` wird bewusst **nicht** mitkopiert — sonst zeigten beide Seiten auf dieselbe
Datei und das Bearbeiten der einen überschriebe die andere.
- [x] **Raster-Plätze direkt anklicken** ✅ 1.5.0 — über der Arbeitsfläche liegt ein Gitter mit
einer Schaltfläche je Platz (bei Vorher/Nachher entsprechend beschriftet). Klick setzt das
links ausgewählte Bild, Ablegen per Drag setzt das gezogene. Die Aufteilung entspricht
`BerichtPage::slotRectsInBox()`. Die Plätze reagieren nur im Auswahlmodus — beim Zeichnen
haben die Werkzeuge Vorrang, sonst käme man auf Raster-Seiten nicht mehr zum Zeichnen.
- [x] **Seitenwechsel serialisiert** ✅ 1.5.0 — beim schnellen Durchklicken überlappten sich zwei
Durchläufe von `loadPage()`: der zweite speicherte die noch nicht umgeschaltete Seite ein
zweites Mal, und beide rendern in denselben Canvas — so konnte die Notiz der einen Seite bei
der anderen landen. Jeder Aufruf bekommt jetzt eine Nummer und bricht ab, sobald ein neuerer
gestartet ist.
## 5. Kleinkram / Fixes
- [x] **Mehrfach-Upload**: `bindExtraUpload` verarbeitete nur `inp.files[0]` — Mehrfachauswahl im
Dateidialog war möglich, es kam aber nur eine Datei an ✅ 1.5.0
- [x] Upload-Fortschritt ✅ 1.5.0 — der Knopf zeigt beim Mehrfach-Upload „⏳ 3 / 8"
- [x] `att-delete` löscht die Datei wirklich aus den Dokumenten des Belegs ✅ 1.5.0 — der Dialog
sagt das jetzt deutlich und warnt zusätzlich, wenn die Datei im Bericht in Gebrauch ist.
---
## Erledigt
### 1.5.1 — 2026-08-22
API-Seite zur PWA nachgezogen (Abschnitt 0): Thumbnail-Endpoint `size=thumb` statt Ausliefern
der Originaldateien (9,8 KB statt 235 KB je Kachel, mit ETag/304), EXIF-Aufnahmezeit in der
Anhängeliste, `title` und `composite_path` in der Bericht-Detailantwort, neuer Endpoint
`api/note.php` für Textnotizen.
### 1.5.0 — 2026-08-21
Vollständig abgearbeitet. Anhänge-Kachelraster mit Miniaturen (1.11.4), Server-Thumbnail-Endpoint,
PDF-Lightbox, Arbeitstisch mit echter Seitengeometrie (2), Bildaustausch auf bestehenden Seiten (3),
Arbeiten ohne Neuladen, Autosave, Tastenkürzel, Sammelaktionen auf Seiten und Raster-Plätze (4).
Nebenbei gefundene und behobene Fehler:
- `dol_dir_list()` wurde ohne `$mode = 1` aufgerufen — dadurch waren `size` und `date` leer
und in der Anhängeliste stand „ Bytes" ohne Zahl
- PDF.js-Worker-Pfad war hartkodiert ohne `/custom`-Präfix → PDF.js lief im „fake worker"-Modus
auf dem Hauptthread (spürbar langsamer beim Rendern)
- `document.php` wurde ohne `attachment=0` verlinkt → PDFs wurden heruntergeladen statt angezeigt
- Größen-Auswahl der Seite blieb leer, weil der DB-Wert `1` die Option `1.0` nicht traf
- Mehrfach-Upload nahm nur die erste Datei
- `--inputbackgroundcolor` wurde im Modul als „im AwlDark nicht vorhanden" behandelt; die
Variable existiert (KB #512, per DevTools bestätigt) — Editor-Eingabefelder nutzen jetzt
dieselben Farben wie Dolibarr selbst