# Baustelle PWA Mobile Progressive Web App für die Baustellen-Doku — Foto-Upload, Sprachnotizen, Skizzen, offline-fähig. Spricht die REST-API des Dolibarr-Bericht-Moduls. ## Stack - **Vanilla JavaScript** — kein Build, keine Framework-Abhängigkeit - **Service Worker** für App-Shell-Cache (Workbox-frei, eigene Implementierung) - **IndexedDB** für die Offline-Upload-Queue (Auth-Session steckt im HttpOnly-Cookie, nicht in IndexedDB) - **REST API** des `bericht`-Dolibarr-Moduls unter `/custom/bericht/api/` ## Features **Aufträge** - ✅ Login mit Dolibarr-Credentials → zentrales SSO (HttpOnly-Cookie `awl_sso`, same-origin; Single-Sign-On/-Logout über alle AWL-Apps). WebAuthn/Passkey-Login möglich - ✅ Auftragsliste mit Suche, gefiltert auf eigene Aufträge (Multi-User) - ✅ Toggle "Auch abgeschlossene" (Filter in localStorage persistiert) - ✅ Auftragsdetail mit Kunde, Adresse, Telefon (Click-to-Call) - ✅ **Neuer Auftrag** (FAB): Kunde per Suche/Zuletzt-verwendet wählen, dann **Ihr Zeichen** (Pflicht), **Auftragsbeschreibung** (optional), **Geplanter Liefertermin** (Datum + Uhrzeit) und Checkbox **Auftrag direkt freigeben**. Kunden-Defaults (Zahlungsbedingung/Zahlart, Ansprechpartner) werden übernommen. Bei „direkt freigeben" hängt das Backend automatisch eine Std-Lohn-Zeile an (Kundenkarten-Default bzw. Fallback-Produkt, kundenspezifischer Preis) und validiert den Auftrag. **Foto-Upload** - ✅ Live-Kamera-Modal (getUserMedia): bleibt für Serien-Aufnahmen offen — Auslöser + Filmstreifen mit Upload-Status je Foto (💾 gesichert → ⏳ lädt hoch → ✓ fertig), Front-/Rückkamera-Umschaltung, Fehlschuss löschbar - ✅ Alternativ Aufnahme aus der Galerie - ✅ Clientseitige Bild-Verkleinerung auf 2000px (JPEG q=0.85) - ✅ **Persist-First / Datenverlust-Schutz**: jedes Foto wird beim Auslösen ZUERST in IndexedDB gesichert, Upload erst danach; Queue-Item wird nur nach bestätigtem Upload (HTTP 2xx mit gültigem `relpath`) gelöscht — überlebt fehlendes/schwaches Netz, hängende Uploads (45s-Timeout) und App-Kill. Erkennt 2xx-HTML (abgelaufene Session/Proxy-Loginseite) als Fehler statt als Erfolg - ✅ Auto-Sync bei "online", periodisch (15s) und bei App-Fokus; Status-Badge (🟢 alles gesichert / 🟡 lädt hoch / 🔴 offline / ⚠️ fehlgeschlagen) - ✅ Recovery: Tipp auf das Status-Badge öffnet die Warteschlange → erneut senden / teilen; Warnung beim Schließen mit noch ungesicherten Fotos - ✅ Foto-Viewer mit Zoom + Swipe - ✅ Foto-Skizze: Annotationen mit Pfeilen, Kreisen, Rechtecken, Text **Sprachnotizen** - ✅ Sprachaufnahme via MediaRecorder (webm) - ✅ Whisper-Transkription (serverseitig, API-Aufruf) **Berichte** - ✅ Berichte pro Auftrag anzeigen - ✅ Bericht erstellen mit Template-Auswahl - ✅ Seiten umordnen per Drag&Drop - ✅ Seite löschen, Notiz bearbeiten - ✅ Touch-Unterschrift abnehmen (mit GPS + Name) - ✅ Bericht finalisieren → PDF-Vorschau - ✅ PDF-Download **Lieferungen + Kundenunterschrift** - ✅ Lieferungen-Liste pro Auftrag mit Status + Signed-Badge - ✅ Lieferschein-PDF inline (PDF.js, alle Seiten) - ✅ Vollbild-Querformat-Unterschrift mit HiDPI-Canvas, transparent (kein Hintergrund) - ✅ Trimmt Canvas automatisch auf bemalte Fläche - ✅ Name des Unterzeichners aus Kundendaten vorausgefüllt - ✅ GPS-Koordinaten (optional, timeout 3s) - ✅ Unterschrift wird via ODT-Hook in das Lieferschein-PDF gestempelt - ✅ Expedition wird nach Unterschrift automatisch validiert + geschlossen - ✅ Signed-PDF direkt nach Bestätigung als Vorschau **Materialliste** - ✅ Material pro Auftrag erfassen (Label, Menge, Einheit, Notiz) - ✅ Material löschen **PWA** - ✅ Service Worker für Offline-Start - ✅ Installierbar als PWA (Home-Screen-Icon) - ✅ Web Share Target API (Fotos aus anderer App teilen) - ✅ Nativer Android-Share-Sheet für Fotos, PDFs und Dokumente (`navigator.share`) — direkt an WhatsApp / Signal / Mail - ✅ Mehrfachauswahl in Foto- und Dokument-Liste mit Batch-Teilen - ✅ Android-Hardware-Back-Button schließt Modale/Ansichten sauber (History-Modal-Stack), bricht Mehrfachauswahl ab statt App zu verlassen - ✅ „Nochmal drücken zum Beenden"-Toast auf Top-Level-Routen - ✅ PIN-Schutz (optional) ## Geplant - Push-Notifications für neue Aufträge ## Hosting Deploy per Forgejo-Pipeline (Commit-Tag `[deploy]`) nach `/mnt/appdata/firma/dolibarr-202509/modules/baustelle/`. Erreichbar unter `https://awl.data-it-solution.de/custom/baustelle/`. Cache-Busting automatisch via `filemtime()` in `index.php` (`?v=` an JS/CSS) — kein manuelles Versions-Hochzählen nötig, die PWA aktualisiert sich beim nächsten Laden. ## Verzeichnis-Struktur ``` baustelle-pwa/ ├── index.php App-Shell (Cache-Busting via filemtime → ?v=) ├── share.html Web-Share-Target-Empfänger ├── manifest.webmanifest PWA Manifest ├── sw.js Service Worker (Network-First, API pass-through) ├── app.js Hauptlogik (Routes, Views) ├── app.css Mobile-first Styling ├── lib/ │ ├── idb.js IndexedDB-Wrapper (Foto-Queue) │ ├── api.js REST-API-Client (SSO-Cookie same-origin, JSON-Guard, Timeout) │ ├── offline.js Offline-Queue + Sync (Persist-First) │ ├── router.js Hash-Router │ ├── pdf.min.js PDF.js (Lieferschein-Vorschau) │ └── pdf.worker.min.js PDF.js Worker └── icons/ ├── icon-192.png └── icon-512.png ``` ## API Die App spricht die Bericht-API unter `/custom/bericht/api/`: **Auth** - `POST /auth.php` — Login mit Dolibarr-Credentials → setzt HttpOnly-Cookie `awl_sso` (zentrales SSO via awlauth). Folge-Requests authentisieren same-origin über das Cookie (kein Bearer-Token) **Aufträge** - `GET /orders.php` — Aufträge des Users (Filter: `?open=1`, `?q=suche`) - `GET /orders.php?id=X` — Auftrag-Detail inkl. verknüpfte Berichte - `GET /orders.php?id=X&action=photos` — Anhang-Liste - `POST /orders.php?id=X&action=upload_photo` — Foto-Upload (multipart) **Kunden** - `GET /customers.php` — Kundenliste (Filter: `?q=suche`) - `GET /customers.php?id=X` — Kundendetail **Berichte** - `GET /reports.php` — Alle Berichte des Users - `GET /reports.php?id=X` — Bericht-Detail mit Seiten - `POST /reports.php?action=create` — Neuen Bericht anlegen - `POST /reports.php?id=X&action=finalize` — Bericht finalisieren - `DELETE /reports.php?id=X` — Bericht löschen **Seiten** - `DELETE /pages.php?id=X` — Seite löschen - `POST /pages.php?id=X` — Seite aktualisieren (note, rotation) - `POST /pages.php?action=signature&bericht_id=X` — Unterschrift hinzufügen - `POST /pages.php?action=reorder` — Seiten umordnen **Material** - `GET /materials.php?element_type=X&element_id=Y` — Materialliste - `POST /materials.php?element_type=X&element_id=Y` — Material hinzufügen - `POST /materials.php?id=X&delete=1` — Material löschen **Lieferungen** - `GET /shipments.php?order_id=X` — Lieferungen zu einem Auftrag - `GET /shipments.php?id=X` — Lieferung-Detail (inkl. bericht_id falls Unterschrift vorhanden) - `GET /shipments.php?id=X&action=pdf[&variant=auto|signed|unsigned]` — Lieferschein-PDF - `POST /shipments.php?id=X&action=confirm` — Kunden-Unterschrift einstempeln (FormData mit signature_png, signer_name, gps_lat, gps_lon, signed_at). Backend setzt signed_status=1 und schließt die Expedition **Medien** - `GET /photo.php?relpath=X` — Foto abrufen (mit Thumbnail: `&size=thumb`); Auth über `awl_sso`-Cookie (same-origin, auch für ``-Tags — kein `?jwt=` mehr nötig) - `POST /delete_photo.php` — Foto löschen - `POST /voice.php?order_id=X` — Sprachnotiz hochladen - `POST /transcribe.php` — Whisper-Transkription anfordern - `GET /pdf.php?id=X` — PDF abrufen (Final oder Preview); Auth über `awl_sso`-Cookie (same-origin) **Templates** - `GET /templates.php` — Bericht-Vorlagen - `GET /odt_templates.php` — ODT-Deckblatt-Vorlagen ## Lizenz GPL v3+