MUSTERDATEN · keine echten Personen
Pflege-PosteingangÜber das Projekt
Nicht angemeldet

Über das Projekt

Unabhängige Bewerbungsdemo, inspiriert von KLARA — kein Produkt der Hochschule Anhalt. Bewerbung auf Stelle Nr. 479 (Wissenschaftliche Mitarbeit Web Engineering). Alle Personen und Dokumente sind erfundene Musterdaten. Stand: 04.11.2026.

Demo: https://pflege-posteingang-demo.vercel.app · Repository: https://github.com/baseaccountai/pflege-posteingang-demo

Was die Anwendung macht

In Pflegeeinrichtungen kommen Arztbriefe, Medikationspläne und Überleitungsbögen weiterhin auf Papier an und werden von Hand in die Dokumentation übertragen. Der Pflege-Posteingang ist der digitale Eingang dafür, mit generativer KI und einer Sicherheitsarchitektur, die man in der Oberfläche sehen und ausprobieren kann:

SchrittWas passiertWo die KI begrenzt wird
1. ErfassenFoto oder PDF hochladen; OCR macht daraus TextPrüfung auf versteckte Anweisungen, bevor ein Sprachmodell den Text sieht
2. Prüfen und FreigebenDie KI schlägt Bewohner, Diagnosen, Medikation und Wiedervorlagen vor; die API gleicht jeden Wert mit der wörtlichen Textstelle im Dokument ab, das Original steht daneben; ein Medikationsabgleich zeigt neu, geändert, abgesetztEin Mensch gibt frei. Ohne Bestätigung des Bewohners geht nichts in die Akte
3. BewohnerakteFreigegebene Daten mit Herkunft: aus welchem Dokument, von wem freigegebenRow Level Security: jede Pflegekraft sieht nur ihren Wohnbereich
4. Fragen (RAG)Fragen an die freigegebenen Dokumente; Antworten nur mit geprüften QuellenzitatenDas Modell sieht keine Namen, nur Platzhalter wie Bewohner_K42
5. AgentEin Agent liest mit den Rechten der Pflegekraft und schlägt Wiedervorlagen vorEigenes Agenten-Token; gespeichert wird erst nach „Bestätigen“
6. ProtokollDie Pflegedienstleitung sieht, wer wann welches Modell genutzt hat und was blockiert wurdeProtokoll nur für die PDL, Akteur setzt die Datenbank

Die Bilder stammen aus der lokalen Testumgebung mit Modell-Attrappe (daher „fake-llm“ als Modellname); in der öffentlichen Demo arbeitet an derselben Stelle Mistral.

Startseite mit Projektkarte, Anforderungs-Landkarte und Rollenwahl

Posteingang: ein Medikationsplan bereit zur Prüfung, ein präparierter Brief als verdächtig markiert

Prüfen und Freigeben: KI-Vorschlag und Medikationsabgleich gegen die Akte (unverändert, geändert, neu, abgesetzt)

Angriff erkannt: die unsichtbare weiße Schrift im PDF wird sichtbar gemacht

Bewohnerakte: Medikation, Diagnosen, Wiedervorlagen und Dokumente, jeder Eintrag mit Herkunft

Fragen an die Dokumente: Antwort mit Quelle und dem, was das Modell tatsächlich gesehen hat

Agent: Vorschlag einer Wiedervorlage, erst nach Bestätigung gespeichert

Kein Zugriff: Wohnbereich 2 öffnet die Akte aus Wohnbereich 1

Bewohnerakte auf dem Handy

Bezug zur Stelle

„Sie verfügen über …“ – wo es in der Demo zu sehen ist (dieselbe Zuordnung steht als Anforderungs-Landkarte auf der Startseite):

AnforderungUmsetzungIn der AppIm Repository
Softwarearchitektur, Web-Backend (Python/TypeScript)Next.js als Backend-for-Frontend (TypeScript), FastAPI (Python) als Sicherheitsschicht, Postgres; arc42 mit 12 ADRs–Architektur, apps/api/, apps/web/
Anbindung von LLMs über APIsMistral OCR, Mistral Small (Feldvorschläge, Antworten, Agent), Ministral (Prüfmodell), mistral-embed; Anbieter per Konfiguration austauschbar, TageskontingentePosteingangproviders/, extraction/
RAG und agentenbasierte KIStrukturbewusstes Chunking, Vektorsuche nur im eigenen Wohnbereich, Antworten nur mit geprüften Zitaten; Agent mit Function Calling, fünf Werkzeugen und BestätigungspflichtFragen, Agentrag/, agent/
IT- und API-Sicherheit, OAuth 2.0/OIDCOIDC-Login (Code + PKCE) über den BFF, Tokens nie im Browser, Zugriff im Namen des Nutzers unter RLS, Agenten-Token per Token Exchange (RFC 8693)Rollenwahl, Bewohnerauth/, Migrationen, ADR 0012
wünschenswert: lokale SprachmodelleKomplett lokaler Betrieb mit make up-local: Ollama (qwen3:8b, bge-m3), Docling und Keycloak, ohne Cloud-Dienst; nur per Konfiguration umgeschaltet–ollama.py
wünschenswert: Docker, CI/CDDocker-Images für Web und API; GitHub Actions: Tests, Secret-Scan, Deployment nur bei grüner CI, nächtlicher Reset–Workflows, infra/
wünschenswert: Sicherheitsrisiken von LLM-AnwendungenBedrohungsmodell nach OWASP Top 10 für LLM-Anwendungen, fünf Schichten gegen Prompt-Injection, gemessen auf einem TestkorpusPosteingang (Musterdokumente mit Angriff)Bedrohungsmodell, security/

Aufgaben der Stelle – was die Demo davon im Kleinen vorwegnimmt:

AufgabeIn der Demo
Sicherheitsrisiken generativer KI untersuchen (Prompt-Injection, RAG, Agenten)Bedrohungsmodell, präparierte Musterdokumente, Angriffskorpus mit 134 Angriffen und Bericht
Systemarchitektur: Schnittstellen, Rollen- und Rechtekonzepte, modulare KI-ModelleRollen aus OIDC-Claims, RLS je Wohnbereich, Agent mit eigener Identität, Anbieter hinter Schnittstellen
Sicherheitskonzepte unter DSGVO und EU AI Act, Vergleich Cloud und lokalPseudonymisierung vor jedem Modell, ehrlich benannte Grenze bei der OCR, Hinweis „KI-Antwort, bitte prüfen“, Protokoll. Eine Einordnung nach AI Act und der Messvergleich Cloud gegen lokal stehen noch aus
Sicherheitskomponenten spezifizieren, implementieren, testenJede Funktion als Spec mit Akzeptanzkriterien, testgetrieben umgesetzt, Sicherheitstests in der CI

Technologie

RolleÖffentlichLokalBegründung
Web-AppNext.js 16, Tailwind, shadcn/ui, PWA auf Vercel (fra1)DockerADR 0004, ADR 0008
BackendPython 3.12, FastAPI auf Vercel (fra1)DockerADR 0001, ADR 0011
Daten, Vektoren, DateienSupabase (Postgres, pgvector, RLS), Region IrlandSupabase lokalADR 0002, ADR 0010
Login (OIDC)Zitadel CloudKeycloak bzw. Test-IdPADR 0005
OCRMistral OCRDoclingADR 0003
SprachmodelleMistral Small, Ministral 8B, mistral-embedOllama (z. B. Qwen3 8B, bge-m3)ADR 0003
CI/CDGitHub Actions––

Welcher Anbieter läuft, entscheidet allein die Konfiguration (OCR_PROVIDER, LLM_PROVIDER, OIDC_ISSUER …), nicht der Code. Für Tests gibt es zu jedem Anbieter eine Attrappe.

Architektur

Architektur: Browser, Next.js als BFF, FastAPI als Sicherheitsschicht, Supabase mit RLS, Identity Provider und KI-Anbieter

Grundsätze (arc42-Dokument):

  • Next.js ist nur Backend-for-Frontend. Der Browser bekommt ein Sitzungs-Cookie, die Tokens liegen verschlüsselt (AES-256-GCM) in Postgres (ADR 0009).
  • FastAPI ist die Sicherheitsschicht. Sie prüft jedes Token selbst und ruft Modelle nur über ein einziges Modell-Tor auf. Ein Architekturtest stellt sicher, dass kein anderes Modul einen Anbieter direkt nutzt.
  • Die Rechte liegen in der Datenbank. Die API greift im Namen des Nutzers oder des Agenten zu (set local role + Claims je Transaktion, ADR 0007). Row Level Security trennt die Wohnbereiche auch dann, wenn die API einen Fehler hätte. Der Service-Schlüssel dient nur Seed und Reset.

Datenfluss beim Einlesen: Datei → OCR → Prüfung auf versteckten Text und Regeln (lokal, ohne Cloud-Modell) → Pseudonymisierung → Prüfmodell → Feldvorschlag → Freigabe durch einen Menschen → Chunking (Überschriften, Tabellen ganz, sonst rekursiv mit ca. 600 Tokens und 12 % Überlappung) → Embeddings → pgvector mit Wohnbereich, Bewohner, Dokumenttyp, Datum und Seite. Verdächtige Abschnitte werden nicht indiziert.

Datenfluss bei einer Frage: Frage → Prüfung auf Angriffe → Vektorsuche unter RLS → Namen durch Platzhalter ersetzt → Modell → Ausgabe geprüft (nur Zitate aus den gefundenen Quellen, keine Links oder Bilder) → Platzhalter zurückübersetzt → Antwort mit Quellen → Protokoll.

Datenfluss beim Agenten: Token der Pflegekraft → Token Exchange bei Zitadel → Agenten-Token (sub = Pflegekraft, act = Agent) → höchstens vier Werkzeugschritte, fünf Modellaufrufe, 60 Sekunden → Vorschlag (15 Minuten gültig) → „Bestätigen“ durch die Pflegekraft → erst dann legt der Agent die Wiedervorlage an.

Sicherheit und Datenschutz

Rollen und Rechte

WerSiehtDarf
Pflegekraft WB1 / WB2Bewohner und Dokumente des eigenen Wohnbereichserfassen, freigeben, fragen, Agent beauftragen und bestätigen
Pflegedienstleitungbeide Wohnbereiche und das Protokollwie oben, dazu Protokoll
Agenthöchstens, was die beauftragende Pflegekraft siehtlesen, Wiedervorlage vorschlagen; anlegen erst nach Bestätigung

Ein fremder Bewohner und einer, den es nicht gibt, ergeben dieselbe Antwort. So verrät die Demo in aller Regel nicht einmal, dass es einen Datensatz gibt. Das gilt auch für den Agenten: Fragt man ihn nach einer Person aus dem anderen Wohnbereich, antwortet er, ohne ein Modell aufzurufen (eine Ausnahme steht unter „Offene Grenzen“).

Was der Agent nicht kann: Medikation ändern, Daten löschen, Nachrichten nach außen senden, andere Wohnbereiche lesen. Diese Aktionen gibt es nicht als Werkzeug, und die Datenbank würde sie dem Agenten-Token auch nicht erlauben. Steht in einem Dokument eine Anweisung an die KI, entsteht daraus höchstens ein offener Vorschlag, den ein Mensch verwerfen kann.

Pseudonymisierung: Bevor ein Sprachmodell einen Text sieht, ersetzt die API Namen und Geburtsdaten aller Bewohner, weitere Personen nach Anrede oder Titel, Telefonnummern, E-Mail-Adressen, Versichertennummern und Adressen durch Platzhalter. Die Zuordnung bleibt im Speicher der API. Das Modell-Tor prüft unmittelbar vor dem Aufruf noch einmal: Steht noch ein Klarname im Text, wird das Modell nicht aufgerufen. Bei jeder Antwort kann man aufklappen, was das Modell tatsächlich gesehen hat.

Prompt-Injection: fünf Schichten, weil kein einzelner Filter zuverlässig ist:

SchichtMaßnahme
1. Dokument prüfenRegeln für typische Angriffsmuster; versteckter Text im PDF (weiße oder winzige Schrift)
2. PrüfmodellMinistral bewertet jeden Abschnitt (nur pseudonymisierten Text)
3. Prompt-AufbauDokumentinhalte als markierte Daten, getrennt von den Anweisungen
4. Minimale RechteRLS, eingeschränktes Agenten-Token, Bestätigungspflicht
5. Ausgabe prüfennur Zitate aus erlaubten Quellen, keine Klarnamen, keine Links

Gemessen an Dokumenten, auf einem Testkorpus mit 134 Angriffen (deepset/prompt-injections, eigene Angriffe nach BIPIA-Muster, eigene Pflege-Angriffe) und 62 harmlosen Pflegetexten (Bericht vom 31.10.2026):

SchichtErkennungsrateFehlalarmrate
Regeln allein12,7 % (17/134)0,0 % (0/62)
Prüfmodell (ministral-8b-latest)88,8 % (119/134)11,3 % (7/62)
beide zusammen89,6 % (120/134)11,3 % (7/62)

Fragen und Agent-Aufträge prüft das Prüfmodell mit einer eigenen Anweisung: Aufgaben wie „Plane eine Blutdruckkontrolle“ sind kein Angriff, nur Versuche, die KI umzusteuern (Regeln aufheben, Rolle wechseln, Bestätigung umgehen, Anweisungen preisgeben). Anlass war der Realtest: Mit der Anweisung für Dokumente hielt Ministral normale Agent-Aufträge für Angriffe. Gemessen auf 26 harmlosen Anfragen und 21 Angriffen in Auftragsform (Bericht vom 02.11.2026, Vergleich mit der Dokument-Anweisung):

PrüfanweisungErkennungsrateFehlalarmrate
für Dokumente (vorher)100,0 % (21/21)30,8 % (8/26)
für Anfragen (jetzt)100,0 % (21/21)3,8 % (1/26)

Liefert das Prüfmodell kein verwertbares Urteil, wird die Anfrage trotzdem nicht ausgeführt, aber mit eigener Meldung statt „Angriff erkannt“; das Protokoll nennt den Grund.

Erkennungsmuster und Testkorpus liegen getrennt. Die CI prüft bei jedem Push, dass die Regeln nicht schlechter werden.

Offene Grenzen, ehrlich benannt (Bedrohungsmodell):

  • Die Cloud-OCR sieht das Originaldokument mit Namen; nur der lokale Betrieb mit Docling vermeidet das.
  • Die öffentliche Demo nutzt den kostenlosen Mistral-Tarif, der Eingaben zum Training verwenden darf – unkritisch, weil nur erfundene Musterdaten verarbeitet werden. Für echte Pflegedaten wären ein Tarif ohne Trainingsnutzung und ein Auftragsverarbeitungsvertrag nötig – oder der komplett lokale Betrieb.
  • Etwa jeder zehnte Angriff kommt durch die Erkennung, am häufigsten Rollenspiele (Jailbreaks, 64,7 % erkannt). Die Schichten 3 bis 5 begrenzen dann die Wirkung: Nichts geht ohne Freigabe in die Akte, und der Agent kann nur vorschlagen.
  • 11,3 % Fehlalarme bei harmlosen Texten: Ein markiertes Dokument wird nicht gelöscht, sondern einem Menschen zur Prüfung gezeigt.
  • Der Anfragen-Korpus ist klein (47 Einträge, alle vom selben Autor wie die Prüfanweisung); 100 % Erkennung dort heißt nicht, dass jeder umformulierte Angriff erkannt wird.
  • Die Pseudonymisierung arbeitet mit dem Verzeichnis der Bewohner und mit Regeln. Ein Name ohne Anrede, der nicht im Verzeichnis steht, kann durchrutschen.
  • Beim Agenten verrät ein bloßer Nachname ohne Anrede, ob es ihn im anderen Wohnbereich gibt: Er wird sofort abgewiesen, ein unbekanntes Wort geht ans Modell. Daten werden dabei nicht sichtbar; schließen ließe sich das erst mit Namenserkennung (NER).

Vorgehen

  • Spec vor Code: 13 Funktionen (F01–F13), jede mit Anforderungen, Design und Aufgaben im Kiro-Stil (ADR 0006), zusammen 176 Akzeptanzkriterien in EARS-Form („WENN …, DANN soll das System …“). Code entstand erst nach Freigabe der Spec (docs/specs/).
  • Testgetrieben: Akzeptanzkriterien und Tests sind über ihre Kennungen verknüpft; die Regel lautet: erst der Test, dann sein Fehlschlag, dann der Code. Stand: rund 1 040 API-Tests (pytest, davon 433 gegen eine echte Postgres-Datenbank mit RLS), 377 Web-Tests (Vitest, davon 20 gegen die Datenbank) und 87 End-to-End-Abläufe (Playwright), jeweils auf Desktop und Handy – zusammen rund 1 600 Tests. Sprachmodelle sind in den Tests Attrappen. Echte Modelle prüft ein kleiner, getrennter Satz von Realtests.
  • Phasen mit Halte-Punkt: Jede Phase endet mit grünen Tests, einem unabhängigen Code-Review (Codex) und einer Entscheidung des Bewerbers, ob und wie es weitergeht.
  • KI-gestützt entwickelt: Der Code entstand mit Claude Code als Coding-Agent. Feste Regeln (CLAUDE.md) legten dabei Specs, Tests, Reviews und Sicherheitsgrenzen fest. Der Bewerber hat jede Spec und jede Phase freigegeben.

Ergebnisse und Ausblick

Ergebnisse:

  • Die Sicherheitsarchitektur ist in einer laufenden Anwendung sichtbar: Rollen, RLS, Agenten-Token und Pseudonymisierung kann man ausprobieren, ebenso Angriffe über die Musterdokumente im Posteingang.
  • Messwerte statt Behauptungen: Erkennungs- und Fehlalarmrate je Schicht und Kategorie.
  • Missbrauchsschutz: Tageskontingente begrenzen die öffentliche Demo, zum Beispiel auf 50 OCR-Seiten und 100 Modellaufrufe pro Tag; die Länge jedes Aufrufs ist ebenfalls begrenzt.
  • Realtest des Agenten gegen Mistral und Zitadel: Er brachte zwei Fehler ans Licht, die die Attrappen nicht zeigen konnten (Fehlalarme des Prüfmodells bei normalen Aufträgen, Rückfragen des Agenten, obwohl ein Auftrag nur einen Durchgang hat). Beide sind behoben und mit Tests belegt.
  • Komplett lokal läuft dieselbe Anwendung ohne Cloud-Dienst (Keycloak, Docling, Ollama). Auf einem Laptop ohne GPU ist das langsam: qwen3:8b schreibt etwa 1,3 Tokens/s, ein Feldvorschlag dauert rund 13 Minuten. Der lokale Modus zeigt, dass es geht und dass kein Text den Rechner verlässt; für den Alltag bräuchte er eine GPU oder ein kleineres Modell.

Noch offen: ein gemessener Vergleich der Qualität von Cloud- und lokalen Modellen (Feldvorschläge, Antworten, Erkennungsrate).

Was im KLARA-Kontext als Nächstes käme:

ThemaNächster Schritt
Vergleich Cloud und lokalGleicher Korpus und gleiche Fragen gegen Mistral und lokale Modelle; Ergebnis als Entscheidungshilfe für Einrichtungen
PseudonymisierungErkennung von Namen per NER (z. B. Presidio) zusätzlich zum Verzeichnis; Messung der Trefferquote
AgentenFeinere Delegation (Scopes je Werkzeug), Widerruf laufender Aufträge, Prüfung weiterer Werkzeuge
RegulierungEinordnung nach EU AI Act und DSGVO-Folgenabschätzung gemeinsam mit Pflegepraxis und Medizinethik
PraxiserprobungRückmeldungen von Pflegekräften zu Verständlichkeit von Belegen, Warnungen und Bestätigungen

Betrieb

Öffentliche Demo: https://pflege-posteingang-demo.vercel.app. Auf der Startseite gibt es einen Knopf je Rolle mit dem Benutzernamen (pflege-wb1, pflege-wb2, pdl). Die Passwörter stehen in der Bewerbung und nicht im Repository: Mit öffentlichen Zugangsdaten könnte jeder die Tageskontingente aufbrauchen, und die Demo wäre ausgerechnet bei der Begutachtung ohne KI. Sie liegen nur als Secrets vor und werden alle 15 Minuten zurückgesetzt, falls jemand sie ändert.

Ohne Anmeldung zeigt /muster eine Musterakte. Jede Nacht um 3 Uhr werden alle Daten auf die Musterdaten zurückgesetzt. Uploads sind auf fünf pro Sitzung begrenzt. Bitte keine echten Personendaten hochladen. Schläft die Datenbank (kostenloser Tarif), zeigt die App „Demo startet gerade …“. Ob der KI-Anbieter gerade erreichbar ist, steht unten auf der Projektseite („KI-Anbieter: erreichbar“).

Lokal, ohne Konto und ohne Schlüssel (Supabase, Web, API, Test-IdP, Attrappen für OCR und LLM):

make setup     # einmalig: Abhängigkeiten und Playwright-Browser
make up-test   # alles starten
make smoke     # prüft Startseite, API mit Datenbank und Test-IdP
make test      # Unit-Tests API und Web
make e2e       # End-to-End auf Desktop und Handy

Mit make up laufen echte Anbieter und der IdP aus der .env.

Komplett lokal, ohne Cloud-Dienst (Keycloak, Docling, Ollama auf dem eigenen Rechner, etwa 10 GB freier Arbeitsspeicher):

ollama pull qwen3:8b && ollama pull bge-m3
make up-local      # anmelden mit den lokalen Passwörtern, z. B. pflege-wb1 (siehe README)
make smoke-local   # prüft alle Dienste und ruft die echten Modelle einmal auf

Weitere Befehle und gemessene Laufzeiten stehen in der README.

Aus der laufenden Demo

Gemessene Erkennungs- und Fehlalarmrate des Schutzes vor Prompt-Injection: Sicherheitsbericht

Agenten-Token: Token Exchange (RFC 8693) bei Zitadel: Der Identity Provider tauscht das Token der Pflegekraft gegen ein Agenten-Token (sub = Pflegekraft, act = Agent) und protokolliert jede Delegation. ADR 0012

KI-Anbieter: erreichbar

Welche KI sieht welche Daten

SchrittÖffentlich (Mistral)Lokal
Texterkennung (OCR)Original (Bild bzw. PDF)Docling auf dem eigenen Rechner
Feldvorschlagnur PlatzhalterOllama auf dem eigenen Rechner
Suche (Embeddings)nur PlatzhalterOllama auf dem eigenen Rechner
Antwort auf Fragennur PlatzhalterOllama auf dem eigenen Rechner

Platzhalter: Bewohner werden zu „Bewohner_K42“, ihre Geburtsdaten zu „Geburtsdatum_K42“, Ärztinnen und Ärzte zu „Person_1“, Telefonnummern zu „[TELEFON_1]“. Die Zuordnung bleibt im Backend. Grenze: Namen ohne Anrede oder Titel, die nirgends bekannt sind, werden nicht erkannt.