Files

326 lines
22 KiB
Markdown
Raw Permalink Normal View History

# Workflow-System
Dieses System führt **Workflows aus, die vollständig als XML-Dateien definiert sind**. Eine Workflow-Datei beschreibt eine Abfolge von Schritten (Tasks) — Formulare, Genehmigungen, E-Mails, PDF-Verarbeitung, Bedingungen — und die Engine arbeitet diese Schritte sequenziell oder parallel ab.
Die wichtigsten Eigenschaften:
- **XML statt Code**: Neue Abläufe entstehen durch Anlegen einer XML-Datei, nicht durch Programmierung.
- **Tokenbasiert und zustandslos**: Jeder Schritt ist ein normaler Web-Aufruf. Der komplette Zustand (erledigte Tasks, gesammelte Variablen) wird serverseitig gespeichert — Bearbeiter können Tage später weitermachen, ohne dass etwas verloren geht.
- **Benutzer-Interaktion per Weblink**: Wenn ein Schritt eine Person erfordert (Formular ausfüllen, genehmigen, abstimmen), erhält diese automatisch eine E-Mail mit einem persönlichen Link.
- **E-Mail-Benachrichtigungen**: Zuweisungen, Rückgaben und Erinnerungen werden automatisch verschickt.
- **PDF-Verarbeitung**: Hochgeladene PDFs können gestempelt, mit Text befüllt, zusammengeführt und kryptografisch signiert werden.
- **Parallelität und Abstimmungen**: Unabhängige Zweige laufen parallel; N-von-M-Abstimmungen (Quorum) sind eingebaut.
Typischer Ablauf: Ein Mitarbeiter startet einen Workflow, füllt ein Formular aus, ein Vorgesetzter bekommt per Mail einen Genehmigungslink, das Dokument wird gestempelt und das Ergebnis per Mail zugestellt — alles definiert in einer einzigen XML-Datei.
## Grundkonzepte
### Workflow-Definition als XML-Datei
Jeder Workflow ist eine `.xml`-Datei im Workflow-Ordner der Installation. Der Dateiname (ohne `.xml`) ist gleichzeitig der Name des Workflow-Typs. Die Datei beschreibt alle Schritte deklarativ; die Engine liest sie bei jedem Aufruf neu ein — Änderungen an der XML wirken sofort auf neue Durchläufe.
### Einen Workflow starten
Ein neuer Durchlauf wird über die Start-Seite ausgelöst:
```
start.php?xml=<name>
```
`<name>` ist der Dateiname der Workflow-XML ohne Endung (z. B. `start.php?xml=dienstreise`). Es wird ein neuer Workflow-Datensatz angelegt, der eingeloggte Benutzer als Antragsteller in den Kontext eingetragen und sofort zum ersten Schritt weitergeleitet.
### Lebenszyklus und Status
Jeder Workflow-Durchlauf hat genau einen Gesamtstatus:
| Status | Bedeutung |
|---|---|
| `RUNNING` | Workflow läuft; die Engine arbeitet automatische Schritte ab (auch nach einer Rückgabe zur Überarbeitung) |
| `WAITING` | Workflow wartet auf eine Person (z. B. Formular ausfüllen, genehmigen) |
| `COMPLETED` | Alle Tasks erfolgreich abgeschlossen |
| `ERROR` | Ein Task ist mit einem technischen Fehler abgebrochen |
| `CANCELLED` | Workflow wurde bewusst gestoppt (z. B. Ablehnung mit `stop`-Task) |
Bei jedem Aufruf läuft die Engine die XML von oben durch, überspringt bereits abgeschlossene Tasks und führt den ersten offenen Task aus. Liefert dieser `waiting`, pausiert der Workflow und der zuständige Bearbeiter wird benachrichtigt.
### Zugriffs- und Schritt-Token (Sicherheit)
Jeder Durchlauf ist über zwei Token geschützt:
- **Zugriffs-Token** (`token`): identifiziert den Workflow-Durchlauf. Ohne gültigen Token gibt es keinen Zugriff.
- **Schritt-Token** (`step`): wird für jeden neuen interaktiven Schritt frisch erzeugt und **nur per Benachrichtigungs-Mail an den zugewiesenen Bearbeiter** verschickt.
Der Link in der E-Mail hat die Form:
```
index.php?token=<zugriffs-token>&step=<schritt-token>
```
Nur der aktuell **zugewiesene Bearbeiter** sieht das interaktive Formular — alle anderen erhalten lediglich eine Status-Ansicht. Wechselt der Bearbeiter oder beginnt ein neuer Schritt, wird ein neues Schritt-Token erzeugt und der alte Link damit für interaktive Aktionen ungültig. Formulare sind zusätzlich automatisch CSRF-geschützt.
### Kontext-Variablen und Mustache-Templating
Der **Kontext** ist der gemeinsame Variablenspeicher eines Workflow-Durchlaufs. Jeder abgeschlossene Formular-Task schreibt seine Eingabefelder hinein, jeder Task kann Werte ergänzen — nachfolgende Tasks können alles davon nutzen.
In **allen Textknoten der XML** (E-Mail-Texte, Empfänger, Bedingungen, Dateiangaben, HTML) können Variablen im Mustache-Format eingesetzt werden:
- `{{variable}}` — einfacher Wert aus dem Kontext
- `{{objekt.feld}}` — verschachtelter Zugriff, z. B. `{{ICH.mail}}`
Wichtige **Systemvariablen**, die ab dem Start automatisch verfügbar sind:
| Variable | Inhalt |
|---|---|
| `{{ICH.id}}` | Personen-ID des Antragstellers (der Person, die den Workflow gestartet hat) |
| `{{ICH.vorname}}`, `{{ICH.nachname}}` | Name des Antragstellers |
| `{{ICH.mail}}` | E-Mail-Adresse des Antragstellers |
| `{{ICH.funktion}}` | Funktion/Rolle des Antragstellers |
| `{{DATE}}` | Datum des Workflow-Starts (tt.mm.jjjj) |
| `{{TODAY}}` | Tagesdatum zum Zeitpunkt des jeweiligen Schritts (z. B. für Stempel) |
| `{{WORKFLOW_ID}}` | Eindeutige numerische ID des laufenden Durchlaufs |
| `{{URL_WORKFLOW}}` | Basis-Webadresse der Workflow-Anwendung (für selbstgebaute Links) |
| `{{temp_dir}}` | Arbeitsverzeichnis des Durchlaufs für erzeugte Dateien |
| `{{latest_pdf_path}}` | Pfad der zuletzt erzeugten/bearbeiteten PDF-Datei — wird von jedem PDF-Task automatisch aktualisiert (dazu passend `{{latest_pdf_url}}` als Web-Adresse) |
### Zuweisung mit `<assign_to>`
Interaktive Tasks (Formulare, Genehmigungen, Abstimmungen) erhalten ein `<assign_to>`-Element, das bestimmt, wer den Schritt bearbeiten soll:
```xml
<task type="html_form" id="genehmigung">
<assign_to>max.mustermann@example.org</assign_to>
...
</task>
```
Erlaubt sind eine **E-Mail-Adresse**, eine **Personen-ID** aus der Benutzerverwaltung oder ein **Namens-Präfix** — natürlich auch als Variable (`{{ICH.mail}}`, `{{chef_mail}}`). Die Engine löst den Bearbeiter auf und verschickt automatisch eine Benachrichtigungs-Mail mit dem persönlichen Bearbeitungslink, inklusive persönlicher Anrede, sofern die Person im System bekannt ist.
Zwei Komfort-Regeln vermeiden Mail-Flut:
- **Selbstzuweisung**: Ist der nächste Bearbeiter der aktuell eingeloggte Benutzer, wird keine Mail verschickt — die Folgeseite erscheint direkt im Browser (Schritt-für-Schritt-Durchklicken).
- **Unveränderter Schritt**: Bleiben Bearbeiter und Schritt gleich (z. B. Seite neu geladen), wird keine erneute Mail verschickt.
## Struktur-Elemente
### `<workflow id="...">` — Wurzelelement
Jede Datei beginnt mit dem `<workflow>`-Wurzelelement. Direkt darunter steht genau ein `<task type="sequence">` als Haupt-Container:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<workflow id="mein_workflow_v1">
<task type="sequence" id="haupt">
<!-- Schritte hier -->
</task>
</workflow>
```
Jedes `id`-Attribut muss innerhalb der Datei eindeutig sein — die Engine merkt sich anhand der IDs, welche Tasks bereits erledigt sind.
### `<task type="sequence">` — Reihenfolge
Führt seine Kind-Tasks strikt nacheinander aus. Ein Task startet erst, wenn der vorherige erfolgreich abgeschlossen ist. Sequenzen können beliebig verschachtelt werden.
### `<task type="parallel">` mit `<branch>` — parallele Zweige
Führt mehrere unabhängige Zweige aus. **Der Parallel-Block gilt erst als abgeschlossen, wenn alle Zweige fertig sind.**
```xml
<task type="parallel" id="benachrichtigungen">
<branch id="zweig_a">
<task type="email" id="mail_a">...</task>
</branch>
<branch id="zweig_b">
<task type="email" id="mail_b">...</task>
</branch>
</task>
```
Wartet ein Zweig auf eine Person, pausiert der Parallel-Block an dieser Stelle und wird beim nächsten Aufruf nahtlos fortgesetzt.
**Watchdog-Zweige**: Zweige, die ausschließlich aus Wächter-Tasks der Typen `escalate`, `wait_until` oder `external_trigger` bestehen (Fristen-Überwachung, Zeitpunkt abwarten, externes Signal), werden **automatisch geschlossen, sobald mindestens ein Arbeits-Zweig komplett fertig ist**. So blockiert z. B. ein noch laufender Eskalations-Zweig den Abschluss nicht, wenn die eigentliche Arbeit bereits erledigt wurde — typisches Muster: ein Zweig mit dem Genehmigungsformular, daneben ein Watchdog-Zweig, der nach Ablauf einer Frist eskalieren würde.
## Testmodus
Für gefahrloses Testen gibt es eine einfache Konvention: Enthält der Kontext eine Variable **`test_modus_mail`** mit einer E-Mail-Adresse, werden **alle E-Mails des Workflows auf diese Adresse umgeleitet** — sowohl die Benachrichtigungs-Mails der Engine als auch die per `email`-Task verschickten Mails (CC/BCC entfallen dabei komplett). Die Zuweisungen (`assign_to`) bleiben unverändert, damit auch die Bearbeiter-Logik realistisch getestet werden kann.
Am einfachsten setzt man die Variable ganz am Anfang des Workflows per `set_var`-Task:
```xml
<task type="set_var" id="konfiguration">
<var name="test_modus_mail">tester@example.org</var>
</task>
```
Zum Produktivschalten den Wert leeren. Der Testmodus gilt nur für Workflows, die die Variable selbst setzen — andere Workflows laufen unverändert.
## Minimalbeispiel
Ein vollständiger kleiner Workflow: Antragsteller füllt ein Formular aus, eine zweite Person genehmigt oder lehnt ab, der Antragsteller erhält das Ergebnis per Mail.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<workflow id="minimal_antrag_v1">
<task type="sequence" id="haupt">
<!-- 1. Antrag: Formular für den Antragsteller (Person, die den Workflow startet) -->
<task type="html_form" id="antrag">
<assign_to>{{ICH.mail}}</assign_to>
<config>
<required>betreff,begruendung</required>
<html><![CDATA[
<!DOCTYPE html>
<html lang="de">
<head><meta charset="UTF-8"></head>
<body>
<form method="post">
<h2>Antrag stellen</h2>
<p><label>Betreff<br>
<input type="text" name="betreff"></label></p>
<p><label>Begründung<br>
<textarea name="begruendung"></textarea></label></p>
<button type="submit">Absenden</button>
</form>
</body>
</html>
]]></html>
</config>
</task>
<!-- 2. Genehmigung: die zuständige Person erhält automatisch eine Mail mit Link -->
<task type="approve_reject" id="genehmigung">
<assign_to>chefin@example.org</assign_to>
<config>
<title>Antrag prüfen: {{betreff}}</title>
<subtitle>Antrag von {{ICH.vorname}} {{ICH.nachname}}</subtitle>
<output_var>decision</output_var>
</config>
</task>
<!-- 3a. Bei Ablehnung: Mail an Antragsteller, dann Workflow beenden -->
<task type="if" condition="{{decision}} == 'rejected'">
<then>
<task type="email" id="mail_ablehnung">
<config>
<an>{{ICH.mail}}</an>
<titel>Ihr Antrag wurde abgelehnt</titel>
<text><![CDATA[
Hallo {{ICH.vorname}},<br><br>
Ihr Antrag "{{betreff}}" vom {{DATE}} wurde abgelehnt.<br>
<strong>Begründung:</strong> {{decision_reason}}
]]></text>
</config>
</task>
<task type="stop" id="ende_abgelehnt">
<message>Der Antrag wurde abgelehnt.</message>
</task>
</then>
</task>
<!-- 3b. Bei Genehmigung: Bestätigungsmail -->
<task type="email" id="mail_genehmigt">
<config>
<an>{{ICH.mail}}</an>
<titel>Ihr Antrag wurde genehmigt</titel>
<text><![CDATA[
Hallo {{ICH.vorname}},<br><br>
Ihr Antrag "{{betreff}}" vom {{DATE}} wurde genehmigt.
]]></text>
</config>
</task>
</task>
</workflow>
```
Ablauf: Datei z. B. als `minimal_antrag.xml` speichern, dann per `start.php?xml=minimal_antrag` starten. Nach dem Absenden des Antrags erhält `chefin@example.org` automatisch eine Benachrichtigungs-Mail mit dem persönlichen Genehmigungslink; nach der Entscheidung wird der Antragsteller informiert und der Workflow steht auf `COMPLETED` (bzw. `CANCELLED` bei Ablehnung).
---
# Task-Referenz
Jeder Task-Typ ist in einer eigenen Datei unter [`tasks/`](tasks/) dokumentiert — mit Zweck, allen Parametern (Pflicht/Default), Eingangs- und Ausgangswerten und einem XML-Beispiel. Die Tabellen hier geben den Schnellüberblick: Task ansehen, Kurzbeschreibung lesen, per Klick in die Detail-Doku springen.
Die Struktur-Container `sequence` und `parallel`/`branch` sind oben unter [Struktur-Elemente](#struktur-elemente) beschrieben.
## Steuerung, Logik und Zeit
| Task | Was er kann |
|---|---|
| [`aktenzeichen_vergabe`](tasks/aktenzeichen_vergabe.md) — Aktenzeichen vergeben | Kollisionssicher die nächste Nummer aus einem jahresweisen Nummernkreis ziehen und formatieren. |
| [`beleg_abgleich`](tasks/beleg_abgleich.md) — Belege abgleichen | Felder zweier Datensätze mit Toleranzen vergleichen (z. B. Bestellung ↔ Rechnung). |
| [`calc`](tasks/calc.md) — Berechnung | Wertet arithmetische/logische Ausdrücke sicher aus und schreibt die Ergebnisse als Kontextvariablen. |
| [`decision_table`](tasks/decision_table.md) — Entscheidungstabelle | Mehrspaltige Entscheidungstabelle (DMN-light) statt verschachtelter if-Kaskaden. |
| [`escalate`](tasks/escalate.md) — Eskalation bei Fristüberschreitung | Hält den Workflow bis zum Ablauf einer Frist im Wartezustand; solange bleibt der ursprüngliche Bearbeiter zuständig. |
| [`event_race`](tasks/event_race.md) — Ereignis-Wettrennen | Ereignisbasiertes Gateway: die zuerst abgeschlossene Warte-Option gewinnt, der Rest wird storniert. |
| [`external_trigger`](tasks/external_trigger.md) — Auf externen Callback warten | Pausiert den Workflow, bis ein externes System (Signatur-Dienst, Webhook, Pipeline, manueller Klick) eine generierte Callback-URL mit einmaligem Token aufruft. |
| [`foreach_parallel`](tasks/foreach_parallel.md) — Parallele Multi-Instanz | Kind-Tasks je Listenelement unabhängig ausführen, optional mit Abschlussbedingung. |
| [`frist_rechner`](tasks/frist_rechner.md) — Fristen berechnen | Verwaltungsfristen mit Bekanntgabefiktion, Feiertagen und Werktagsregel berechnen. |
| [`if`](tasks/if.md) — Bedingte Verzweigung | Führt abhängig von einer Bedingung die Tasks im `<then>`- oder im optionalen `<else>`-Zweig aus. |
| [`json_transform`](tasks/json_transform.md) — JSON umformen | Werte per Pfadausdruck aus JSON ziehen und als Kontextvariablen ablegen. |
| [`log_step`](tasks/log_step.md) — Audit-Log-Eintrag | Schreibt einen unveränderlichen Eintrag in das Audit-Log des Workflows (mit Task-ID, Aktion, Benutzer, Details und Zeitstempel). |
| [`loop_foreach`](tasks/loop_foreach.md) — Schleife über eine Liste | Iteriert über ein Array aus dem Kontext und führt die direkt enthaltenen Kind-Tasks pro Element aus. |
| [`map_lookup`](tasks/map_lookup.md) — Wertetabelle / Mapping | Bildet einen Eingabewert über eine Inline-Tabelle auf einen Zielwert ab — spart lange `<if>`-Kaskaden für Zuordnungen wie Status → Empfänger oder Typ → Feldname. |
| [`return_to`](tasks/return_to.md) — Zur Überarbeitung zurückgeben | Setzt frühere Schritte zurück, indem die angegebenen Task-IDs aus dem Ausführungsstatus gelöscht werden — sie laufen beim nächsten Trigger erneut. |
| [`schedule_resume`](tasks/schedule_resume.md) — Geplante automatische Fortsetzung | Pausiert den Workflow und plant einen Weck-Zeitpunkt, zu dem der Workflow automatisch fortgesetzt wird — im Gegensatz zu `wait_until`, das passiv auf den nächsten Trigger wartet. |
| [`set_var`](tasks/set_var.md) — Kontextvariablen setzen | Setzt eine oder mehrere Kontextvariablen ohne Benutzerinteraktion. |
| [`signal_fire`](tasks/signal_fire.md) — Internes Ereignis auslösen | Feuert ein Ereignis auf dem internen Event-Bus der Anwendung, sodass registrierte Listener reagieren — ohne Umweg über die HTTP-API. |
| [`signal_wait`](tasks/signal_wait.md) — Auf Signal warten | Pausieren, bis ein anderes Ereignis ein passendes Signal (Name + Korrelation) hinterlegt. |
| [`stop`](tasks/stop.md) — Workflow abbrechen | Bricht den gesamten Workflow sofort ab; die Engine setzt den Gesamtstatus auf `CANCELLED`. |
| [`subworkflow`](tasks/subworkflow.md) — Anderen Workflow einbetten | Lädt eine zweite Workflow-XML (Name ohne `.xml` aus dem Workflow-Verzeichnis) und führt sie synchron im laufenden Workflow aus — inklusive Wartezuständen. |
| [`try_catch`](tasks/try_catch.md) — Fehlergrenze mit Retry | Fehler abfangen, mit Backoff wiederholen und im catch-Zweig weiterlaufen statt den Workflow abzubrechen. |
| [`wait_until`](tasks/wait_until.md) — Bis Zeitpunkt warten | Pausiert den Workflow bis zu einem festen oder relativen Zeitpunkt. |
| [`wiedervorlage`](tasks/wiedervorlage.md) — Wiedervorlage | Vorgang bis zu einem Termin parken und dem Bearbeiter mit Notiz wieder vorlegen. |
## Interaktion und Kommunikation
| Task | Was er kann |
|---|---|
| [`approve_reject`](tasks/approve_reject.md) — Genehmigen/Ablehnen | Zeigt dem Bearbeiter eine JA/NEIN-Entscheidungsseite, optional mit eingebetteter PDF-Vorschau im Vollbild. |
| [`assign_group`](tasks/assign_group.md) — Gruppen-Freigabe | Genehmigungsschritt an eine Gruppe zustellen; wer zuerst entscheidet, übernimmt (claim). |
| [`calendar_event`](tasks/calendar_event.md) — Kalendereintrag anlegen | Legt vollautomatisch (ohne Benutzerinteraktion) einen Ereignis-Eintrag an — Termin, Frist oder Vermerk — und verknüpft ihn mit einem Bezugsobjekt (z. |
| [`cloud_link`](tasks/cloud_link.md) — Öffentlichen Cloud-Freigabelink erzeugen | Gibt eine Datei im angebundenen Cloud-Speicher per öffentlichem Link frei und schreibt die Link-URL in den Kontext. |
| [`email`](tasks/email.md) — E-Mail versenden | Versendet eine E-Mail (ohne Benutzerinteraktion) mit Betreff, Text und optionalen Anhängen. |
| [`html_form`](tasks/html_form.md) — Freies HTML-Formular | Rendert ein beliebiges, selbst definiertes HTML-Formular und blockiert den Workflow, bis der Benutzer es absendet; `<assign_to>` bestimmt Bearbeiter und Benachrichtigung. |
| [`load_person`](tasks/load_person.md) — Personendaten nachladen | Lädt einen Personen-Stammdatensatz anhand einer ID, E-Mail-Adresse oder Login-Kennung aus der Personenverwaltung und stellt ihn strukturiert im Kontext bereit — typisch, um Anrede oder Mail-Adresse einer über eine ID referenzierten Person zu ermitteln. |
| [`mkz_pick`](tasks/mkz_pick.md) — Maßnahmen auswählen | Interaktive (Mehrfach-)Auswahl von Maßnahmen (MKZ) eines Verfahrens aus einer filterbaren Liste. |
| [`person_pick`](tasks/person_pick.md) — Person auswählen | Interaktive Auswahl einer oder mehrerer Personen über ein durchsuchbares Dropdown. |
| [`quorum`](tasks/quorum.md) — Abstimmung (N von M) | Mehrpersonen-Abstimmung: Jede in `<assign_to>` genannte Person darf eine Stimme (Zustimmen/Ablehnen, optional mit Kommentar) abgeben. |
| [`tg_pick`](tasks/tg_pick.md) — Verfahren auswählen | Interaktive Auswahl eines Verfahrens (Teilnehmergemeinschaft) über ein durchsuchbares Dropdown (Suche nach VKZ oder Name). |
| [`webhook`](tasks/webhook.md) — HTTP-Aufruf an externe URL | Sendet einen HTTP-Request an eine beliebige URL (z. |
## KI und Fachdienste
| Task | Was er kann |
|---|---|
| [`ki_auftrag`](tasks/ki_auftrag.md) — KI-Auftrag | Freitext-Auftrag (klassifizieren/zusammenfassen/entwerfen) an die zentrale KI-Kette, optional mit Datei/Variable als Material. |
| [`ki_dok_extrakt`](tasks/ki_dok_extrakt.md) — KI-Feldextraktion | Schema-basierte Feldextraktion aus PDF/Text per KI mit Pflichtfeld-Validierung. |
| [`paperless_ablage`](tasks/paperless_ablage.md) — Archiv-Ablage | Datei mit Metadaten ins Dokumentenarchiv (Paperless-ngx) übergeben. |
| [`rag_recherche`](tasks/rag_recherche.md) — RAG-Recherche | Belegte Antwort mit Quellenangaben aus dem hausinternen Vektor-RAG. |
| [`route_dienstfahrt`](tasks/route_dienstfahrt.md) — Routing/Kilometer | Distanz/Fahrzeit über das hausinterne Routing berechnen und Kilometerangaben plausibilisieren. |
## PDF- und Dokument-Verarbeitung
> **Konvention:** Signatur-Tasks (`pdf_sign`, `pdf_sign_at_text`) gehören ans **Ende** einer PDF-Bearbeitungskette — Text-/Stempel-Tasks verwerfen beim Re-Import vorhandene Signaturen. Details in den jeweiligen Task-Dokus.
| Task | Was er kann |
|---|---|
| [`pdf_from_template`](tasks/pdf_from_template.md) — PDF aus HTML-Vorlage | Erzeugt ein neues PDF aus HTML — entweder direkt inline im XML oder aus einer hinterlegten HTML-Vorlagendatei. |
| [`pdf_merge`](tasks/pdf_merge.md) — PDFs zusammenführen | Fügt mehrere PDF-Dateien in der angegebenen Reihenfolge zu einem Gesamtdokument zusammen. |
| [`pdf_rotate`](tasks/pdf_rotate.md) — Interaktive Seitendrehung | Zeigt dem Bearbeiter eine Vorschau aller Seiten mit Dreh-Buttons (0°/90°/180°/270° je Seite, plus „Alle gleich drehen"). |
| [`pdf_sign`](tasks/pdf_sign.md) — PDF stempeln und signieren (feste Position) | Bringt einen aus Text erzeugten Sichtvermerk-Stempel an einer festen Koordinate auf und versieht das Dokument mit einer kryptografischen Signatur (systemweit hinterlegtes Zertifikat). |
| [`pdf_sign_at_text`](tasks/pdf_sign_at_text.md) — Stempeln/Signieren an gefundener Textstelle | Sucht eine Phrase im PDF-Text (z. |
| [`pdf_split`](tasks/pdf_split.md) — PDF aufteilen | Teilt ein PDF in Einzelseiten oder benannte Seitenbereiche auf. |
| [`pdf_stamp_interactive`](tasks/pdf_stamp_interactive.md) — Interaktive Stempelplatzierung | Bearbeiter platziert einen Stempel (Vorlage, Bild oder Text) per Klick frei auf der PDF-Seite; danach wird er dauerhaft eingebrannt. |
| [`pdf_text`](tasks/pdf_text.md) — Text an feste Koordinate schreiben | Schreibt einen (dynamischen) Text an eine feste Koordinate in ein bestehendes PDF — z. |
| [`pdf_text_at_text`](tasks/pdf_text_at_text.md) — Text an gefundener Textstelle schreiben | Sucht eine Phrase im PDF und schreibt relativ dazu einen Text — typischer Anwendungsfall: ein „x" in eine Checkbox neben einem gefundenen Formular-Label setzen. |
| [`vorlage_docx`](tasks/vorlage_docx.md) — DOCX aus Vorlagen-Skript erzeugen | Ruft serverseitig eine Vorlage des zentralen Vorlagen-Dienstes auf (dieselbe, die auch interaktiv im Browser genutzt wird), befüllt deren Formularfelder aus dem Workflow-Kontext und übernimmt das erzeugte DOCX in den Workflow. |