Brainversum · tuxametrics Graph Admin

konzept vertraulich owner: matus

Service-Landschaft

Service-Landschaft

Key: PG-DOMAINS-0001 · Domain: Projekt · siehe ../INDEX.md

Eigene Bausteine

Baustein Art Port Zweck
tuxametrics-platform-service Quarkus Data Service (plt) 8125 Die Capability-Authority (GG-ARCH-SERVICES-0005, Form „eigen"): Tenant (= Praxis), Capability-Katalog inkl. allowedActors, CapabilityGrant. Check-Endpunkt für jeden CapabilityGuard. Wire-Vertrag: CAPABILITY_CHECK_CONTRACT.md
tuxametrics-virtual-identity-service Quarkus Data Service (vid) 8126 Identity je Praxis: Personen, Funktionspostfächer und agentische Identitäten. REST /api/vid/v1, MCP nur lesend. Capability-Konsument, nicht Authority
tuxametrics-substanzstammdaten-service Quarkus Data Service (sub) 8128 Referenzkatalog Wirkstoff ← Handelsname (Medikament/Supplement). REST /api/substanz/v1, MCP nur lesend. Der einzige Fachdatenbestand dieses Produkts ohne Patientenbezug — und ohne Mandanten: alle Zeilen tragen den Sentinel platform, die API ist trotzdem tenant-skopiert (Sicherheitsgrund, siehe ADR-0012 §3). Löst Handelsname → Wirkstoff auf, schaltet damit keine Interaktionsprüfung frei
tuxametrics-laborauswertung-service Quarkus Data Service (txm) 8120 Der gesamte Gold Path: Patient, Auswertung, Intake, Findings, Therapieplan, Freigabe, Bericht. REST /api/txm/v1, MCP /mcp (nur lesend)
tuxametrics-ui React/TS, App auf @zwirn/web 5173 (dev) Slices entlang des Ablaufs plus App-Gerüst (Router, Auth, Nav)
tuxametrics-process-hub-cockpit Spring Boot + Flowable 8 8124 /process-api/** für das Prozess-Cockpit. Dünner Wrapper um dev.zwirn:zwirn-process-hub-flowable-spring, kein Fachcode. Die eine dokumentierte Ausnahme vom Quarkus-Standard (Zwirn-ADR-0007) — und die eine benannte Ausnahme von GG-DEVOPS-0003: bleibt bewusst JVM
tuxametrics-keycloak Keycloak 26.1, Realm digital-labs 8180 Der IdP. Beantwortet ausschließlich wer bist du; was darfst du beantwortet der platform-service (GG-GOV-SECURITY-0003). Clients und Claim-Mapper: keycloak/README.md
tuxametrics-db Postgres 18 5520 Eigene DB, nur der Laborauswertungs-Service
tuxametrics-platform-db Postgres 18 5524 Eigene DB der Authority
tuxametrics-vid-db Postgres 18 5525 Eigene DB der Virtual Identity
tuxametrics-substanz-db Postgres 18 5528 Eigene DB des Substanzkatalogs. Die Trennung von tuxametrics-db ist die Entscheidung: der Bestand soll perspektivisch durch eine offizielle externe Arzneimitteldatenbank ersetzbar sein, und das darf keine Operation an Befunden und Freigaben werden
tuxametrics-auth-db Postgres 18 5526 Keycloaks eigene DB — sonst läge der Realm auf einer H2-Datei im Container
tuxametrics-process-hub-db Postgres 18 5523 Flowable-Engine-DB des Cockpits. Enthält seit 2026-08-12 eine Definition (das Dokumentationsmodell des Gold Path) und keine Instanz
opa OPA-Policy-Bundle (Zwirn-ADR-0005) 8181 An der Capability-Entscheidung nicht beteiligt. Der platform-service entscheidet in Java; GG-ARCH-SERVICES-0005 nennt „Kein OPA-Zwang" als eigene Abgrenzung. Der Container stammt aus der Zeit vor der Authority — ihn zu entfernen ist eine eigene kleine Entscheidung

Mandantenschlüssel: platform ist der Sentinel für plattformweite Aggregate und Grants (util/PlatformScope) — kein echter Mandant. Seit 2026-08-26 hat er einen zweiten Nutzer außerhalb der Authority: den Substanzkatalog (util/SubstanzScope, ADR-0012). Das ist bewusst dieselbe Zeichenkette und keine zweite Konvention — beide Male heißt sie „gehört keiner Praxis". praxis01 ist der synthetische Demo-Mandant des Referenzfalls. Beide haben genau 8 Zeichen; das ist die harte Obergrenze aus GG-GOV-SECURITY-0005.

Betriebene Brainversum-Quelle (seit 2026-08-26)

Eine eigenständige brainversum-Instanz mit genau einer Quelle: der Dokumentation dieses Repos (56 Markdown-Dateien). Drei Prozesse auf einem Image, betrieben auf tuxametrics-vm. Umfang, Begründungen und Betrieb: ../../brainversum/README.md.

Baustein Art Port Zweck
tuxametrics-brainversum-ingest brainversum (Python 3.13) Liest den kuratierten Markdown-Baum alle 300 s in einen SQLite-Graphen (brainversum daemon). Kein veröffentlichter Port
tuxametrics-brainversum-web brainversum (Python 3.13) 8135 Durchsuchbare Oberfläche auf den Graphen. Volltext über FTS5/BM25
tuxametrics-brainversum-mcp brainversum (Python 3.13) 8136 MCP-Server (streamable-http, /mcp) — derselbe Bestand für einen Agenten. Nur lesend

Sie gehören nicht zum Gold Path, und die Portlücke zu 81208128 zeigt das. Diese drei Container sprechen mit keinem anderen Service dieses Stacks: keine Datenbank, kein Keycloak-Client, keine Capability, kein Eintrag im Capability-Katalog. Sie lesen Markdown und sonst nichts. Entsprechend ist GM-7 unberührt — hier wird nichts entschieden und nichts freigegeben.

Das beantwortet OF-13 nicht. Die Zeile „Second Brain" (Quellenablage) unter „Externe Abhängigkeiten" weiter unten bleibt unverändert offen. Dort geht es um die Ablage klinischer Evidenz hinter der Evidenzkennzeichnung (Epic F5 Research, nicht im Schnitt) — Fachinhalt, der in Empfehlungen einfließt. Hier geht es um die Engineering-Dokumentation dieses Repos. Gleicher Name, andere Sache; wer beides verwechselt, hält eine offene fachliche Frage für erledigt.

Eigene, isolierte Instanz — keine Föderation. Sie ist nicht die zentrale Second-Brain-Instanz des Nutzers (C:\dev\secondbrain gegen C:\brain), kennt deren Vault nicht und hat auf ihn keinerlei Zugriff. brainversum kann zwei Instanzen zusammenschalten (node/gateway, brainversum-ADR-0014 bis -0017); hier läuft der Ein-Prozess-Spezialfall. Das Zusammenschalten ist ein eigener, bewusst noch nicht gegangener Schritt — vorbereitet ist es (Ports von außen erreichbar, Quelle als eigenständiger Träger geführt), gebaut ist es nicht.

Zwei benannte Abweichungen, beide in ../../brainversum/README.md begründet: das Image lässt torch/sentence-transformers weg (318 MB statt 1,36 GB; Suche ist damit FTS5 statt hybrid — der von brainversum selbst vorgesehene Rückfall), und die zwei Ports binden auf 0.0.0.0 statt wie alles andere hier auf 127.0.0.1, weil der Zugriff von außerhalb der VM der Zweck ist. brainversum bringt keine Authentifizierung mit; es liegen dort ausschließlich Engineering-Dokumente und keine Patientendaten.

GG-DEVOPS-0003 (nativ für jeden nicht-lokalen Einsatz) greift hier nicht — das ist keine Ausnahme wie beim Process-Hub-Cockpit, sondern Nicht-Anwendbarkeit: brainversum ist Python, es gibt kein JVM-Image, das zu ersetzen wäre. Der Fußabdruck ist mit ~30–60 MiB je Prozess ohnehin die Größenordnung, auf die die Regel zielt.

Betriebene Zwirn-Docker-Services (Zwirn-ADR-0006)

Fertige Images aus dem Zwirn-Repo. Keine Java-Klasse überquert einen Classpath — der Container ist die Grenze, konsumiert wird nur über das Netz. Jeder bekommt eine eigene Datenbank; eine über Produkte hinweg gepoolte Instanz ist ausdrücklich ausgeschlossen (tenantKey ist nur innerhalb eines Produkts eindeutig). Warum sie hier stehen und was sie kosten: ../../agentic-engineering/backlog/audit-feedback-processhub-integration.md (Audit/Feedback/Process-Hub), ../../agentic-engineering/backlog/testmanagement-integration.md (Testmanagement).

Baustein Port Zweck
zwirn-audit-service 8122 Protokoll der drei fachlich bedeutsamen Übergänge: Empfehlungen erzeugt, Übersteuerung (GM-7.2), Freigabe erteilt. Frontend: @zwirn/audit
tuxametrics-audit-redis 6380 Der Ingest-Weg, nicht ein Cache: der Audit-Service hat keinen schreibenden REST-Endpunkt, er liest den Redis-Stream events
tuxametrics-audit-db 5521 Eigene DB des Audit-Service. Enthält nur Schlüssel und Zählungen — keine Messwerte, kein Patientenschlüssel, keine Freitext-Begründung
zwirn-autoimprove-service 8123 Claim-basierte Karten-Pipeline über Bugs/Ideen/Aufgaben (NEU → … → ABGENOMMEN), mit AGENT-Actor und gestaffelten menschlichen Freigaben. Registriert 16 eigene autoimprove.*-Capabilities. Frontend: @zwirn/autoimprove (ADR-0007)
tuxametrics-autoimprove-db 5522 Eigene DB des Autoimprove-Service. Port und Slot geerbt vom abgeschalteten Feedback-Service — die Volumes sind nicht übernommen (anderes Schema), Altdaten werden nicht migriert
zwirn-testmanagement-service 8127 Produktneutraler Katalog (TestGroupTestSubgroupTestCase) plus TestRun-Protokoll für den fachlichen Testfallkatalog. Kein eigenes Frontend-Paket — Seiten liegen direkt in tuxametrics-ui/src/domains/testfaelle
tuxametrics-testmanagement-db 5527 Eigene DB des Testmanagement-Service

Nicht mehr betrieben: zwirn-feedback-service. Bis 2026-08-13 hing er auf genau den zwei Ports oben; seit ADR-0007 ist er abgeschaltet, samt @zwirn/feedback, html2canvas und dem Melde-Button in der TopNav.

Der Grund ist kein Mangel des Feedback-Service. Zwirn bietet beide Bausteine unabhängig an — den leichtgewichtigen Rückkanal (OPEN → IN_PROGRESS → RESOLVED) und die claim-basierte Pipeline (NEU → BEREIT_ZUR_ANALYSE → … → ABGENOMMEN). Für ein Produkt ist die Wahl ein Entweder-oder: beide gleichzeitig zu betreiben hieße, zwei Rückkanäle mit zwei Zustandsmodellen und zwei Oberflächen für dieselbe Sache zu haben. tuxametrics hat die Pipeline gewählt; das ist eine Produktentscheidung und sagt über Zwirn nichts.

Damit ist auch die Frage von 2026-08-09 („erst Feedback sammeln, dann entscheiden, ob es eine zweite Stufe braucht") beantwortet — mit ja, aber über den kanonischen Service statt über einen Eigenbau. Das am 2026-08-13 dafür gebaute Modul tuxametrics-feedback-process (ADR-0006, Port 8128, eigene Engine-DB) ist am Tag darauf ersatzlos entfallen; es beruhte auf einem Recherchefehler, den ADR-0007 benennt.

Der erste AGENT-Actor des Produkts entsteht dabei — Keycloak-Client tuxametrics-autoimprove-agent, AGENT-Identity in der VID (boot/AgentIdentitySeeder), drei autoimprove.*-Grants. Es gibt keinen Betreiber dieser Rolle: kein Scheduler, kein Bot. Die Karten laufen bis BEREIT_ZUR_ANALYSE und bleiben dort sichtbar stehen, solange niemand claimt.

Und der erste eigene Service-Client: tuxametrics-autoimprove-service (user_key svc-tuxametrics-autoimprove, tenant_key nur ["platform"]) statt des geteilten tuxametrics-services. Damit sind es drei Keycloak-Service-Accounts statt einem geteilten für alles — und ein zweiter Bootstrap-Grant auf platform.capability.create in boot/CapabilityRegistrar der Authority. Präzedenzfall ist DOT, das denselben Schnitt gewählt hat (C:\dev\dl-controlling\dot, ADR-0071, „Dedizierter Keycloak-Client").

Ebenfalls aus dieser Adoption entstanden, weil @zwirn/autoimprove es voraussetzt: GET /api/platform/v1/me/capabilities in der Authority (web/MeResource) — die Selbstauskunft „was darf ich hier?", an der jede handelnde Schaltfläche der Zwirn-Frontend-Pakete hängt. Sie fehlte bis dahin; ohne sie wäre das Board für einen berechtigten Menschen stumm bedienungslos gewesen.

Ein Service, acht Domänen — und warum

Das Fachmaterial schneidet acht Domänen (regelwerk, patientenakte, intake, auswertung, evidenz, therapieplan, bericht, governance). Der Gold Path führt durch sechs davon, und zwar in einem Durchlauf: eine Auswertung liest Regelwerk und Intake, schreibt Findings, daraus entstehen Empfehlungen, daraus eine Freigabe, daraus ein Bericht.

Acht Services hätten für diesen einen Durchlauf sieben Netzwerkgrenzen bedeutet — bei einem Prototyp, dessen Zweck es ist, den Durchlauf zu zeigen. Der Domänenschnitt bleibt als Paketstruktur und Dokumentation erhalten (domain-map.md); die erste echte Trennung von Datenhoheit ist der richtige Zeitpunkt für eigene Services, nicht früher.

Am 2026-08-26 ist genau dieser Zeitpunkt einmal eingetreten, und das Argument oben trägt dort nicht: tuxametrics-substanzstammdaten-service liegt nicht auf dem Durchlauf (er wird nachgeschlagen, nicht durchlaufen), ist nicht patientenbezogen, nicht mandantengebunden und soll perspektivisch durch eine externe Quelle ersetzt werden. Er ist damit kein neunter Schnitt derselben Domäne, sondern die erste echte Datenhoheitsgrenze dieses Repos (ADR-0012 §1). Für die acht Fachdomänen des Gold Path bleibt die Aussage oben unverändert gültig.

Externe Abhängigkeiten

Abhängigkeit Status
Autorisierungs-Authority (Capability-Check) Entschieden und gebaut (2026-08-10): eigentuxametrics-platform-service, Port 8125 (siehe oben). ADR-0005
IdP Entschieden und gebaut (2026-08-10): Keycloak, Realm digital-labs, Port 8180 (siehe oben)
„Second Brain" (Quellenablage) Vollständig unbeschrieben (OF-13). Epic F5 Research ist nicht im Schnitt; die Evidenzkennzeichnung bleibt, die Quellenablage nicht. Unverändert offen, auch seit 2026-08-26 — seither läuft zwar eine betriebene Brainversum-Quelle, die indexiert aber die Engineering-Doku dieses Repos, nicht klinische Evidenz. Gleicher Name, andere Sache
Arzneimitteldatenbank (Handelsname → Wirkstoff) Präzisiert seit 2026-08-26, nicht erledigt (ADR-0012). Eine offizielle Datenbank ist weiterhin nicht angebunden, und das Fachmaterial hat weiterhin keine Quelle (OF-07). Was es jetzt gibt, ist ein eigener, extern belegter Startkatalog (tuxametrics-substanzstammdaten-service, 11 Wirkstoffe / 14 Handelsnamen aus Gelbe Liste und NIH ODS) — also die Fähigkeit Handelsname → Wirkstoff. Die Interaktionsprüfung bleibt trotzdem draußen: sie bräuchte zusätzlich einen Interaktionskatalog (Wirkstoff × Mikronährstoff), und den gibt es nicht
Laborschnittstelle (FACH-026) Vollständig unbeschrieben (OF-65). Erfassungsart.IMPORTIERT bleibt ungenutzt
Process-Hub-Aggregator (/api/process-hub/v1/tenants) Existiert nirgends — weder in Zwirn noch hier. Deshalb sind Prozessliste und Aufgabenliste aus @zwirn/bpmn nicht gemountet; nur das Cockpit ist verdrahtet. Seit 2026-08-14 kostet das nichts mehr: das einzige Modul dieses Produkts, das eine Aufgabenliste gebraucht hätte, ist mit ADR-0007 entfallen. Der Punkt bleibt offen, ist aber wieder rein theoretisch

Frontend: Slices plus App-Gerüst

tuxametrics-ui enthält die Domain-Slices (Model/Api/Components/Pages) nach dem Muster aus zwirn/samples/sample-frontend-react und das App-Gerüst darum herum: Vite, Router, Tailwind. Layout/Nav (AppLayout/TopNav/Sidebar) sind seit 2026-08-13 produktlokal (src/shell/, src/nav/navConfig.ts) — Muster aus den Schwesterprodukten eimr/evenews übernommen: eine einzige, immer sichtbare Sidebar statt Icon-Rail plus separatem Untermenü. @zwirn/web bleibt nur noch für Auth (useAuth, TokenSync, createOidcConfig) und Theme (useTheme) sowie das generische cn-Utility im Einsatz. Verifiziert per tsc --noEmit.

Dazu drei Zwirn-Feature-Pakete als file:-Dependency — jedes ist ein eigenes npm-Paket wegen seines Dependency-Fußabdrucks, nicht aus Ordnungsliebe (Zwirn-ADR-0009/0010/0012):

Paket Zusätzliche Last Wo eingehängt
@zwirn/audit keine Sidebar-Sektion „Protokoll" (Gruppe „Technische Daten") → audit/system-log
@zwirn/autoimprove keine Sidebar-Sektion „Autoimprove" (Gruppe „Technische Daten") → autoimprove/dashboard, …/board, …/waiting, …/history, …/modules. Ersetzt seit 2026-08-14 @zwirn/feedback (html2canvas). Der Melde-Knopf hängt weiter auf jeder Seite (shell/TopNav.tsx), kommt aber nicht aus dem Paket: es exportiert keinen. Produktlokaler Nachbau in src/domains/autoimprove/, wie in DOT (ADR-0007 §6) — ohne automatischen Screenshot, dafür mit Einfügen/Hochladen
@zwirn/bpmn @xyflow/react Sidebar-Sektion „Prozesse" (Gruppe „Technische Daten") → process-hub/cockpit. Lazy geladen, damit kein Patienten-Screen @xyflow/react mitzieht

Alle drei stehen zusätzlich in zwirn-dedupe.ts — dieselbe Symlink-Falle wie bei @zwirn/web (zwei Instanzen einer Bibliothek mit Modul-State reißen Auth bzw. Diagramm-Context auseinander).

Die IdP-Frage ist seit 2026-08-10 beantwortet. main.tsx bindet jetzt AuthShell, und die entscheidet: ein gebautes Artefakt nimmt immer OIDC (AuthProvider + createOidcConfig aus @zwirn/web, Realm digital-labs, Client tuxametrics-ui). Der DevAuthProvider bleibt daneben stehen — aber mit veränderter Bedeutung: er war der Ersatz für eine offene Entscheidung, heute ist er nur noch die Abkürzung für einen Dev-Loop ohne laufende Infrastruktur.

Befehl Auth-Weg Braucht Docker?
npm run dev dev/dev-auth-stub.mjs — kein OIDC, kein Realm, jeder Capability-Check allowed: true nein
npm run dev:oidc echter Keycloak (/realms-Proxy) + echte Authority auf 8125 ja
npm run build immer OIDC

Dass der Stub im gebauten Artefakt nicht existiert, ist keine Konvention, sondern die Bedingung aus GG-ARCH-SERVICES-0005.5. Deshalb hängt der Default an import.meta.env.PROD und nicht an einer Variable, die jemand vergessen kann.

Frontend-Module für das Claim-Board

Für CLAIMS.md ist ein Modul sonst eine Zeile aus den Tabellen oben — also ein Wurzelverzeichnis. Für tuxametrics-ui reicht das nicht: dieses eine Verzeichnis trägt acht Domain-Slices und das App-Gerüst; „ein Modul = ein Wurzelverzeichnis" hieße dort „das ganze Frontend ist ein Modul". Am 2026-08-26 kollidierte deshalb shell/TopNav.tsx (Marken-Icon) mit components/KpiCard.tsx und routes/HomeRoute.tsx (Kacheln der Startseite) — zwei Arbeiten, die sich fachlich nie berührt hätten (CLAIMS.md § Historie).

Ein Frontend-Modul ist deshalb ein Domain-Slice oder einer der geteilten src/-Bereiche:

Modulname im Board Deckt ab
tuxametrics-ui/<slice> src/domains/<slice>/** — je ein Ordner unter src/domains/
tuxametrics-ui/<bereich> src/<bereich>/** — je ein direkter Ordner unter src/ außer domains
tuxametrics-ui/app-shell alles Übrige: src/App.tsx, src/main.tsx, src/index.css, src/index.ts, package.json, vite.config.ts, index.html, tailwind.config.js

Diese Liste ist mechanisch aus dem Dateisystem abgeleitet und hier nur zur Orientierung dokumentiert — nicht vorgeschrieben. Der PreToolUse-Guard liest sie zur Laufzeit (.claude/hooks/lib.mjs, discoverFrontendModules) und löst einen konkreten Pfad ohne Umweg über eine Liste auf. Ein neuer Ordner unter src/domains/ ist damit sofort ein eigenes Modul — ohne Codeänderung und ohne Nachtrag hier. Eine handgepflegte Liste würde genau dann rotten, wenn ein Slice neu ist und Kollisionen am wahrscheinlichsten sind.

Der Stand vom 2026-08-26, rein als Momentaufnahme: Slices auswertung, autoimprove, bericht, patient, regelwerk, systemsteckbrief, testfaelle, therapieplan; geteilte Bereiche api, auth, components, lib, nav, routes, shell. Wer den aktuellen Stand braucht, liest nicht diesen Absatz, sondern ls tuxametrics-ui/src und ls tuxametrics-ui/src/domains.

Zwei Punkte, die man kennen muss:

Die Backend-Services sind davon unberührt: sie sind je ein eigenes Wurzelverzeichnis und damit bereits richtig geschnitten. Ein Modul bleibt dort das ganze Verzeichnis.