Verweise auf fremde Akten: Zugehörigkeitsprüfung in allen Server Actions durchgehen #23

Closed
opened 2026-08-23 16:55:31 +00:00 by florian.wilde · 1 comment
Owner

Problem

Wenn ein Formular einen anderen Datensatz verknüpft (Konto, Vertrag,
Immobilie, Kontakt, Dokument), muss die Server Action prüfen, ob dieser
Datensatz zur selben betreuten Person gehört. An mehreren Stellen fehlte
diese Prüfung.

Gefunden und bereits behoben wurde sie bei:

  • Vermögensposten speichern — kontoId wurde geprüft, vertragId und
    immobilieId nicht (Issue #8)
  • Buchung speichern — vertragId ungeprüft (Issue #8)
  • Ansprechpartner am Vorgang — von vornherein mit Prüfung gebaut
    (Issue #9)

Das waren aber nur die Stellen, die mir beim Arbeiten an anderen Aufgaben
vor die Füße gefallen sind. Ein systematischer Durchgang steht aus.

Warum das zählt

Solange nur eine betreute Person angelegt ist, ist es folgenlos. Sobald
es zwei sind, kann ein manipuliertes Formular eine Verknüpfung über
Aktengrenzen hinweg anlegen — und dann steht etwa der Rückkaufswert der
einen Akte am Vertrag der anderen, oder ein fremder Name im Briefkopf.

Was ich will

  • Alle Server Actions unter src/server/actions/ daraufhin durchsehen,
    ob jeder Fremdschlüssel aus dem Formular gegen betreuteId geprüft
    wird
  • Die Prüfung als gemeinsame Hilfsfunktion, statt sie zehnmal
    abzuschreiben — dann fällt beim nächsten neuen Verweis eher auf, wenn
    sie fehlt
  • Ergebnis kurz festhalten: welche Stellen geprüft, welche gefunden

Akzeptanzkriterien

  • Jeder aus einem Formular gelesene Verweis wird gegen die Akte
    geprüft, bevor er gespeichert wird
  • Die Prüfung liegt an einer Stelle, nicht verstreut
  • Für mindestens einen Fall gibt es einen Test, der den Verweis auf
    eine fremde Akte abweist
  • Fehlerfall meldet verständlich („gehört nicht zu dieser betreuten
    Person"), statt zu werfen

Hinweis

Keine Migration. Sicherheitsnaher Aufräumpunkt.

Angelegt auf Zuruf im Chat, nicht aus dem Dashboard — bitte in Nebula
nachtragen.

## Problem Wenn ein Formular einen anderen Datensatz verknüpft (Konto, Vertrag, Immobilie, Kontakt, Dokument), muss die Server Action prüfen, ob dieser Datensatz zur selben betreuten Person gehört. An mehreren Stellen fehlte diese Prüfung. Gefunden und bereits behoben wurde sie bei: - Vermögensposten speichern — `kontoId` wurde geprüft, `vertragId` und `immobilieId` nicht (Issue #8) - Buchung speichern — `vertragId` ungeprüft (Issue #8) - Ansprechpartner am Vorgang — von vornherein mit Prüfung gebaut (Issue #9) Das waren aber nur die Stellen, die mir beim Arbeiten an anderen Aufgaben vor die Füße gefallen sind. Ein systematischer Durchgang steht aus. ## Warum das zählt Solange nur eine betreute Person angelegt ist, ist es folgenlos. Sobald es zwei sind, kann ein manipuliertes Formular eine Verknüpfung über Aktengrenzen hinweg anlegen — und dann steht etwa der Rückkaufswert der einen Akte am Vertrag der anderen, oder ein fremder Name im Briefkopf. ## Was ich will - Alle Server Actions unter `src/server/actions/` daraufhin durchsehen, ob jeder Fremdschlüssel aus dem Formular gegen `betreuteId` geprüft wird - Die Prüfung als gemeinsame Hilfsfunktion, statt sie zehnmal abzuschreiben — dann fällt beim nächsten neuen Verweis eher auf, wenn sie fehlt - Ergebnis kurz festhalten: welche Stellen geprüft, welche gefunden ## Akzeptanzkriterien - [ ] Jeder aus einem Formular gelesene Verweis wird gegen die Akte geprüft, bevor er gespeichert wird - [ ] Die Prüfung liegt an einer Stelle, nicht verstreut - [ ] Für mindestens einen Fall gibt es einen Test, der den Verweis auf eine fremde Akte abweist - [ ] Fehlerfall meldet verständlich („gehört nicht zu dieser betreuten Person"), statt zu werfen ## Hinweis Keine Migration. Sicherheitsnaher Aufräumpunkt. _Angelegt auf Zuruf im Chat, nicht aus dem Dashboard — bitte in Nebula nachtragen._
florian.wilde added the in-arbeit label 2026-08-23 19:38:22 +00:00
florian.wilde started working 2026-08-23 19:38:44 +00:00
florian.wilde worked for 1 hour 41 minutes 2026-08-23 21:20:38 +00:00
Author
Owner

🚀 Umgesetzt und nach main übernommen.

  • Merge-Commit: d75eb18
  • Pull Request: #34 (gemergt)
  • Gesamtaufwand: 01:42

Der Durchgang — alle 22 Dateien unter src/server/actions/

Das Ergebnis ist besser als befürchtet: Bis auf eine Stelle war jeder Verweis geprüft.

Stelle Befund
Buchung: kontoId, belegId, vertragId war geprüft
Buchung: vorgangId ungeprüft — geschlossen
Vermögensposten, Saldostand, Wertstand, Nachweisdokument geprüft
Kontaktprotokoll, Dokumentverknüpfungen, Fristen geprüft
Genehmigung, Beschlussdokument, Schreiben geprüft
Belegmappe: vorgangId sicher, weil die Abfrage ohnehin auf die Akte eingeschränkt ist

Die gemeinsame Stelle: src/lib/auth/verweise.ts. Die acht erlaubten Ziele sind eine ausgeschriebene Aufzählung statt eines dynamischen Tabellenzugriffs — so sieht der Typprüfer jede Abfrage, und welche Tabellen erreichbar sind, ist eine Entscheidung und keine Nebenwirkung. Mehrere Verweise werden nebeneinander geprüft.

Umgestellt: die vier Einzelprüfungen der Buchung, die drei des Vermögenspostens, die eigene Hilfsfunktion für den Ansprechpartner. Bewusst nicht angefasst: Stellen mit eigener, passenderer Form — etwa das Kontaktprotokoll, das beide Verweise parallel lädt und feldgenaue Meldungen liefert.

So prüfst du es

  1. git switch main && git pull && npm run dev
  2. Einen Vorgang öffnen, im Auswahlfeld Ansprechpartner per Entwicklerwerkzeug einen Eintrag mit einer erfundenen Id einfügen, auswählen, speichern.
    Erwartet: „Dieser Kontakt gehört nicht zu dieser betreuten Person." — und keine Verknüpfung in der Datenbank.
  3. Dasselbe bei einer Buchung mit einem fremden Vorgang.
  4. npx playwright test e2e/fremdakte.spec.ts — deckt beides ab.

Zwei Dinge, die ich falsch angefangen hatte

  1. Mein erster Test rief die Server Action per fetch nach. Der wäre auch ohne jede Prüfung grün gewesen, weil Next einen Aufruf ohne gültige Action-Id ohnehin ablehnt — er hätte nichts bewiesen. Ersetzt durch den Weg über das echte Formular; die Gegenprobe mit ausgebauter Prüfung bestätigt, dass er anschlägt.
  2. Der Test riss beim ersten Lauf regelmäßig in die Zeitgrenze. Ursache war nicht der Code, sondern die Übersetzung der Route im Entwicklungsmodus. Frist auf 45 s gesetzt, mit Begründung im Test.

Zur Testsuite, in Klartext: Der volle Lauf meldete zunächst 6 Fehlschläge von 137, ein zweiter 3, ein dritter 0. Alle waren Zeitüberschreitungen beim ersten Aufruf einer Route (15–25 s Übersetzungszeit je Route laut Log; warm antwortet dieselbe Seite in 0,3 s), keiner ein falsches Ergebnis, und alle in Bereichen, die diese Änderung nicht berührt.

655 Unit-Tests grün, Typecheck und Lint sauber. Weder Changelog noch Version — sichtbar ändert sich nichts.

🚀 **Umgesetzt und nach `main` übernommen.** <!-- claude-status branch: fix/23-fremdschluessel-pruefen merge: d75eb18 pr: 34 zeit_sekunden: 6114 --> - Merge-Commit: `d75eb18` - Pull Request: #34 (gemergt) - Gesamtaufwand: 01:42 **Der Durchgang — alle 22 Dateien unter `src/server/actions/`** Das Ergebnis ist besser als befürchtet: Bis auf **eine** Stelle war jeder Verweis geprüft. | Stelle | Befund | |---|---| | Buchung: `kontoId`, `belegId`, `vertragId` | war geprüft | | **Buchung: `vorgangId`** | **ungeprüft — geschlossen** | | Vermögensposten, Saldostand, Wertstand, Nachweisdokument | geprüft | | Kontaktprotokoll, Dokumentverknüpfungen, Fristen | geprüft | | Genehmigung, Beschlussdokument, Schreiben | geprüft | | Belegmappe: `vorgangId` | sicher, weil die Abfrage ohnehin auf die Akte eingeschränkt ist | **Die gemeinsame Stelle:** `src/lib/auth/verweise.ts`. Die acht erlaubten Ziele sind eine ausgeschriebene Aufzählung statt eines dynamischen Tabellenzugriffs — so sieht der Typprüfer jede Abfrage, und welche Tabellen erreichbar sind, ist eine Entscheidung und keine Nebenwirkung. Mehrere Verweise werden nebeneinander geprüft. Umgestellt: die vier Einzelprüfungen der Buchung, die drei des Vermögenspostens, die eigene Hilfsfunktion für den Ansprechpartner. Bewusst **nicht** angefasst: Stellen mit eigener, passenderer Form — etwa das Kontaktprotokoll, das beide Verweise parallel lädt und feldgenaue Meldungen liefert. **So prüfst du es** 1. `git switch main && git pull && npm run dev` 2. Einen Vorgang öffnen, im Auswahlfeld *Ansprechpartner* per Entwicklerwerkzeug einen Eintrag mit einer erfundenen Id einfügen, auswählen, speichern. Erwartet: „Dieser Kontakt gehört nicht zu dieser betreuten Person." — und keine Verknüpfung in der Datenbank. 3. Dasselbe bei einer Buchung mit einem fremden Vorgang. 4. `npx playwright test e2e/fremdakte.spec.ts` — deckt beides ab. **Zwei Dinge, die ich falsch angefangen hatte** 1. Mein erster Test rief die Server Action per `fetch` nach. Der wäre auch ohne jede Prüfung grün gewesen, weil Next einen Aufruf ohne gültige Action-Id ohnehin ablehnt — er hätte nichts bewiesen. Ersetzt durch den Weg über das echte Formular; die Gegenprobe mit ausgebauter Prüfung bestätigt, dass er anschlägt. 2. Der Test riss beim ersten Lauf regelmäßig in die Zeitgrenze. Ursache war nicht der Code, sondern die Übersetzung der Route im Entwicklungsmodus. Frist auf 45 s gesetzt, mit Begründung im Test. **Zur Testsuite, in Klartext:** Der volle Lauf meldete zunächst 6 Fehlschläge von 137, ein zweiter 3, ein dritter 0. Alle waren Zeitüberschreitungen beim ersten Aufruf einer Route (15–25 s Übersetzungszeit je Route laut Log; warm antwortet dieselbe Seite in 0,3 s), keiner ein falsches Ergebnis, und alle in Bereichen, die diese Änderung nicht berührt. 655 Unit-Tests grün, Typecheck und Lint sauber. Weder Changelog noch Version — sichtbar ändert sich nichts.
florian.wilde removed the in-arbeit label 2026-08-23 21:22:38 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Total Time Spent: 1 hour 41 minutes
florian.wilde
1 hour 41 minutes
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: florian.wilde/betreuungs-cockpit#23