# Workflow Editor n8n-inspirierter Editor zum Erstellen von Aufgabenlisten (Tasks) für die stadtbote-App. Funktionsblöcke werden per Drag & Drop auf einem Canvas angeordnet und verbunden; daraus wird das app-konforme `tasks`-JSON erzeugt. ## Funktionen - Funktionsblöcke für die stadtbote-Task-Typen (Ankunft, Unterschrift, Fotos, Quittungsgeber, Stationshinweis, Kommissionsnummer, Abhol-/Lieferstatus) - Erzeugen des app-konformen Task-JSON - Eigene Typen mit konfigurierbaren Vorgaben - Aufruf per Deep-Link mit Übergabe von Tasks, eigenen Typen und Metadaten als JSON-Body - Rückgabe der bearbeiteten Tasks und des vollständigen eigenen Typkatalogs an den Aufrufer ## Technik - Java 21, Spring Boot 3, Vaadin 24 - Drawflow als Canvas-/Node-Editor ## Konfiguration Für den Editor ist keine Datenbank erforderlich. Tasks und eigene Typen werden beim Aufruf übergeben und bei **Fertig** an den Aufrufer zurückgegeben. Der Aufrufer ist für deren dauerhafte Speicherung verantwortlich. Optionale Einstellungen sind in `.env.example` beschrieben. ## Start ```bash mvn spring-boot:run ``` Die Anwendung läuft anschließend unter http://localhost:8080/. ## Aufruf und Rückgabe mit dem Python-Testserver Die Webapp muss mit dem aktuellen Code auf Port 8080 laufen. In einem zweiten Terminal den Testserver starten (Python 3, keine zusätzlichen Pakete): ```bash python3 tools/editor_test_server.py ``` Der Testserver öffnet seine Aufruferseite unter `http://127.0.0.1:8090`. Dort das Beispiel bearbeiten oder eigenes JSON einfügen und den Editor öffnen. Der Editor erscheint eingebettet in der Seite. **Fertig** gibt die validierten Tasks und den vollständigen Katalog eigener Typen zurück; **Abbrechen** meldet den Abbruch ohne bearbeitete Tasks oder Typen. Beide Ergebnisse werden im Python-Terminal als JSON ausgegeben und auf der Testseite angezeigt. Nach **Fertig** enthält das JSON-Eingabefeld die Rückgabe für den nächsten Editor-Aufruf. **Neue Liste** leert die Tasks und behält den aktuellen eigenen Typkatalog. Nach **Abbrechen** bleibt die Eingabe unverändert. Die Testseite hält diese Daten nur bis zum Neuladen; die Konsolenausgabe bleibt im Terminal verfügbar. Eine Datei vorgeben oder andere Ports verwenden: ```bash python3 tools/editor_test_server.py --json tools/example_tasks.json python3 tools/editor_test_server.py --editor-url http://127.0.0.1:8080 --port 8090 --no-browser ``` Als Eingabe ist ein Task-Array oder ein Objekt erlaubt: ```json { "name": "Testauftrag", "tasks": [{ "type": 3, "topic": "Ankunft melden", "track": true }], "customTypes": [], "metadata": { "auftragId": "TEST-4711", "revision": 2 } } ``` Für eine neue Liste `tasks` weglassen oder `[]` übergeben. Die Metadaten werden unverändert zurückgegeben. Zum Abschließen eines neu aufgebauten Workflows müssen Start, Aufgaben und Abschluss vollständig verbunden sein. Beim Import vorhandener Tasks ergänzt der Editor die internen Start-/Abschlussmarkierungen; sie sind nicht Teil des zurückgegebenen Task-Arrays. ### Eigene Typen `customTypes` enthält den vollständigen Katalog für diesen Editor-Aufruf. Ohne dieses Feld oder mit `[]` stehen nur die eingebauten Typen zur Verfügung. Eigene Typen werden vor den Tasks geladen. Ein Task verweist mit `type` auf die `taskType`-Nummer seines eigenen Typs (ab 1000), beispielsweise: ```json { "name": "Zustellnachweis", "tasks": [{ "type": 1000, "topic": "Zustellung fotografieren", "min": 1, "max": 3 }], "customTypes": [{ "typeId": "custom-1000", "taskType": 1000, "baseTypeId": "fotos-aufnehmen", "label": "Zustellnachweis", "description": "Fotos zur Dokumentation einer Zustellung.", "icon": "vaadin:camera", "color": "#059669", "inputs": 1, "outputs": 1, "properties": [ { "id": "min", "label": "Mindestanzahl Fotos", "type": "NUMBER", "defaultValue": 1 }, { "id": "max", "label": "Maximale Anzahl Fotos", "type": "NUMBER", "defaultValue": 3 }, { "id": "opt", "label": "Optionale Aufgabe", "type": "BOOLEAN", "defaultValue": false }, { "id": "reenter", "label": "Erneut bearbeitbar", "type": "BOOLEAN", "defaultValue": true } ] }], "metadata": { "auftragId": "TEST-4711" } } ``` `properties` beschreibt die Eigenschaften samt Vorgabewerten; `type` ist dabei einer der Werte `TEXT`, `TEXTAREA`, `NUMBER`, `BOOLEAN`, `FIELD_LIST`, `NAME_LIST` oder `CHOICE_LIST`. Das mitgelieferte Beispiel `tools/example_tasks.json` enthält einen eigenen Foto-Typ und einen zugehörigen Task. Bei **Fertig** wird `customTypes` immer vollständig zurückgegeben, einschließlich unveränderter und neu angelegter Typen. Der Aufrufer ersetzt seinen bisherigen Katalog durch dieses Array, damit auch gelöschte Typen berücksichtigt werden. `[]` bedeutet, dass keine eigenen Typen mehr vorhanden sind. Bei **Abbrechen** übernimmt der Aufrufer keine Änderungen. ### Übergabeprotokoll Die Python-Seite ruft serverseitig `POST /api/editor/import` auf und ergänzt `returnOrigin`, z. B. `http://127.0.0.1:8090`. Die Antwort enthält `token` und `deepLink`. Der Aufrufer öffnet den Deep-Link in einem iframe oder Popup. Der Import bleibt für 30 Minuten im Speicher der Webapp verfügbar, sodass ein Neuladen während dieser Zeit möglich ist. Der Editor sendet das Ergebnis per `postMessage` ausschließlich an diese Origin: ```json { "type": "tasklist-editor:result", "token": "", "status": "completed", "name": "Testauftrag", "metadata": { "auftragId": "TEST-4711", "revision": 2 }, "tasks": [{ "s_id": 1, "type": 3, "topic": "Ankunft melden", "track": true }], "customTypes": [] } ``` Bei Abbruch ist `status` gleich `cancelled`; die Felder `tasks` und `customTypes` entfallen. Die Testseite prüft Absender-Origin, Fenster und Token und leitet das Ergebnis an `POST /api/result` des Python-Servers weiter. Erst nach dessen Bestätigung wird der iframe geschlossen. Ohne `returnOrigin` zeigt der Editor einen schreibgeschützten JSON-Dialog zum Kopieren mit `name`, `metadata`, `tasks` und `customTypes`. Der Testserver ist ein lokales Entwicklungswerkzeug und bindet an `127.0.0.1`. Er übernimmt bekannte Task-Felder des Editors; unbekannte Task-Typen werden vom bestehenden Importer übersprungen. Beliebige zusätzliche Daten daher in `metadata` übergeben.