konzept vertraulich owner: matus
Prozess-Cockpit wieder anschließen — was am 2026-08-13 stillgelegt wurde und was es kostet
Prozess-Cockpit wieder anschließen — was am 2026-08-13 stillgelegt wurde und was es kostet
Status: ERLEDIGT (2026-08-15) — Weg A gebaut, nachdem Zwirn den generischen Hub bekommen hat. ·
Art: Korrektur einer von außen zugelaufenen Änderung, keine Scope-Entscheidung ·
Ursache: Zwirn / DOT-ADR-0081
Nachtrag 2026-08-15 — was tatsächlich passiert ist
Die Empfehlung unten lautete „keiner von beiden Wegen jetzt", mit einer klar benannten Bedingung: „Wenn die Authority-Entscheidung fällt, ist Weg A der richtige nächste Schritt." Beide Voraussetzungen sind seither eingetreten, und zwar in dieser Reihenfolge:
- Die Authority ist entschieden (2026-08-10, ADR-0005) — damit fiel die Blockade, die Weg A „nicht sinnvoll startbar" machte.
- Zwirn hat den generischen Aggregator gebaut (
dev.zwirn:zwirn-process-hub-router-spring, Zwirn-ADR-0042). Damit ist der Kern von Weg B ebenfalls da — nur eben in Zwirn, wo er hingehört, und nicht produktlokal hier.Umgesetzt ist deshalb Weg A auf Basis von Weg B:
tuxametrics-process-hub-cockpitist jetzt zugleich Prozessmodul (zwirn-process-api+zwirn-process-flowable) und Hub (zwirn-process-hub-router-spring), dessen Modul-Registry genau einen Eintrag hat und auf sich selbst zeigt. Der Entartungsfall N=1 wird also gefahren, aber nicht nachgebaut.Was das konkret geändert hat:
Stelle Änderung tuxametrics-process-hub-cockpit/pom.xmlzwirn-process-hub-flowable-springraus (brachte Flowables rohe REST-Fassade mit), stattdessenflowable-spring-boot-starter-process(nur Engine) + die drei Zwirn-Prozess-Artefakte +postgresql(war vorher transitiv).../config/ProcessModulKonfiguration.javadie zwei Pflicht-Ports: OwnedProcessDefinitions(tuxametrics-auswertung) undProcessModuleAuthorization(reicht das Aufrufer-Token durch, keine Rechteverstärkung).../capability/PlatformCapabilityCheckClient(Laufzeit-Check, Token-Passthrough),PlatformCapabilityAdminClient(Registrierung, Service-Account) undCapabilityRegistrar— der erste Capability-Code dieses Moduls überhauptapplication.yamlModul-Key auswertung, Capability-Präfixtxm.process, Modul-Registry aufhttp://127.0.0.1:8124tuxametrics-ui/src/App.tsx,nav/navConfig.tscreateProcessHubRoutes({})gemountet (ohne die zwei Aufgaben-Routen), Sidebar-Section „Prozesse" mit zwei Punkten zurückvite.config.ts,nginx-locations.conf/flowable-api/process-api/raus,/api/process-hub/rein (kein Rewrite nötig)domains/testfaelle/api/flowableApi.ts→prozessApi.tsmusste mit — siehe „Der Fund" unten Vier neue Capability-Schlüssel, alle rein lesend und für Agenten offen (
[USER, SERVICE, AGENT]):txm.process.process-module.read,txm.process.definition.read,txm.process.instance.read,txm.process.job.read. Hub- und Modul-Seite teilen sich bewusst ein Präfix — hier sind beide derselbe Prozess, und der Hub reicht das Token des Aufrufers durch; zwei Präfixe hätten acht Katalogeinträge und acht Grants je Praxis für vier Fragen erzeugt, die nie verschieden beantwortet werden können. Begründung im Javadoc voncapability/CapabilityRegistrar.Der Fund, der beinahe ein stiller Ausfall geworden wäre: der Abschnitt „Bewusst nicht angefasst" unten führt die
/flowable-api/process-api/-Proxyregeln als konsumentenlos. Das stimmte am 2026-08-13 und nicht mehr am 2026-08-14: die Testfall-UI hatte inzwischen ein Gold-Path-Prozessdiagramm bekommen, das Flowables rohes REST direkt anrief (domains/testfaelle/api/flowableApi.ts). Das Entfernen der Regel hätte das Diagramm ohne Fehlermeldung leer gelassen. Es ist stattdessen auf den Prozess-Vertrag umgestellt worden (prozessApi.ts,fetchDefinitions/fetchDefinitionModel) — und liest damit nebenbei erstmals mandantengescoped und capability-geprüft.Was der Umbau NICHT mitgemacht hat: den Aufgaben-Lebenszyklus (claim/complete/unclaim). Eigener Eintrag mit Begründung und Auslösebedingung:
process-hub-task-lifecycle.md.Was noch offen ist: die vier Schlüssel sind registriert, aber noch nicht gegrantet.
scripts/erste-grants-bootstrap.sqlkennt sie nicht — ohne Grant antwortet das Cockpit fail-closed mit403 (no_grant). Das ist die richtige Fehlerrichtung, aber kein fertiger Zustand.Der Rest dieses Dokuments bleibt als Herleitung stehen. Der Abschnitt „Strukturelle Ursache, die dieses Repo nicht lösen kann" (
file:-Dependency ohne Versionsgrenze) ist von alldem unberührt und gilt unverändert.
Ursprünglicher Status (2026-08-13): Sofortmaßnahme umgesetzt · Priorität: niedrig — das Cockpit hat nie einen Gold-Path-Schritt getragen
Dieses Dokument ergänzt audit-feedback-processhub-integration.md
(dort die ursprüngliche Anschluss-Entscheidung) und grenzt an
flowable-passthrough-tenant-isolation.md (dort die
Sicherheitsfrage desselben Backends).
Was passiert ist
@zwirn/bpmn ist am 2026-08-13 im Zwirn-Repo auf einen engine-agnostischen Prozess-Vertrag
umgestellt worden (DOT-ADR-0081, umgesetzt von der Zwirn-Session claude-session-process-hub-router).
Der Umbau ist inhaltlich richtig und keine Verschlechterung:
- Vorher war Flowables Wire-Format faktisch der Vertrag zwischen Backend und Cockpit. Ein Prozessmodul auf einer anderen Engine hätte es nachbauen müssen.
- Der Client
flowableClient(/flowable-api/process-api/...) ist ersatzlos entfernt. Alles läuft jetzt überprocessClient→/api/process-hub/v1/tenants/.... - Die handgepflegte Modul-Liste im Frontend (
processModules-Prop) ist entfallen; die Modul-Liste inklusive Live-Engine-Version kommt jetzt zur Laufzeit vom Hub (GET .../process-modules).
Für tuxametrics hat das eine Folge, die der Umbau selbst nicht auffangen konnte:
Die Gegenstelle, die dieses Repo betreibt, ist nicht mehr die Gegenstelle, die das Paket erwartet.
tuxametrics-process-hub-cockpit serviert Flowables eigene REST-API unter /process-api/**. Einen
Process-Hub-Aggregator unter /api/process-hub/v1/tenants gibt es hier nicht — und, das ist der
Punkt, auch in Zwirn nicht. Zwirn liefert nur die Modul-Seite des Vertrags
(dev.zwirn:zwirn-process-api → /api/v1/process-module, /api/v1/tenants/{t}/process-*). Die
Hub-Seite existiert bisher als produktlokaler Code in genau einem Repo (dot-process-hub).
Was das für die Routen bedeutet
| Seite | vor 2026-08-13 | seit dem Umbau |
|---|---|---|
ProcessCockpitPage |
funktionierte (flowableClient + auditClient) |
kein Backend |
ProcessDefinitionDetailPage |
funktionierte | kein Backend |
ProcessInstanceDetailPage |
funktionierte | kein Backend |
ProcessInstancesPage, ProcessTasksPage, TaskDetailPage |
nie gemountet (brauchten schon immer den Aggregator) | unverändert nicht gemountet |
Die ersten drei waren also nicht die Seiten mit dem bekannten Aggregator-Problem — sie liefen gegen ein real vorhandenes Backend. Sie sind erst durch den Umbau dazugekommen.
Was am 2026-08-13 getan wurde
Nach der bereits in diesem Repo etablierten Haltung — „Eine Route, die garantiert 404 liefert, ist
schlechter als eine Route, die es nicht gibt" (siehe
audit-feedback-processhub-integration.md, Abschnitt
„Was das Prozess-Cockpit hier zeigt") — sind die verbliebenen drei Seiten stillgelegt, nicht
repariert:
| Datei | Änderung |
|---|---|
tuxametrics-ui/src/App.tsx |
die 7 <Route>-Elemente der drei Seiten, ihre lazy()-Importe und die PROZESSMODULE-Konstante entfernt; Begründung als Kommentarblock an derselben Stelle |
tuxametrics-ui/src/nav/navConfig.ts |
Sidebar-Section „Prozesse" entfernt — ein Menüpunkt auf eine nicht existierende Route behauptet eine Fähigkeit, das ist dieselbe Vortäuschung eine Ebene höher |
Bewusst nicht angefasst:
- Die
file:-Dependency@zwirn/bpmnbleibt intuxametrics-ui/package.json. Der Wiederanschluss ist geplant; ein Entfernen würde nurpackage-lock.jsondurchrütteln.tsc --noEmitprüft das Paket weiterhin mit — der nächste Vertragsbruch fällt also wieder beim Bauen auf und nicht im Browser. tuxametrics-process-hub-cockpit(Service, Engine, deployte BPMN-Definition) bleibt unverändert.- Die Proxy-Regeln auf
/flowable-api/process-api/intuxametrics-ui/vite.config.tsundtuxametrics-ui/nginx-locations.confbleiben stehen — siehe „Nebenbefund" unten, das ist eine eigene Entscheidung.
Ergebnis: npx tsc --noEmit sauber, npx vite build grün. Sichtbare Nebenwirkung: @xyflow/react ist
nicht mehr im Bundle — die Dependency, wegen der @zwirn/bpmn überhaupt ein eigenes npm-Paket ist
(Zwirn-ADR-0012).
Nebenbefund: zwei Dokumente sind dadurch veraltet
audit-feedback-processhub-integration.mdsagt „ProcessModuleInfo[]bleibt leer. Ein Eintrag dort behauptete ein Prozessmodul […] für tuxametrics gäbe es dafür keine Fundstelle." Das stimmte bis 2026-08-12; danach stand dort ein Eintrag (tuxametrics-auswertung), weil inzwischen eine BPMN-Definition deployt wurde. Mit der Stilllegung ist die Aussage wieder wahr, aber aus einem anderen Grund.flowable-passthrough-tenant-isolation.mdstützt sein „heute nicht schlimm" auf zwei Punkte, von denen einer nicht mehr gilt und einer sich verschoben hat:- „Die Engine ist leer.
find . -name "*.bpmn*": null Treffer" — nicht mehr wahr, seit 2026-08-12 liegttuxametrics-process-hub-cockpit/src/main/resources/processes/tuxametrics-auswertung.bpmn20.xmlim Deployment. - „Der einzige Aufrufer ist das externe Paket
@zwirn/bpmn" — dieser Aufrufer ist jetzt weg. Damit hat der schreibfähige, nicht tenant-geprüfte Passthrough/process-api/**null legitime Konsumenten und ist reine Angriffsfläche. Das macht das Entfernen der beiden Proxy-Regeln (Vite + nginx) zur naheliegenden nächsten Sofortmaßnahme — sie ist hier bewusst nicht mitgemacht worden, weil sie die Betriebsform des Service berührt und in jenes Dokument gehört.
- „Die Engine ist leer.
Der Wiederanschluss: zwei Wege
Weg A — ein produkteigener Hub in tuxametrics-process-hub-cockpit
tuxametrics hat genau ein Prozessmodul, und es steckt im selben Service, der auch der „Hub" sein soll. Der Aggregations-Teil eines Hubs (Fan-out über N Module, Merge, Paginierung) ist hier also der Entartungsfall N = 1: reines 1:1-Routing.
Schritte:
dev.zwirn:zwirn-process-api+dev.zwirn:zwirn-process-flowableals Dependencies aufnehmen. Der Service hat bereits eine eingebettete Flowable-Engine — er wird damit ein regulärer Prozessmodul-Anbieter (/api/v1/process-module,/api/v1/tenants/{t}/process-*).- Einen dünnen Router davor, der
/api/process-hub/v1/tenants/{t}/…auf die eigene Modul-API abbildet und Instanz-/Aufgaben-Ids mit dem Routing-Key präfixt ({moduleKey}::{id}).
Das ist ausdrücklich kein 20-Zeilen-Platzhalter. Der ehrliche Aufwand liegt nicht im Routing,
sondern hier: zwirn-process-api schützt jeden Endpunkt mit Zwirns CapabilityGuard, und der ist
fail-closed. tuxametrics hat keine entschiedene Authority
(capability-authority.md) — ohne registrierte Capabilities
({prefix}.process-module.read, .definition.read, .instance.read, .job.read) antwortet jeder
Aufruf mit 403 statt 404. Ein Cockpit, das statt „nicht da" nun „verboten" sagt, ist keine
Verbesserung.
Weg A ist damit an dieselbe eine Entscheidung gekettet wie schon vier andere Services. Er wird billig, sobald die Authority entschieden ist — und ist bis dahin nicht sinnvoll startbar.
Weg B — warten auf einen geteilten Hub in Zwirn (zwirn-process-hub-spring)
Der Hub-Baustein liegt heute nur produktlokal in dot-process-hub (~750 Zeilen Kern: Router,
Instanz-/Aufgaben-Aggregator, Service-Token-Client). Ihn als wiederverwendbaren Spring-Starter nach
Zwirn zu ziehen wäre die strukturelle Lösung.
Einschätzung: sinnvoll, aber noch nicht jetzt — und nicht von hier aus zu entscheiden.
Dafür spricht: Der Hub hat keine Entities und keine eigene Datenbank (dot-process-hubs pom sagt
das ausdrücklich). Er besteht damit genau den Aufnahme-Lackmustest, an dem Zwirn-ADR-0019 die
Testfallverwaltung als Bibliothek hat scheitern lassen. Und die Vorgeschichte des Nachbarmoduls
zwirn-process-hub-flowable-spring ist die Warnung: derselbe Fund wurde erst in DOT gemacht und dann
von Hand nach evepop kopiert — exakt der Drift, den ein geteiltes Artefakt verhindert.
Dagegen spricht — und das wiegt heute schwerer: Es gibt eine einzige lauffähige Implementierung.
Ihre drei produktspezifischen Nähte sind bekannt (die dot-eigenen Capability-Key-Namen, der
dot-platform-service-eigene Token-Broker POST /api/platform/v1/tenants/{t}/service-clients/token, die
hub.*-Property-Namen), aber welche davon echte Variationspunkte sind, lässt sich aus einem Sample
nicht ablesen. Eine Bibliothek aus einer Implementierung zu extrahieren, friert geratene Nähte ein —
und Zwirn hat mit ADR-0018 → ADR-0019 bereits einmal eine zu früh gebaute Bibliothek zurücknehmen
müssen.
Und der entscheidende Punkt für tuxametrics: Der eine Konsument, der einen zweiten Beleg liefern könnte, ist dieses Repo — und tuxametrics braucht ausgerechnet den Entartungsfall N = 1, also die Variante, in der der Aggregator gar nichts aggregiert. Die allgemeine Bibliothek am Sonderfall zu entwerfen ist die falsche Reihenfolge.
Auslösebedingung, ab der Weg B gebaut werden sollte: sobald ein zweiter Hub mit echtem
Fan-out (≥ 2 Prozessmodule) entsteht — dkfz-prozesswerkstatt führt bereits einen
prozesswerkstatt-process-hub im Compose. Dann liegen zwei unabhängige Implementierungen vor und die
Nähte sind belegt statt geraten. Die Entscheidung gehört ins Zwirn-Repo (ADR-Charakter) und dort zur
Session, die den Zwirn-Teil von DOT-ADR-0081 gebaut hat — nicht hierher.
Empfehlung
Keiner von beiden jetzt. Das Cockpit hat nie einen Gold-Path-Schritt getragen; der Ablauf Patient → Befund → Auswertung → Freigabe läuft weiterhin als linearer REST-Ablauf über den Laborauswertungs-Service. Es gibt keinen fachlichen Verlust, der Dringlichkeit begründet.
Wenn die Authority-Entscheidung fällt, ist Weg A der richtige nächste Schritt — er ist dann klein,
er macht tuxametrics-process-hub-cockpit nebenbei vom Sicherheits-Sonderfall (roher
Flowable-Passthrough) zu einem regulären, capability-geschützten Prozessmodul, und er liefert Zwirn
genau den zweiten Beleg, den Weg B braucht.
Strukturelle Ursache, die dieses Repo nicht lösen kann
Der Bruch kam ohne Vorwarnung an, und das ist kein Versehen der Zwirn-Session:
@zwirn/bpmn wird als file:-Dependency konsumiert (Zwirn-ADR-0009), also direkt aus dem
Arbeitsverzeichnis des Nachbar-Repos. Es gibt damit keine Versionsgrenze: eine noch nicht einmal
committete Änderung in ../zwirn bricht hier sofort den Build. DOT-ADR-0081 nennt als Gegenmittel
ausdrücklich, „das Paket muss die Version mitziehen" — genau das ist bei einer file:-Dependency
nicht möglich, das version-Feld wird bei der Auflösung ignoriert.
Das ist eine Zwirn-Entscheidung, nicht hier zu treffen. Es ist aber der Grund, warum ein Konsument
solche Umbauten nur nachträglich bemerken kann — und ein Argument dafür, tsc --noEmit über die
file:-Pakete weiterhin mitlaufen zu lassen (siehe oben: Dependency bleibt bewusst stehen).