Files

35 KiB
Raw Permalink Blame History

Changelog

2026-07-09 — geo_reverse + Workflow karte-verorten

  • geo_reverse — Reverse-Geocoding: Punkt (GeoJSON 25833 aus geo_erfassen oder ost/nord) → Ort, Ortsteil, PLZ, Straße. Transform via utm33ToWgs84 (require-route), Abfrage Nominatim/OSM. Der ALKIS-WFS liefert keine PLZ/Ortsteil.
  • Workflow karte-verorten (Server, workflows/karte-verorten.xml): Punkt auf der Karte anklicken (geo_erfassen) → geo_reverse → Ort/Ortsteil/PLZ anzeigen. Start: start.php?xml=karte-verorten; auch als Kachel auf der Startseite.

2026-07-09 — personen_liste: anrede-Spalte

  • personen_liste liefert zusätzlich anrede (get_Anrede(false) = „Frau/Herr Nachname"). Genutzt im Posteingang-Workflow: die Select-Option trägt data-anrede, JS schreibt sie ins Feld empfaenger_anrede → E-Mail-Anrede „Hallo Frau Hielscher,". Mail neu strukturiert (HTML <br>, {{{BESCHREIBUNG}}} ist roh), Datei-Zeile entfernt. Neu: {{ICH.anrede}} in start.php.

2026-07-09 — personen_liste + Posteingang-Workflow + upload Drag&Drop

  • personen_liste — Mitglieder einer Gruppe (Default VLN_MITARBEITER, rekursiv, nur aktive) als Liste {id,name,mail,funktion}; fuer -Optionen im html_form, Mail-Verteiler oder loop_foreach.
  • upload — Dropzone nachgeruestet: Datei hineinziehen ODER klicken zum Auswaehlen (rueckwaertskompatibel).
  • Workflow posteingang (Server, workflows/posteingang.xml): PDF hochladen -> Postnummer+Datum -> Posteingangsstempel positionieren+einbrennen (ohne Signatur) -> herunterladen ODER an VLN-Mitarbeiter weiterleiten (E-Mail "Neuer Posteingang" mit Anhang).
  • 2026-07-09 — posteingang + postausgang (Post-Stempel-Tasks)

    • posteingang / postausgang — PDF mit Eingangs-/Ausgangsstempel ("EINGANG/AUSGANG VLN Sachsen / Datum / Nr.") versehen. Der Stempel wird LOKAL per GD gezeichnet (1:1-Kopie der Generatoren 0_meinvln/posteingang|postausgang/stempel.php, kein mein.*-HTTP), interaktive Platzierung + Einbrennen von pdf_stamp_interactive geerbt. Config: file (Pflicht), nr, datum, breite_mm/hoehe_mm, output_var; assign_to Pflicht (interaktiv). Transparenter Hintergrund.

    2026-07-09 — 8 neue Tasks: OCR, RAG-Verwaltung, KI→Liste, Text-Vergleich

    • pdf_ocr — gescannte PDF durchsuchbar machen (ocrmypdf/tesseract deu). Gemeinsamer Extraktor _DokumentText.php mit OCR-Fallback, jetzt auch in ki_auftrag, ki_dok_extrakt, rag_einpflegen. ki_auftrag bricht bei leerer Eingabedatei hart ab.
    • rag_status — Chunk-Anzahl + distinkte Quellen im (gefilterten) Bereich; Idempotenz-Wächter vor rag_einpflegen.
    • rag_loeschen — Quelle/Bereich aus dem Vektor-RAG entfernen (Filter Pflicht).
    • bauakte_dateien — alle Dateien einer Bauakte/eines Ordners als Liste (loop_foreach → rag_einpflegen).
    • ki_tabelle — mehrere Tabellenzeilen per KI extrahieren → Liste.
    • ki_pruefliste — Dokument gegen N Kriterien: ja/nein/unklar + Begründung.
    • ki_beleg_pruefung — Aussagen gegen Quelle prüfen (belegt/unbelegt/widerspruch).
    • text_diff — zwei Texte/Dokumente deterministisch vergleichen (diff -u, ohne KI).

    RAG-Klasse: neue Methoden count(), quellen(), loeschen(). Editor-Schemas + Palette ergänzt; MCP-Katalog erkennt alle 8 inkl. Pflichtparameter.

    • Fix: Mixed-Content bei start.php-Start. start.php baute URL_WORKFLOW aus $_SERVER['HTTPS'] — hinter Traefik (TLS am Proxy) nicht gesetzt ⇒ http://. Das ES-Modul pdf.js/pdf-lib in pdf_zeichnen wurde dadurch als Mixed-Content geblockt (Editor blieb bei „PDF wird geladen …"). start.php nutzt jetzt die kanonische URL_WORKFLOW-Konstante (https, Fallback X-Forwarded-Proto); TaskPdfZeichnen hebt die pdflib-Basis zusätzlich defensiv auf https, wenn der Request https ist. Betraf nur den Browser-Start via start.php (MCP-Start war https).

    • Neu: Task bauakte_attribut — setzt/entfernt Metadaten im DATA_FILE.content-JSON einer Bauakte-Datei. Kurzform <signiert>true</signiert> setzt das Bauakte-signed-Flag (sperrt Bearbeiten; KEINE Krypto-Signatur), plus freie <attribute>(JSON) und <entfernen>. Nur Dateien in der angegebenen Bauakte, md5-validiert. In vergabe-angebot-pruefen nach der Ablage eingebaut (markiert das geprüfte Dokument als signiert). DBV-Falle dokumentiert: DBV::getInstance() hat kein sqlSafe (das ist DB/SecureDB) → in Tasks sql/sqlA + escape nutzen.

    • Neu: Task rag_einpflegen — Dokument (PDF/TXT/MD/DOCX) oder Rohtext in den Vektor-RAG (Qdrant rag_docs, ollama bge-m3) einpflegen, getaggt mit <bereich> (+ <typ>, <quelle>, freie <meta key>). Danach per rag_recherche <filter key="bereich"> durchsuchbar; gesetzte Meta-Schlüssel werden als Qdrant-Index angelegt. Textextraktion via pdftotext/pandoc/soffice. Voraussetzung: php-worker im Netz qdrant_default (in manager/docker-compose.yaml persistiert).

    • Fix: is_signed in der Bauakte war unzuverlässig. DATA_FILE.content.signed wird nur gesetzt, wenn IN der Bauakte signiert wurde — extern signierte PDFs (z. B. „VLN Sachsen Autosign") standen auf false. Folge: „Bearbeiten" und „Vergabe prüfen" wurden für signierte Dateien angeboten, und pdf-annot.php liess sie per Direkt-URL bearbeiten (── „Drehung speichern" hätte das Original und damit die Signatur überschrieben). Neu zentral in require-bauakte.php: pdf_hat_signatur() (Tail-Scan der letzten 64 KB auf /ByteRange, 1,8 ms/Datei statt 23 ms für pdfsig) und bauakte_datei_signiert() (Flag ODER echte Signatur). Genutzt in index.php, pdf-annot.php und der pdf_annot_save-Sperre in ajax.php. Ergebnis deckte sich bei allen Stichproben mit pdfsig.

    • bauakte_datei_waehlen: Begründung statt stiller Auswahl. Wird per Direkteinstieg eine Datei übergeben, die abgelehnt wird (signiert / falscher Ordner / andere Bauakte), nennt die GUI jetzt den Grund, statt kommentarlos die Dateiauswahl zu zeigen.

    2026-07-08 (Workflow-Direktstart aus der Bauakte)

    • start.php: Start-Parameter-Whitelist. ?code=<md5>&file=<md5>&zurueck=bauakte landen als start_bauakte_md5 / start_file_md5 (Praefix = ungeprueft) bzw. als serverseitig gemapptes rueck_url/rueck_name im Kontext. Nur 32-hex bzw. bekanntes Kuerzel; keine Pfade/Dateinamen.
    • bauakte_pick + bauakte_datei_waehlen: Direkteinstieg. Liegt die id schon im Kontext (start_bauakte_md5 / start_file_md5), wird KEINE GUI gezeigt — die id wird gegen genau die rechtegefilterte Liste geprueft, die der Nutzer sonst saehe (Bauakte per get_meine(), Datei per Bauakte+Ordner+nur_unsigniert). Kein Treffer ⇒ normale GUI. Mit <start_var></start_var> abschaltbar.
    • vergabe-angebot-pruefen: Abschluss-Schritt mit Rueckkehr. Popup ⇒ postMessage(workflow_fertig)
      • window.close() (weg 2); gleicher Tab mit rueck_url ⇒ Button + Auto-Weiterleitung (weg 1); sonst normaler Fertig-Bildschirm. Werte ueber Data-Attribute (XSS-sicher), targetOrigin fest.
    • Bauakte: Dropdown-Eintrag „Vergabe pruefen" pro PDF im Ordner Vergabe/Angebote (V/AA), oeffnet den Workflow als Popup und laedt den Ordner nach dem Fertig-Signal neu. Kein iframe (SameSite=Lax, cross-site). Doku: direktstart.md.

    2026-07-08 (Listen-Tasks + MCP-Katalog)

    • workflow_lint präzisiert. ja¹-Zellen in der Doku markieren alternative Quellen (z. B. pdf_stamp_interactive: vorlage | stempel | stempel_text) und gelten nicht mehr als Pflichtparameter — das erzeugte Fehlalarme. Ein Task ohne id ist jetzt eine Warnung; mehrere Tasks ohne id sind ein Fehler, weil sie sich den State-Key teilen (Abschluss-Marker vermischen sich).
    • MCP: drei weitere Werkzeuge.
      • workflow_get versteht jetzt format=struktur — nur der Task-Baum (Typ, id, assign_to, Verzweigung, output_var) statt der ganzen XML. Bei bauakte-vergabe-pruefen: 1.772 statt 6.251 Zeichen (72 %). Standard bleibt xml.
      • workflow_vars — Variablen-Landkarte: welche Kontextvariablen erzeugt werden (mit Task und Herkunftsart: <output_var>, <var name>, <as>, Formularfeld, Task-id), welche gelesen werden und welche gelesen werden, ohne je gesetzt zu sein (Tippfehler).
      • workflow_batch — mehrere Werkzeuge in einem Aufruf (z. B. create + lint + start). Jede Operation wird einzeln gegen die gewährten Scopes geprüft (ein read-Key kann darüber kein workflow_create ausführen), Verschachtelung ist verboten, max. 20 Operationen; die Kette bricht standardmäßig beim ersten Fehler ab und meldet die restlichen als übersprungen.
    • pdf_stempel_oben: Schriftart wählbar. Neue Parameter schrift, schriftgroesse, schriftstil, abstand_oben_mm, auto_verkleinern. Neben den FPDF-Kern-Fonts steht NATIONFD (NationalFirstFontDotted, gepunktet) zur Verfügung — dieselbe Schrift, die PDFER::stamper() für die Vergabe-Unterlagen nutzt. Unbekannte Schrift → Fehlermeldung mit Liste der verfügbaren. Eingebettete Schriften haben nur eine Schnittform, ein angeforderter schriftstil wird verworfen (sonst FPDF-Abbruch „Undefined font"). Zellhöhe bleibt fix bei 7 mm, damit große Schriften oben stehen bleiben. Vorgabe (Helvetica 12 pt fett) unverändert — pdf_anlagen_merge nutzt dieselbe Routine und bleibt unberührt. auto_verkleinern (Default an) schrumpft zu breiten Text, statt ihn über den Seitenrand laufen zu lassen.
    • Neu: Task liste — Tabelle direkt im Editor pflegen (freie Spalten, z. B. name/mail/rolle). Ergebnis ist eine Liste aus Zeilen-Objekten: {{var}} (loop_foreach), {{var}}_json, {{var}}_anzahl, {{var}}_leer und je Spalte {{var}}_<spalte>_liste (fertiger Mail-Verteiler). Zellen dürfen Platzhalter enthalten.
    • Neu: Task liste_filtern — Zeilen nach Bedingungen auswählen (ist, enthaelt, endet_auf, groesser, in, … ; und/oder). Quelle ist jede Liste (Task liste, person_pick, json_transform, JSON-String oder Komma-Liste). Zusätzlich {{var}}_entfernt.
    • Editor: neuer Feldtyp table — echtes Zeilenraster, feste oder dynamische Spalten (columnsFrom); Kopfzeile zieht nach, wenn spalten geändert wird.
    • MCP: vier neue Werkzeuge (token-sparsam entworfen):
      • task_list — alle Task-Typen mit Einzeiler, optional Volltextfilter; interaktiv=true markiert Tasks, die <assign_to> brauchen.
      • task_doc — Doku zu MEHREREN Tasks in EINEM Aufruf; format=xml|kurz|md (≈1/10, 1/3, voll).
      • task_search — findet den passenden Task zu einer Aufgabenbeschreibung.
      • workflow_lint — statische Prüfung: unbekannte Task-Typen, doppelte ids, fehlende Pflichtparameter, interaktive Tasks ohne <assign_to>. Fängt ab, was sonst erst beim Start auffällt.

    2026-07-08 (Bauakte-Vergabe: Stempelauswahl, Ordnerfilter, Docroot-Fix)

    • pdf_stamp_interactive: Stempelart zur Laufzeit wählbar. Neue Parameter stempel_auswahl (Komma-Liste oder alle) und stempel_default. Der Bearbeiter wählt die Art im Dropdown; Bild und Maße wechseln mit. Neue Ausgaben <id>_stempel_art / <id>_stempel_label.
    • Fix: Stempelgröße. auto rechnete Pixel mit 96 dpi um, die bau-Vorlage rendert aber mit 4 px/pt. Stempel waren dreimal zu groß (breiter als A4). Block-Stempel messen jetzt 84,7 × 22,9 mm (= die in stempel-core.php dokumentierten 85 × 23 mm). Gemerkte Skalierung invalidiert (localStorage-Schlüssel wf_stempel_scale2:).
    • Fix: Block-Stempel ohne summe (frf,ga,v,f,ng) liefen in einen TypeError in zueuro(). summe wird jetzt über voneuro() normalisiert, datum fällt auf heute zurück. Kein stiller HTTP-Fallback mehr — der echte Fehlergrund wird gemeldet.
    • Fix: Quelldateien außerhalb des Docroots. Neu AbstractTask::browserFile(): liegt die PDF nicht unter dem Workflow-Docroot (z. B. Bauakte-Datei aus upload_neu), wird sie einmalig ins temp_dir kopiert. Ohne das bekam der Browser einen Dateipfad statt einer URL und der Editor blieb leer — betraf pdf_zeichnen und pdf_stamp_interactive.
    • bauakte_datei_waehlen: neuer Parameter ordner (Kurzcode V oder Klarname Vergabe, Komma-Liste, exakter Treffer) sowie neue Ausgaben <prefix>_basis (Name ohne Endung) und <prefix>_endung.
    • bauakte_datei_waehlen: Pfad-Filter und Signatur-Filter. <ordner> versteht jetzt Pfade (V/AA, Vergabe/Angebote, gemischt Vergabe/AA); je Segment zaehlt Kurzcode oder Klarname. Neu <nur_unsigniert>true</nur_unsigniert>: digital signierte PDFs werden gar nicht erst angeboten (und beim Absenden serverseitig abgewiesen) — sie liessen sich ohnehin nicht bearbeiten. Erkennung per pdfsig; das Bauakte-Flag DATA_FILE.content.signed ist nicht verlaesslich. Nebenbei: DATA_FOLDER.setting ist PHP-serialisiert, nicht JSON.
    • Neuer Workflow bauakte-vergabe-pruefen: Bauakte → PDF aus Vergabe → kommentieren → Summe → Prüfstempel platzieren → als <Name>_geprüft.pdf in denselben Ordner zurück.

    2026-07-08

    • Neu: Task pdf_zeichnen — Freihand-Markierungen direkt auf der PDF (Stift, Linie, Pfeil, Rechteck, Ellipse, Text, Radierer ganz/Bereich), eigene Stifte inkl. Textmarker-Deckkraft, „Nur mit Stift“ (Apple Pencil / Palm Rejection), Zoom, Ansicht-Drehung, Undo/Redo, lokaler Entwurf. Gleiche Zeichenmaschine wie der Bauakte-PDF-Editor. Beim Abschluss brennt pdf-lib die Striche als Vektor-Ebene (OCG „Markierungen“) ins PDF. Signierte PDFs sind gesperrt (signiert=ablehnen). Doku: tasks/pdf_zeichnen.md.

    2026-07-07 (pdf_stamp_interactive: eigene Signatur mit P12)

    • Neue Option eigene_signatur=true (+ optional grund): die Platzier-GUI verlangt P12-Datei + Zertifikat-Passwort; das PDF wird kryptografisch signiert (pyHanko/PAdES-LTA via ltv-signer) mit dem Stempel als sichtbarer Signatur-Optik an der geklickten Position, statt das Bild nur einzubrennen.
    • Sicherheit: is_uploaded_file, openssl_pkcs12_read gegen Passwort, P12 in 0600-Tempdatei + Cleanup, Passwort nie geloggt. P12/Passwort-Felder via form="posForm" (multipart); Confirm erst bei Position + Zertifikat+Passwort.

    2026-07-07 (Datei-/Office-/QGIS-Task-Familien + Upload + Fixes)

    • QGIS-Kern komplettiert (10 Geo-Tasks): geo_aufloesen (Dissolve), geo_verorten (raeuml. Join), geo_zuschneiden (Clip), geo_konvexe_huelle, geo_vereinfachen (Simplify), geo_zusammenfuehren (Merge), geo_zaehlen_in_flaeche (Count in polygon), geo_reparieren (ogr2ogr -makevalid; MariaDB kann kein ST_MakeValid), geo_umschliessende_box (Envelope), geo_naechster (Nearest). Neuer Helfer geo_features().
    • geo_wfs: nur_attribut/nur_wert (Client-Filter) + bbox_puffer (arithmetisch, KEIN ST_Buffer-Hang). geo_raeumliche_auswahl: toleranz (ST_Distance-Saum) + _bbox-Output. geo_visualisieren: legende an/aus (karte.php ?legende=0 + Umschalter).
    • Cache: cache_lade (jetzt CONTAINER wie if: Kind-Tasks laufen nur bei Miss + Ergebnis wird auto-gecacht) + cache_schreiben; Datei-Cache MD5+TTL.
    • Excel: excel_lesen/excel_schreiben (PhpSpreadsheet; Startzelle/Spalten/Bereich/Einzelzellen/Vorlage). Word: word_lesen/word_schreiben (PhpWord TemplateProcessor ${platzhalter}+Zeilen klonen; PDF via soffice). Zip: zip_erstellen/zip_entpacken (ZipArchive, Zip-Slip-sicher). Je eigener *-download.php (statisch geblockt).
    • upload: interaktiver Datei-Upload ($_FILES) -> Serverpfad in Context; entsperrt excel_lesen/word_lesen/zip_entpacken.
    • Workflow dokument-signatur-verband: upload PDF -> optionale Freigeber (sequenziell, approve_reject) -> Unterschrift Verband-Mitarbeiter (pdf_stamp_interactive). Als Start-Button Dokument digital freizeichnen in MeinVLN.
    • Fixes: pdf_stamp_interactive vorlage=bau lokal statt HTTP (Container erreicht mein.*-URL nicht; stempel-core.php); Stempel-Picker Cursor ohne Bild ueber Kopfleiste; person_pick required=false erlaubt Absenden ohne Auswahl; Editor: XML-Kommentare editierbar + verschiebbar (mit Task oder einzeln).

    2026-07-05 (Neuer Geo-Task: raeumliche Auswahl nach Relation)

    • geo_raeumliche_auswahl: waehlt aus einer Kandidaten-Featuremenge alle Features nach raeumlicher Relation zu einer Referenz (intersects/touches/within/contains/overlaps/disjoint) -> liefert die Feature-Liste (nicht wie geo_verschneidung eine Geometrie, nicht wie geo_selektieren interaktiv).
    • Anwendung: FB-Gemeinden (Gemeinden die das Verfahren schneiden) + anliegende Gemeinden (touches, mit Ausschluss der FBG). sammeln_var akkumuliert {name,art} ueber mehrere Aufrufe -> Ergebnistabelle. Editor-Schema + Palette (Geo-Operationen) ergaenzt.
    • Backend MariaDB-Spatial (ST_Intersects/ST_Touches...). Verkettung: tg_pick -> geo_lade(umringe) -> geo_wfs(Gemeinden) -> geo_raeumliche_auswahl x2.

    2026-07-04 (Zertifizierungssignatur DocMDP fuer pdf_siegel)

    • Neue Option zertifizieren= an pdf_siegel (pyHanko-Weg): Autor-/Zertifizierungssignatur (blaues Band in Acrobat). endfassung=P1 keine Aenderung (LTA erzwungen AUS, da nachtraeglicher Dok-Zeitstempel P=1 bricht), zertifiziert=P2 (Inhalt gesperrt, LTA), mit_kommentaren=P3 (+Annotationen, LTA). Muss erste Signatur sein.
    • ltv-signer /sign um certify-Parameter erweitert (MDPPerm NO_CHANGES/FILL_FORMS/ANNOTATE); pdfsign_ltv() + Task + Editor + Doku.
    • Acrobat-Hinweis: Zertifizierungen brauchen im Trust der VLN-Root zusaetzlich den Haken 'Zertifizierte Dokumente'.

    2026-07-04 (LTA: sichtbare Signatur mit Stempelbild)

    • pdf_siegel mit ltv=true kann jetzt eine SICHTBARE Signatur mit Stempelbild setzen (Bild-only). Neue Task-Felder bild/seite/x/y/breite/hoehe (Koordinaten oben-links, Points, Seite 1-basiert wie sign_an_position; leer/-1 = letzte Seite). LTA bleibt erhalten (Kette + Sperrinfos + Dok-Zeitstempel).
    • ltv-signer-Container um pyHanko [image-support]/Pillow erweitert; rendert das Bild als StaticStampStyle-Hintergrund in einem sichtbaren Signaturfeld. pdfsign_ltv() um image/page/box-Parameter erweitert.
    • Hinweis: SAPP-Funktionen sign_mit_bild/sign_an_position koennen ebenfalls Bilder, sind aber PAdES-T (kein LTA).

    2026-07-04 (PAdES-LTA: Langzeit-Signatur + CRL/OCSP-Sperrdienst)

    • Neuer Signierweg: pdf_siegel mit ltv=true erzeugt PAdES-LTA (langzeit-validierbar). Zertifikatskette + Sperrinfos (VLN-CRL + DigiCert-TSA-OCSP) + Dokument-Zeitstempel werden ins PDF (DSS) eingebettet. In Acrobat gruen OHNE 'Sperrung nicht geprueft' und OHNE 'nicht LTV-faehig' (bei importierter VLN-Stamm-CA).
    • Neue VLN-CA-Sperrinfrastruktur (/daten/dockervorlagen/manager/pki): eigenes autosign_ltv.p12 (Leaf mit crlDistributionPoints + authorityInfoAccess/OCSP, EKU documentSigning), delegierter OCSP-Signer (EKU OCSPSigning + noCheck). Root unveraendert wiederverwendet.
    • CRL + OCSP oeffentlich unter https://sign.flurneuordnung-sachsen.de/pki/ : statische CRL (taeglich per Cron, pki/renew_crl.sh) + OCSP-Responder-Container ocsp-responder (nginx-sign Proxy location /pki/ocsp).
    • Signatur via Microservice-Container ltv-signer (pyHanko 0.35, Token-gesichert, www read-only + Sandbox 0_workflow/ltv). Neue Funktion pdfsign_ltv() in require-sign.php ruft ihn per HTTP.
    • SAPP-Weg (pdfsign_tsa, PAdES-T, autosign.p12) bleibt Default; ltv=true schaltet auf den pyHanko-LTA-Weg.

    2026-07-04 (Signatur-Auswertung: Signaturen-Array + Integritaetspruefung)

    • Neuer Task pdf_signaturen: liest alle Signaturen einer PDF (poppler pdfsig) als Array in Signier-Reihenfolge (sortiert nach Signierzeit). Je Eintrag: nr, unterzeichner (CN), dn, email, signiert_am/_iso, zeitstempel, feld, hash, abdeckung_gesamt, gueltig, zertifikat_status. Ausgabe {{signaturen}} (+ _json fuer loop_foreach, _anzahl, _letzter, _letzter_am).
    • Neuer Task pdf_signatur_integritaet: prueft, ob NACH der letzten Signatur noch veraendert wurde (deckt die zeitlich letzte Signatur das ganze Dokument bis zum Dateiende?). Ausgabe {{integritaet_unveraendert}}/{{integritaet_veraendert}} (bool), _signiert, _letzter_unterzeichner, _letzter_am, _nachtraeglich_bytes, _meldung. Verzweigung per if auf {{integritaet_veraendert}}.
    • Gemeinsamer Parser (public static in TaskPdfSignaturen) fuer beide Tasks. In den Editor eingepflegt (Palette PDF, Schema + Hilfe-Doku tasks/pdf_signaturen.md + tasks/pdf_signatur_integritaet.md).
    • Verifiziert: 1-Sig unveraendert; 2-Sig korrekt in Reihenfolge (erste partial, letzte gesamt); +5 Byte angehaengt -> als 'VERAENDERT +5B' erkannt.

    2026-07-04 (Fix: PDF-Siegel/TSA-Signatur war in Acrobat ungueltig)

    • Ursache: SAPP misst die Signaturlaenge mit einem TSA-Abruf und signiert dann mit einem zweiten; RFC-3161-Zeitstempel variieren um wenige Bytes, wodurch die reservierte /Contents-Laenge nicht zur echten Signatur passte. Folge: ByteRange um wenige Bytes verrechnet -> Acrobat 'SigDict /Contents illegal data' bzw. 'Digest Mismatch', Zeitstempel nicht erkannt. Trat intermittierend auf.
    • Fix in vendor/ddn/sapp/PDFDoc.php: Reserve-Marge auf __SIGNATURE_MAX_LENGTH + /Contents wird auf die reservierte Laenge aufgefuellt (Trailing-Nullen liegen ausserhalb der ByteRange). 8/8 Wiederholungslaeufe jetzt gueltig (poppler: Signature is Valid / Total document signed).
    • pdfsign_tsa() prueft nach dem Schreiben zusaetzlich die ByteRange-Konsistenz und wirft bei Abweichung eine Exception (keine still-kaputten Siegel).
    • Hinweis: 'Identitaet nicht bestaetigt' bleibt normal (VLN-eigene CA, nicht in Acrobats Vertrauensliste); erst Import der VLN-Stamm-CA macht es voll gruen.

    2026-07-04 (PDF siegeln mit Zeitstempel + Grund)

    • Neuer Task pdf_siegel: siegelt eine PDF mit dem VLN-Org-Zertifikat (autosign.p12) als PAdES-T inkl. DigiCert-Zeitstempel (LTV) und optionalem Signatur-Grund (reason). In Acrobat sind Grund und Zeitstempel in den Unterschrifteneigenschaften sichtbar; langzeit-validierbar.
    • Basis: neue Funktion pdfsign_tsa() in require-sign.php (SAPP set_tsa + set_metadata_props). Nur dieser Weg erzeugt einen echten RFC-3161-Zeitstempel; die tsa-Option des alten pdf_sign (TCPDF) ist wirkungslos.
    • Config: file (Default {{latest_pdf_path}}), reason, name, ort, tsa (leer=kein Zeitstempel), output, output_var. In den Editor eingepflegt (Palette PDF, Feld reason konfigurierbar).
    • Rechtlich = AES (Org-Soft-Zertifikat, keine QES). Server-seitig verifiziert: /Reason gesetzt, timeStampToken eingebettet.

    2026-07-04 (Externe Gegenzeichnung ohne Login)

    • Externe Dritte (kein VLN-Login) koennen jetzt einen Workflow-Schritt bearbeiten. Neu: Tabelle WORKFLOW_EXTERN (Einmal-Token je Schritt+Mail, auditierbar), extern.php (login-loser Renderer eines einzelnen Schrittes + PDF-Stream, Vorbild 0_bauakte/extern.php), extern-lib.php.
    • Neuer Task pdf_sign_extern: mailt der externen Person einen extern.php-Link; sie signiert per Zeichnen (Signaturseite wird angehaengt) ODER laedt eine unterschriebene PDF hoch. Engine: no_notify-Flag unterdrueckt die Standard-Assign-Mail (Task mailt selbst), WORKFLOW_ACCESS_TOKEN im Context.
    • Workflow dokument-gegenzeichnen: Ersteller gibt Name/Mail/Freitext + PDF -> Person erhaelt Mail 'Bitte Dokument gegenzeichnen' mit Link -> signiert login-los -> Ersteller bekommt Mail 'Dokument wurde unterzeichnet' mit signierter PDF im Anhang.
    • End-to-end verifiziert (Agentmail): Invite-Mail korrekt, login-loser Zugang, Signatur -> 2-seitige PDF, Einmal-Token verbraucht.
    • Hinweis: gezeichnete/hochgeladene Unterschrift = EINFACHE E-Signatur (keine QES).

    2026-07-04 (pdf_split_interactive: visuelle Seiten-Vorschau)

    • pdf_split_interactive: neuer Button 'Visuell ansehen' zeigt einen waagerechten Streifen der Seiten-Vorschauen; zwischen zwei Seiten eine Schere -> Klick setzt/entfernt einen Schnitt, die Teile werden automatisch berechnet. Manuelle Seiteneingabe bleibt Default.
    • Neuer Endpoint pdf-thumb.php: rendert eine Seite server-seitig per pdftoppm (token-gesichert, gecacht). Vorschauen werden lazy geladen (nur sichtbare Seiten) -> auch 400-MB/1366-Seiten-PDFs laufen fluessig, die grosse Datei wird nie in den Browser geladen. Seitenzahl jetzt via pdfinfo (schnell).
    • Verifiziert an der 424-MB-Datei (Bauakte 2027): Seite in ~0.4s als 20-KB-JPEG, Streifen + Schere + Teileberechnung funktionieren.

    2026-07-04 (Editor: Starten-Button)

    • Fix: Starten-Button im Editor startet jetzt den aktuell geoeffneten Workflow (start.php?xml= in neuem Tab) statt nur die leere Startseite. Ohne offene Datei erscheint ein Hinweis.

    2026-07-04 (pdf_merge_interactive)

    • pdf_merge_interactive (neu, generisch): fuehrt mehrere PDFs zu einer zusammen. Eingabe = Array von Pfaden (files, z.B. {{teile}}); der Bearbeiter ordnet per Drag and Drop und waehlt ab/an; Merge per pdftk (Fallback pdfunite). Gegenstueck zu pdf_split_interactive. Setzt latest_pdf_path. End-to-end verifiziert (3+2 -> 5 Seiten).

    2026-07-04 (Palette-Suche + PDF-in-Bauakte-aufteilen)

    • Editor: Suchfeld im Tab Bausteine filtert die Palette live (Name/Typ); leere Gruppen werden ausgeblendet.
    • pdf_split_interactive (neu, generisch): teilt eine beliebige PDF interaktiv in Teile (Name + Seitenbereich, pdftk). Ergebnis-Array fuer loop_foreach.
    • bauakte_datei_waehlen (neu, Bauakte-spezifisch): waehlt eine Datei aus dem Bauakte-Ordnerbaum; liefert lokalen Pfad + Quell-Ordner (folder_md5).
    • bauakte_ablage: neuer Parameter folder_md5 (schreibt in exakt diesen Ordner; Vorrang vor ordner).
    • Workflow bauakte-pdf-aufteilen: Bauakte waehlen, PDF waehlen, interaktiv aufteilen, Teile per loop_foreach in den Quell-Ordner zurueckschreiben. End-to-end verifiziert (49-Seiten-PDF, 2 Teile).

    2026-07-04 (Editor: einklappbare Leiste + XML-Kommentare)

    • Rechte Leiste (Baum/Diagramm/Fehler/Referenz) einklappbar per Chevron-Button; eingeklappt = schmaler Streifen (Center gewinnt Platz), Zustand in localStorage gemerkt.
    • XML-Kommentare: innerhalb des Workflows werden im visuellen Editor als dezente Zeile (kursiv, Sprechblasen-Icon) ueber der jeweiligen Stelle angezeigt. Kommentare ueberleben Speichern (DOMParser + XMLSerializer erhalten sie).

    2026-07-04 (Task-Rename + Editor-Hilfe)

    • Task umverteilen -> sortieren umbenannt (Klasse TaskSortieren + Alias TaskUmverteilen fuer Altbestand; Palette/Schema/Doku/Workflow-XML angepasst).
    • Editor-Hilfe: zentraler Hilfe-Button oben rechts (neben Dashboard) oeffnet ein Modal mit suchbarer, gruppierter Baustein-Liste + ausfuehrlicher Doku; zusaetzlich ein '?'-Icon auf jeder Task-Karte fuer direkte Baustein-Hilfe. Doku = tasks/*.md (jetzt auch auf dem Server) via neuen editor-api.php?action=taskdoc, gerendert mit marked.js.
    • Fix: 'Speichern'-Button wurde beim Hovern weiss (weiss auf weiss) -> Hover-Hintergrund wieder gruen.
    • Editor-Layout: linke Spalte hat jetzt zwei Reiter Workflows und Bausteine. Beim Öffnen/Neuerstellen eines Workflows schaltet sie automatisch auf Bausteine — die Drag-Drop-Palette füllt die ganze linke Spalte statt des gequetschten Kästchens im Mittelbereich. Reiter Workflows jederzeit für die Datei-Liste. Drag-Drop unverändert (Sortable-Gruppe wf-tasks).
    • Alle Tasks haben jetzt eine Doku unter tasks/*.md (18 ergänzt).

    2026-07-04 (Bauakte-Tasks + Genehmigungs-Workflow)

    • KI-Tasks verifiziert: ki_pruefung + recht_frage jetzt funktional getestet (echte KI-/RAG-Antworten).
    • Bauakte-Tasks (5): bauakte_ablage (Datei in Bauakte, Ordner-Kurzcodes z.B. G/BG), bauakte_pick (Ziel waehlen), bauakte_neu (anlegen, Massnahme Pflicht), bauakte_benachrichtigung (Verteiler mailen), bauakte_toeb (raeumlich zustaendige ToeB zu einer Geometrie). Neue Palette-Gruppe 'Bauakte'.
    • Demo-Workflow bauakt-genehmigung: bauakte_pick -> html_form (schreiben) -> pdf_from_template -> approve_reject -> if approved: bauakte_ablage (G/BG) + bauakte_benachrichtigung. End-to-end verifiziert (Ablehnungs-Pfad; Ablage separat unit-getestet).
    • Offen: bauakte_inbox_freigabe (erst ajax.php inbox_approve in wiederverwendbare Funktion refactoren).

    2026-07-04 (10 neue Tasks + PDF-Protokoll)

    • Rechen-Tasks: geo_laenge, geo_puffer (ST_Buffer, z.B. Gewaesserrandstreifen), geo_abstand, geo_zentroid, geo_pruefung (topolog. Boolean fuer type=if: enthaelt/schneidet/innerhalb/...).
    • Interaktiv: geo_messen (Strecke/Flaeche live), geo_grenze_verschieben (Modify + Vorher/Nachher-ha), geo_import (Upload Shape-zip/GPKG/GML/KML/DXF/DGN/GeoJSON -> ogr2ogr -> GeoJSON 25833). geo-editor.js: 5 Modi.
    • KI: ki_pruefung (zentrale KI-Kette), recht_frage (Vektor-RAG FlurbG/AVLNO).
    • PDF-Protokoll: pdf_from_template ist der einheitliche Mustache->PDF-Task (Arrays {{#gesamt}} ok). Freiwilliger-Landtausch endet jetzt mit PDF-Protokoll (template/landtausch-protokoll.mustache: Einlage je Teilnehmer + Umverteilung Vorher/Nachher) + Download-Seite. End-to-end verifiziert.

    2026-07-04 (geo_gemarkung UX)

    • geo_gemarkung: zweiter Waehlweg parallel zum Namen — beim Reinzoomen (Ausschnitt < 30 km) werden Gemarkungsgrenzen des aktuellen Kartenausschnitts als anklickbare graue Layer geladen; Klick waehlt die Gemarkung. gemarkung-geom.php liefert ohne Parameter s jetzt die ganze FeatureCollection im bbox.
    • Hintergrund-Umschalter: Namen stehen jetzt in einer Zeile mit dem Radio (Bootstrap-.row-Konflikt behoben).

    2026-07-04 (Gemarkung ohne Polygon)

    • geo_gemarkung (neuer Task): Gemarkung(en) aus ganz Sachsen (5340) per Suchfeld/Datalist waehlen statt Bereich einzuzeichnen; gewaehlte Gemarkung wird auf der Karte rot hervorgehoben (Highlight via /gemarkung-geom.php on-demand). Output gem_schluessel/gem_namen/gem_geojson/gem_bbox/gem_anzahl. Daten: data/gemarkungen_sn.json, ausgeliefert ueber gemarkung-list.php (PHP-FPM blockt direkte .json).
    • geo_selektieren: neue Optionen filter_attribut/filter_werte (Komma-Liste) begrenzen die angezeigten Objekte serverseitig, z.B. gemaschl={{gem_schluessel}} (nur Flurstuecke der gewaehlten Gemarkung).
    • Workflow freiwilliger-landtausch: Schritt 2 nutzt jetzt geo_gemarkung + gemaschl-Filter statt Polygon-Zeichnen (geo_erfassen->geo_wfs->geo_selektieren entfaellt). End-to-end verifiziert (Gohrisch: 721 Flurstuecke).
    • geo-editor.js: dritter Modus 'gemarkung'. Editor-Schema + Palette ergaenzt.

    2026-07-04 (Umverteilen-UX)

    • umverteilen überarbeitet: ganze Teilnehmer-Spalte ist Ablagezone (irgendwo loslassen → unten angehängt; an Position → dort einsortiert), größere Felder, Greif-Icon, „hierher ziehen"-Platzhalter, Ziel-Spalte-Hervorhebung beim Ziehen, Delta-Anzeige (+/ ha). emptyInsertThreshold für leichteres Treffen.

    2026-07-04 (Flurstuecksnummer)

    • geo_selektieren <flurnummer_aus>: berechnetes Feld flurnummer aus Zaehler/Nenner (lesbare Flurstuecksnummer 5 / 3/109 / 7 a statt Roh-Kennzeichen). In freiwilliger-landtausch fuer die Flurstueck-Anzeige aktiviert.

    2026-07-04 (Umbenennung)

    • Task geo_tauschumverteilen umbenannt (generischer Drag-&-Drop-Verteil-Task, nicht geodaten-spezifisch). Editor-Palette: von „Geo-Operationen" nach „Benutzer". Workflow freiwilliger-landtausch angepasst.

    2026-07-04 (Umverteilung)

    • Neuer Task geo_tausch: Drag-&-Drop-Board zur Umverteilung von Elementen zwischen Gruppen (Teilnehmern); je Gruppe Vorher-/Nachher-Flaeche (ha), Nachher dynamisch. In freiwilliger-landtausch als Schritt 4 ergaenzt. End-to-end verifiziert.

    2026-07-04 (Landtausch + Signatur-Erweiterungen)

    • geo_selektieren: Live-Tabelle (<tabelle>), Flaechen-Summe (<flaeche_attribut> m²→ha), Akkumulation ueber Schleifen (<sammeln_var>/<sammeln_label>), _bbox/_summe_ha. geo_erfassen: _bbox-Output. Statisches geo-editor.js jetzt cache-gebustet.
    • Neuer Workflow freiwilliger-landtausch: Teilnehmerzahl → je Teilnehmer Suchbereich/Gemarkung/Flurstuecke waehlen (ALKIS-WFS) mit dynamischer ha-Tabelle → Uebersicht je Teilnehmer mit Gesamtflaeche. End-to-end verifiziert.

    2026-07-04 (Karten-Erfassung/Selektion)

    • Neue Tasks geo_erfassen (Punkte/Linien/Polygone auf der Karte zeichnen; Typ + Anzahl steuerbar) und geo_selektieren (dargestellte Objekte per Klick auswaehlen; liefert Features + ID-Liste). Gemeinsamer OpenLayers-Editor /geo-editor.js. End-to-end verifiziert.

    2026-07-04 (Export)

    • Neuer Task geo_export + Endpoint geo-download.php: Download der Geodaten in GeoPackage/Shapefile/DXF/DGN/GML/KML/CSV/GeoJSON/FlatGeobuf (ogr2ogr, EPSG:25833; KML→WGS84). Formate beim Task-Erstellen steuerbar; ein Format = kein Auswahldialog. DWG-Hinweis: DXF (native DWG nur mit ODA-Konverter). In gewaesser-im-verfahren als Download-Schritt ergaenzt.

    2026-07-04 (Signaturen)

    • geo_visualisieren + Viewer: Erweiterte Signaturen. Neuer Layer-typ="maske" (EQK-Inverse-Aufhellung: Flaeche ausserhalb des Polygons gedimmt, Rand=Umring). Attributgesteuerter <stil>-JSON: breite_nach (numerisch/kategorie), farbe_nach (kategorie/abstufung), label, punkt/icon; plus strich/deckkraft/z. turf.js im Viewer.

    2026-07-04 (Geo: WFS 1.1.0 + Beispiel-Workflow)

    • geo_wfs: Param <version> — unterstuetzt jetzt auch WFS 1.1.0 (ArcGIS/Landesdienste, GML 3.1.1), inkl. LfULG-Gewaessernetz. geo_lade gibt zusaetzlich _bbox aus.
    • Neuer Workflow gewaesser-im-verfahren: Verfahren waehlen → Umring laden → Fliessgewaesser-WFS → Verschneidung → Karte, die nur die Gewaesser im Verfahrensgebiet zeigt.

    2026-07-04 (MCP OAuth)

    • Neu: OAuth-2.1-Bruecke fuer den Workflow-MCP (claude.ai & Co.). Discovery + Dynamic Client Registration + authorize/token am Domain-Root; Login mit MCP-Key, Token traegt dessen Scopes. Dual-Auth (statischer Key ODER OAuth). Siehe mcp/README.md.

    2026-07-04 (Geo-Reihe komplett)

    • Neu (Tasks): geo_lade (Kartenobjekte in Kontext), geo_verschneidung (intersection/union/difference/symdifference, optional als Kartenobjekt speichern), geo_wfs (WFS-GetFeature mit GML-3.2-Fallback fuer ALKIS & Co.), geo_visualisieren (OpenLayers-Karten-Viewer mit Basemap.de/Luftbild-DOP/DTK/OSM + schaltbaren Layern, oeffentlicher Link karte.php?id=...). Editor-Palette-Gruppe Geo-Operationen erweitert. End-to-end getestet: ALKIS-WFS -> Verschneidung (56 ha) -> Karten-Link.

    2026-07-04 (MCP)

    • Neu: Workflow-MCP-Server unter /mcp (JSON-RPC). Gescopte API-Keys (read/author/interact) via Admin-Konsole im Dashboard. 10 Tools zum Erstellen/Bearbeiten/Starten von Workflows und Interagieren mit Instanzen. Siehe mcp/README.md.

    2026-07-04 (Editor)

    • Neu (Visueller Editor): Persistente Baustein-Palette links neben dem Baum. Tasks werden per Drag-and-Drop aus der Palette in die Container (Sequenz/Parallel/then-else/Wurzel) gezogen. Ersetzt das bisherige, schwer auffindbare "+"-Einfügen (nur am Container-Ende). Touch-tauglich (SortableJS forceFallback) für Tablet-Nutzung. Umsortieren bestehender Karten unverändert.

    2026-07-02

    • Fix (Engine): stop-Task setzte den Gesamtstatus nicht auf CANCELLED. Der Persist-Block in require-workflow.php behandelte nur success/error/return/waiting — bei stop fiel der Status auf den Default RUNNING zurück und der Bearbeiter blieb zugewiesen. Folge: abgelehnte Workflows (z. B. Dienstreise nach Vorsitz-Ablehnung) blieben als offene Aufgabe hängen, cron-resume triggerte sie endlos, und der Bearbeiten-Link führte nur zur Sackgasse "Vorgang abgebrochen". Behoben: eigener stop-Zweig → CANCELLED + current_assignee = NULL. Wirkt für alle stop-Quellen (approve_reject-Ablehnung, quorum, TaskStop). Verhalten entspricht jetzt der bereits korrekten Doku (README "Lebenszyklus und Status", tasks/stop.md).

    2026-07-04

    • Neu (Task): geo_flaeche — Muster-Task der Geo-Reihe. Fläche von Polygon-Kartenobjekten (EPSG:25833) in m²/ha, per Inline-GeoJSON oder Layer+VKZ aus KARTE_OBJEKT. Rechen-Engine MariaDB ST_Area (SRID-0-planar). Siehe tasks/geo_flaeche.md. Editor-Schema + Palette-Gruppe 'Geo-Operationen' ergänzt.