Files
betreuungs-cockpit/CHANGELOG.md
T
Florian Wilde 848aaf1b9f Absenderanschrift in jedem Schreiben
Jeder erzeugte Brief ging bisher ohne Ruecksendeadresse hinaus: Im
Absenderblock stand nur der Name, in der Datumszeile fehlte der Ort. Bei
einer Versicherung oder Behoerde wirkt das unserioes und macht es der
Gegenstelle unnoetig schwer zu antworten.

Neu unter "Mein Konto" ein Feld fuer Strasse, PLZ und Ort. Ab da stehen
sie im Absenderblock jedes Schreibens, und die Datumszeile lautet
"Bayreuth, den 23.08.2026".

Die Anschrift haengt am Benutzer, nicht an der betreuten Person: Sie
gehoert zu mir und gilt fuer alle Akten.

Nicht die Logik fehlte, sondern die Datenquelle - absenderBlock() und
datumsZeile() konnten die Felder schon, briefkopfBauen() hat sie mit
einem Kommentar auf null gesetzt, weil es sie im Datenmodell nicht gab.

Aufbau:
- Drei Felder am Benutzer, Migration ueber den Wrapper aus #24. Das war
  sein erster echter Einsatz: erzeugte Datei ohne Handarbeit brauchbar,
  DROP-INDEX-Zeilen bereits heraus.
- Ein Absender-Typ statt eines blossen Namens, durchgereicht bis in den
  Serienlauf - der hat bisher {name} gebaut und haette die Anschrift
  sonst still verloren.
- Zwei Platzhalter fuer eigene Vorlagen: betreuer_anschrift,
  betreuer_ort.

Was fehlt, bleibt weg: Jede der drei Angaben ist einzeln freiwillig. Nur
ein Ort ergibt eine Datumszeile mit Ort und einen Absenderblock, der
weiterhin nur aus dem Namen besteht. Eine halb ausgefuellte Adresse
sieht nach Fehler aus, ein blosser Name nach Absicht.

Geprueft: sieben Einheitstests fuer den Absenderblock inklusive jeder
Teilbefuellung und der Gegenprobe, dass nie die Heimadresse der
betreuten Person im Absender landet; vier End-to-End-Tests vom leeren
Zustand ueber das Speichern bis zum fertigen Brief.

Refs #21
2026-08-23 20:29:17 +02:00

51 KiB
Raw Blame History

Änderungen

Alle nennenswerten Änderungen an dieser Anwendung, in umgekehrter Reihenfolge. Aufbau nach Keep a Changelog, Versionsnummern nach Semantic Versioning.

Was hier steht: was sich für dich beim Arbeiten ändert — nicht, welche Datei angefasst wurde. Wer den technischen Verlauf braucht, findet ihn im Git-Log; jeder Commit trägt seine Etappe.

Was die Zahlen bedeuten:

Stelle Wann sie steigt Was du tun musst
Major (1.x.x → 2.0.0) Etwas verhält sich anders als vorher, oder eine Migration lässt sich nicht zurücknehmen Changelog lesen, vorher sichern, Zeit einplanen
Minor (1.0.x → 1.1.0) Neue Funktionen, alles Bisherige bleibt wie es war Changelog überfliegen, normal aktualisieren
Patch (1.0.0 → 1.0.1) Fehler behoben, sonst nichts Einfach aktualisieren

Eine Datenbank-Migration lässt sich nicht zurückrollen. Vor jedem Update ein Backup anstoßen — siehe README, Abschnitt Sicherung und Wiederherstellung.


Unveröffentlicht

Noch nichts.

1.10.0 – 2026-08-23

Hinzugefügt

  • Deine Anschrift steht jetzt in jedem Schreiben (#21). Bisher ging jeder Brief ohne Rücksendeadresse hinaus — im Absenderblock stand nur dein Name, und in der Datumszeile fehlte der Ort. Bei einer Versicherung oder Behörde wirkt das unseriös und macht es der Gegenstelle unnötig schwer zu antworten.

    Unter Mein Konto → Meine Anschrift einmal Straße, PLZ und Ort hinterlegen. Ab da stehen sie im Absenderblock jedes erzeugten Schreibens, und die Datumszeile lautet „Bayreuth, den 23.08.2026". Betroffen ist alles: Rückkaufswert-Anfrage, Serienabfrage, Kündigung, Sachstandsanfrage und die eigenen Vorlagen.

  • Zwei neue Platzhalter für eigene Vorlagen: {{betreuer_anschrift}} und {{betreuer_ort}}.

Eine Zusage

Was fehlt, bleibt weg. Jede der drei Angaben ist einzeln freiwillig. Hinterlegst du nur den Ort, bekommst du die Datumszeile mit Ort und einen Absenderblock, der weiterhin nur aus deinem Namen besteht — keine leeren Zeilen, kein Komma ohne Ort. Eine halb ausgefüllte Adresse sieht nach Fehler aus, ein bloßer Name nach Absicht.

Datenbank

Eine Migration: drei Felder am Benutzer. Die Anschrift hängt an dir und nicht an der betreuten Person — sie gilt für alle Akten.

Geprüft

  • Sieben Einheitstests für den Absenderblock, darunter jede Teilbefüllung und die Gegenprobe, dass nie die Heimadresse der betreuten Person im Absender landet.
  • Vier End-to-End-Tests: der Brief ohne hinterlegte Anschrift, das Speichern unter Mein Konto, der Brief danach und die Gegenprobe am Rückkaufswert-Schreiben.

1.9.0 – 2026-08-23

Hinzugefügt

  • Ansprechpartner am Vorgang (#9). Ein namentlich adressiertes Schreiben landet bei der Person, die den Vorgang kennt, statt in der Poststelle — beim Bezirk ist das der Unterschied zwischen zwei Wochen und zwei Monaten. Am Vorgang lässt sich jetzt ein Kontakt aus dem Verzeichnis als Ansprechpartner benennen.

  • Die Sachstandsanfrage redet ihn an. Aus „Sehr geehrte Damen und Herren" wird „Sehr geehrte Frau Sachs" — und der Name steht über der Behörde, damit die Poststelle den Brief zur Person sortiert. Auch das Schreiben aus dem Editor übernimmt Anrede, Empfänger und Anschrift, sodass nichts abgetippt werden muss.

  • Anrede am Kontakt. Damit die Briefanrede stimmt, trägt ein Kontakt wahlweise „Frau" oder „Herr". Geraten wird nie: Ohne Angabe wird mit vollem Namen angeredet („Sehr geehrte(r) Kim Berger,"). Eine falsch geratene Anrede fällt dem Empfänger sofort auf und kostet genau die Aufmerksamkeit, die man gewinnen wollte.

  • Vor dem Anruf weiß man, wen man fragt. Auf der Vorgangsseite steht der Ansprechpartner mit Organisation, Durchwahl und E-Mail, verlinkt auf den Kontakt.

Zwei Zusagen

Ohne Ansprechpartner ändert sich nichts. Ist keiner benannt, bleibt es bei „Sehr geehrte Damen und Herren" — und die Vorgangsseite sagt das auch, statt ein leeres Feld zu zeigen. Ein halb gefüllter Name führt nie zu einer verstümmelten Anrede wie „Sehr geehrte Frau ,".

Der Wechsel bleibt nachvollziehbar. Wer den Ansprechpartner austauscht, findet den Vorgänger im Protokoll — mit Namen, nicht mit der internen Kennung. Zwei Kennungen nebeneinander wären protokolliert, aber nicht nachvollziehbar.

Datenbank

Eine Migration: ansprechpartnerId am Vorgang und anrede am Kontakt. Wird ein Kontakt gelöscht, bleibt der Vorgang bestehen und verliert nur den Verweis — ein Vorgang darf nicht daran hängen, dass es den Kontakt noch gibt.

Geprüft

  • Neun Einheitstests für die Anrede, darunter der Nachname aus „Dr. Anna Maria Schmitt", der Doppelname und der Fall, der nie passieren darf: leerer Name mit gesetzter Anrede.
  • Fünf End-to-End-Tests: die allgemeine Anrede ohne Ansprechpartner, das Benennen samt Anzeige mit Durchwahl, die namentliche Anrede in der Sachstandsanfrage, die vorbelegte Anschrift im Schreiben und der Wechsel im Protokoll.

1.8.0 – 2026-08-23

Hinzugefügt

  • Der Rückkaufswert steht jetzt beim Vertrag (#8). Am Telefon mit der Gesellschaft braucht man die Zahl dort, wo man sie gefragt hat — nicht nach einem Umweg über das Vermögensverzeichnis. Auf der Vertragsseite steht deshalb oben der zuletzt mitgeteilte Wert mit Stichtag und Quelle, darunter die vollständige Historie.

  • Ein alter Wert sagt, dass er alt ist. Ist der jüngste Wert älter als ein Jahr, steht „über ein Jahr alt" daneben — in der Vertragsübersicht wie auf der Vertragsseite. Ein veralteter Betrag ohne erkennbares Alter ist schlimmer als kein Betrag: Man rechnet mit ihm weiter und merkt es erst, wenn der Bezirk nachfragt. Die Grenze von einem Jahr gilt jetzt überall dieselbe; im Vermögensverzeichnis stand sie schon, am Vertrag fehlte sie.

  • Verträge ohne Wert bleiben nicht stumm. Wo ein Rückkaufswert zu erwarten wäre, aber keiner erfasst ist, steht „noch nicht erfasst" statt einer leeren Zelle.

Behoben

  • Ein Vertrag hatte unter Umständen zwei Wertreihen. Vertrag und Vermögensposten wurden über die Art des Postens zusammengeführt. Wer einen Posten von Hand anlegte und ihn als etwas anderes als „Versicherung" führte, bekam beim ersten Eintragen am Vertrag klammheimlich einen zweiten Posten — und damit zwei Wahrheiten, von denen der Bericht die eine und der Vertrag die andere zeigte. Maßgeblich ist jetzt die Verknüpfung mit dem Vertrag, nicht die Art.

  • Fehlende Prüfung bei Verweisen auf Vertrag und Immobilie. Beim Speichern eines Vermögenspostens wurde geprüft, ob das verknüpfte Konto zur betreuten Person gehört — bei Vertrag und Immobilie fehlte dieselbe Prüfung, ebenso beim Vertragsverweis einer Buchung. Bei mehreren betreuten Personen hätte ein manipuliertes Formular eine Verknüpfung über Aktengrenzen hinweg anlegen können. Jetzt wird jeder der drei Verweise gleich behandelt.

Geprüft

  • Zehn Einheitstests: die Ein-Jahres-Grenze (auch der Tag davor und danach), das Alter taggenau und ohne Uhrzeiteinfluss, ein künftiger Stichtag, und die Zusammenführung mehrerer Posten zu einer Historie.
  • Vier End-to-End-Tests: Wert und Stichtag in der Übersicht, das Abzeichen am alten Wert, die Historie am Vertrag, und ein neu eingetragener Wert, der unverändert im Vermögensverzeichnis wiederauftaucht.

1.7.0 – 2026-08-23

Hinzugefügt

  • Eigene Vorlagen für Anschreiben (#7). Wer zum dritten Mal denselben Brief tippt, tippt ihn beim vierten Mal falsch. Neu unter Einstellungen → Schreibvorlagen: eigene Texte hinterlegen, beim freien Schreiben auswählen — der Rest füllt sich aus den Daten, die ohnehin im System stehen.

  • Platzhalter, die sich selbst erklären. Neben dem Editor steht die vollständige Liste — Name, wofür er steht, woher der Wert kommt. Ein Klick setzt ihn an die Cursorstelle; niemand muss {{…}}-Namen raten oder abtippen. Verfügbar sind unter anderem Name und Geburtsdatum der betreuten Person, ihre Anschrift, Betreuungsgericht und Aktenzeichen, das Bestellungsdatum, der Stichtag und das heutige Datum.

  • Vier mitgelieferte Vorlagen als Ausgangspunkt: Auskunftsersuchen an eine noch unbekannte Stelle, Adressänderung nach Heimeinzug, Nachweis der Vertretungsmacht (wenn eine Stelle die Auskunft verweigert) und die Kurzfassung der Rückkaufswert-Anfrage. Sie lassen sich nicht kaputt bearbeiten — „Als Kopie übernehmen" legt eine eigene Fassung an, das Original bleibt liegen. Für Rückkaufswert und Kündigung führt die Oberfläche weiter zuerst zu den fallbezogenen Erzeugern: Die rechnen Kündigungstermine aus, was eine Vorlage nicht kann.

Zwei Zusagen

Nichts geht stillschweigend schief. Fehlt ein Wert (etwa das Aktenzeichen), steht im Brief eine sichtbare Lücke [Aktenzeichen des Gerichts] — kein Leerraum, den erst der Empfänger bemerkt. Ein Tippfehler im Platzhalternamen bricht nicht ab, sondern wird im Text markiert und über dem Editor benannt.

Der Bestellungsabsatz wird nicht vergessen. Ohne den Nachweis der Vertretungsmacht kommt keine Auskunft — und das fällt erst nach vier Wochen auf. Beim Speichern einer Vorlage ohne Bestellungsabsatz kommt deshalb eine Rückfrage. Wer ihn bewusst weglässt (etwa für die zweite Mail an eine Stelle, die den Nachweis schon hat), bestätigt einmal und wird nicht weiter gefragt. Ein ausformulierter Absatz zählt genauso wie der Platzhalter.

Geändert

  • Gelöschte Vorlagen liegen wie alles andere 30 Tage im Papierkorb und lassen sich zurückholen. Beim Vollexport der Akte sind sie mit dabei.

Geprüft

  • Dreizehn Einheitstests für die Platzhalter-Ersetzung, darunter jeder der drei Fälle (Wert einsetzen, sichtbare Lücke, unbekannter Platzhalter) und die Bestellungsabsatz-Erkennung, die sich nicht von einem halben Nachweis („Beschluss der Eigentümerversammlung") täuschen lässt.
  • Sechs End-to-End-Tests: die zweistufige Warnung, das Übernehmen einer mitgelieferten Vorlage, die Auflösung im Editor samt markierter Tippfehler und der Weg durch den Papierkorb.

1.6.0 – 2026-08-23

Hinzugefügt

  • Rückkaufswerte aller Versicherungen in einem Zug anfragen (#6). Vor dem Vermögensverzeichnis und vor jedem Jahresbericht braucht es von jeder Lebens- und Rentenversicherung den Rückkaufswert zum Stichtag — jedes Mal dieselben fünf bis zehn Briefe. Das war der Handgriff, der im Jahr am meisten Zeit gekostet hat.

    Neu unter Verträge → Rückkaufswerte anfragen: Stichtag wählen, Liste prüfen, ein Klick. Heraus kommt ein ZIP mit einer Word-Datei je Gesellschaft plus Begleitblatt — und je Vertrag entsteht nebenbei die PDF-Fassung in der Akte, die Wiedervorlage nach 28 Tagen und der Vermerk, dass angefragt wurde. Auf „Heute" steht danach unter Wartet auf andere, worauf gewartet wird und seit wann.

  • Die Auswahl begründet sich selbst. Vorausgewählt ist nur, was in Frage kommt. Was nicht in Frage kommt, wird nicht stumm ausgeblendet, sondern steht mit Grund in der Liste: „Ohne Gesellschaft fehlt der Empfänger", „bereits vor 10 Tagen angefragt". Nur Vertragsarten, die nie einen Rückkaufswert bilden (Strom, Haftpflicht), bleiben draußen. Gekündigte Verträge bleiben anfragbar — bis zum Wirksamwerden besteht der Vertrag, und genau dann will der Sozialhilfeträger den Wert sehen.

  • Die Zahl steht vor dem Klick auf dem Knopf („4 Schreiben erzeugen"). Einen Fehlgriff soll man bemerken, bevor zehn Briefe entstehen — nicht danach beim Aufräumen.

Zwei Zusagen

Kein Alles-oder-nichts. Jeder Vertrag läuft für sich. Scheitert einer (etwa am Objektspeicher), steht er mit Grund im Begleitblatt des ZIP — die übrigen laufen durch. Eine Transaktion über alle wäre die falsche Zusage: Wenn der neunte Brief scheitert, sollen die acht fertigen nicht verworfen werden.

Der Doppelklick kostet nichts. Ein zweiter Lauf am selben Tag überspringt bereits angefragte Verträge und sagt es im Begleitblatt — keine doppelten Dokumente, keine doppelten Wiedervorlagen. Eine bewusste zweite Anfrage nach einer Woche (Brief verloren) bleibt möglich: von Hand anwählen genügt.

Geprüft

  • Zwölf Einheitstests für die Auswahllogik, darunter der Gleichschritt von Sperrfrist und Wiedervorlage (beide 28 Tage — liefen sie auseinander, würde gemahnt und zugleich neu angefragt).
  • Drei End-to-End-Tests: Vorauswahl samt Begründungen, der volle Lauf mit allen Nebenwirkungen in der Datenbank, und der Dublettenschutz beim zweiten Lauf.

1.5.0 – 2026-08-23

Hinzugefügt

  • Schreiben als E-Mail übernehmen (#5). Vieles geht heute per E-Mail hinaus, nicht per Brief. Im Schreiben-Editor gibt es jetzt den Umschalter Als Brief / Als E-Mail.

    Die E-Mail-Fassung wird aus dem — womöglich schon bearbeiteten — Brieftext abgeleitet: ohne Absenderblock, Anschrift und Datumszeile, die gehören in den Brief und nicht in die Mail. Der Bestellungsabsatz bleibt drin — ohne ihn kommt die Auskunft nicht. Betreff und Text sind einzeln kopierbar.

  • Zwei Wege ins Mailprogramm. Die offene Entscheidung aus dem Issue (mailto oder .eml) ist mit beides beantwortet:

    „Im Mailprogramm öffnen" (mailto) für kurze Texte — der Knopf verschwindet, sobald der kodierte Link 1800 Zeichen übersteigt. mailto übergibt den Text in der Adresszeile, deren Länge nirgends zugesichert ist; ein stillschweigend halbierter Brief fällt erst beim Empfänger auf.

    „Als E-Mail-Entwurf (.eml)" immer: eine Datei, die sich im Mailprogramm als fertiger Entwurf öffnet — Adresse, Betreff und voller Text garantiert vollständig, mit korrekt kodierten Umlauten. Die Datei erfindet bewusst keinen Absender: den trägt das Mailprogramm beim Senden selbst ein.

    Beide Knöpfe erscheinen nur, wenn eine E-Mail-Adresse da ist — aus dem gewählten Kontakt übernommen oder von Hand eingetragen. Ohne Adresse bleibt das Kopieren.

  • Die Ablage kennt den Unterschied. Eine als E-Mail abgelegte Nachricht heißt in der Akte „E-Mail: …" und die PDF-Fassung trägt die Empfängeradresse im Kopf — abgelegt wird die E-Mail-Fassung, nicht der Brieftext. In der Akte soll stehen, was tatsächlich hinausging.

Geprüft

  • 20 Einheitstests: die Ableitung der E-Mail-Fassung (nichts geht stillschweigend verloren, der Bestellungsabsatz bleibt), die mailto-Längengrenze nach der Kodierung, das .eml-Format samt Umlauten nach RFC 2047 und quoted-printable.
  • Vier End-to-End-Tests: Fassung ohne Briefkopf, .eml-Download, kein Mailknopf ohne Adresse, Ablage als gekennzeichnete E-Mail.

1.4.0 – 2026-08-23

Hinzugefügt

  • Schreiben erzeugen, ausgeben und ablegen (#4). Die Anschreiben an Versicherer und Behörden gab es bisher nur als Text zum Kopieren. Danach war Handarbeit: in Word nachbauen, ausdrucken, abschicken — und noch einmal von Hand als Dokument in die Akte legen. Vier Schritte, und der letzte wurde am häufigsten vergessen. Dann fehlt der Nachweis genau dort, wo er gebraucht wird.

    Neu unter Schreiben: Text bearbeiten, als Word-Datei herunterladen, in die Akte legen und dabei eine Wiedervorlage setzen — in einem Zug.

    Der Text bleibt vollständig bearbeitbar. Jeder Fall hat eine Besonderheit, die in den Brief gehört; ein Formulartext, den man nicht mehr ändern kann, wird früher oder später falsch abgeschickt.

  • Schreiben ohne Vertrag und ohne Vorgang. Bisher ging ein Anschreiben nur zu einem vorhandenen Datensatz. Am Anfang einer Betreuung schreibt man aber gerade an Stellen, zu denen es noch keinen gibt — man fragt ja an, um zu erfahren, ob dort überhaupt etwas besteht. Jetzt geht es an einen Kontakt oder an eine frei getippte Anschrift, aus der sich mit einem Klick ein Kontakt anlegen lässt. So wächst das Adressbuch nebenbei beim Schreiben statt durch Pflege.

  • Die Wiedervorlage entsteht mit. Rückkaufswert 28 Tage, Kündigung 21, Sachstandsanfrage 42 — jeweils änderbar, und daneben steht, warum die Frist so lang ist. Bei einer Sachstandsanfrage wird zusätzlich der letzte Kontakt am Vorgang nachgezogen, damit Wartet auf andere auf „Heute" stimmt.

Zwei Entscheidungen, die erklärt gehören

In die Akte kommt eine PDF-Fassung, heruntergeladen wird eine Word-Datei. Der Objektspeicher nimmt nur PDF und Bilder an, geprüft an den Magic Bytes — eine Word-Datei ist ein ZIP-Archiv, sie durchzulassen hieße jedes ZIP durchzulassen. Diese Prüfung ist eine bewusste Zusage der Anwendung; sie für eine Bequemlichkeit aufzuweichen wäre der falsche Handel. Und sachlich ist PDF für den Nachweis ohnehin das richtige Format: Es ändert sich nicht mehr.

Daraus folgt eine Einschränkung, die auch in der Oberfläche steht: Änderst du die Word-Datei danach noch, weicht die Akte davon ab. Dann lieber dort fertig schreiben, den Text zurückkopieren und erst dann ablegen.

Der Berichtssatz wurde nicht umgebogen. Die vorhandene DOCX-Ausgabe setzt einen Bericht mit Kopfzeilen und Unterschriftenblock; ein Brief braucht Absender, Anschriftenfeld, Datumszeile und Grußformel. Beides in eine Funktion zu zwingen hätte beide Ausgaben schlechter gemacht.

Geprüft

  • Zehn Einheitstests, darunter der Gleichschritt der Wiedervorlagefristen: Sie stehen an zwei Stellen und dürfen nicht auseinanderlaufen, sonst mahnt die Anwendung zu zwei verschiedenen Terminen.

  • Fünf End-to-End-Tests: Entwurf mit Bestellungsabsatz, Vertragsbezug, Word-Download, Ablage samt Wiedervorlage und Kontakt aus freier Anschrift.

    Zwei Fehler hat erst der Browsertest gefunden — beide in den Tests selbst: Die Dokumentenliste rendert Tabelle und Karten, je nach Bildschirmbreite ist eine davon versteckt. Ein Treffer auf die unsichtbare Fassung sieht aus wie ein Fehler in der Anwendung.

1.3.0 – 2026-08-23

Hinzugefügt

  • Dauerzahlungen zu einem Vertrag gelten als belegt (#11). Bei einer monatlichen Versicherungsprämie gibt es keinen Beleg — es gibt einen Vertrag, und der wird einmal abgeschlossen, nicht monatlich quittiert. Bisher blieb nur ein Freitextfeld pro Buchung: zwölfmal im Jahr derselbe Satz, mal Anzahl der Verträge.

    Eine Buchung lässt sich jetzt einem Vertrag zuordnen, und diese Zuordnung zählt als Nachweis. Bei einem Dauerschuldverhältnis ist der Vertrag der Beleg: Ein Rechtspfleger will für zwölf gleiche Lastschriften keine zwölf Quittungen sehen, sondern die Police.

    Die Belegquote weist drei Fälle getrennt aus — mit Beleg, durch Vertrag belegt, begründet ohne Beleg. Zusammengeworfen verlöre die Zahl ihre Aussage.

  • Automatisch beim Import, wenn die Gegenstelle zu genau einem Vertrag passt. Bei Mehrdeutigkeit geschieht nichts: Hausrat und Haftpflicht bei derselben Gesellschaft lassen sich nicht auseinanderhalten, und eine falsche Zuordnung wäre schlimmer als gar keine — sie behauptet einen Beleg, und niemand sieht noch einmal hin. Automatisch gesetzte Zuordnungen sind in der Liste als solche gekennzeichnet.

  • Sammelzuordnung unter Wiederkehrende Zahlungen: Liegt zu einer Gruppe ein Vertrag vor, werden alle ihre Zahlungen mit einem Klick zugeordnet. Bei drei Jahren Laufzeit sind das 36 Buchungen.

  • Die Rechnungslegung nennt den Vertrag. Statt „ohne Beleg – …" steht dort „Dauerzahlung zu Vertrag «Bezeichnung», Nr. …". Die Lücke wird nicht versteckt, sondern erklärt: Wer nachprüfen will, weiß sofort, welches Papier er aus dem Ordner holt.

Die Sicherung dagegen

Weicht der Betrag um mehr als ein Fünftel vom hinterlegten Beitrag ab, gilt die Zahlung nicht als belegt, sondern wird als Betrag prüfen markiert. Sonst wäre die Zuordnung eine Hintertür, durch die auch eine verzehnfachte Prämie unbemerkt durchginge.

Ein Fünftel ist bewusst großzügig: Beitragsanpassungen und Versicherungsteuer bewegen sich in dieser Größenordnung, und dabei soll die Anwendung nicht meckern. Wer die Grenze enger zieht, bekommt täglich Warnungen und sieht die eine wichtige nicht mehr.

Steht am Vertrag kein Beitrag, findet keine Prüfung statt. Die Zuordnung gilt trotzdem — es wird nur nicht so getan, als wäre geprüft worden.

Und: Verschwindet der Vertrag, fällt die Buchung zurück in „Beleg fehlt". Ein Nachweis, der auf etwas zeigt, das es nicht mehr gibt, wäre schlimmer als gar keiner.

Zu beachten

  • Eine Datenbank-Migration ist nötig (20260823062000_buchung_vertragszahlung). Sie fügt zwei Spalten hinzu und ändert nichts an vorhandenen Daten.
  • Bestehende Buchungen sind nicht betroffen: Ohne Zuordnung bleibt alles, wie es war.

Geprüft

  • 23 neue Einheitstests. Die Hälfte prüft, dass die Anerkennung auch wirklich wegfällt — der gefährliche Fehler wäre hier ein zu mildes Urteil, nicht ein zu strenges.

  • Fünf End-to-End-Tests: Sammelzuordnung, Anzeige in der Buchungsliste, die abweichende Zahlung, die Kachel auf „Heute", und der Rückfall nach dem Löschen des Vertrags.

    Der Browsertest hat zwei Fehler gefunden, die alle anderen Prüfungen durchgelassen haben — siehe unten.

Behoben

  • Die Buchungsliste hatte eine eigene, fast gleiche Datenabfrage neben der gemeinsamen aus berichte/gemeinsam.ts. Als die Dauerzahlungen dazukamen, wurde nur eine von beiden nachgezogen: In der Liste stand weiter „Beleg fehlt", obwohl der Vertrag hinterlegt war. Beide benutzen jetzt dieselbe Abbildung — die kann nicht halb vergessen werden.

1.2.0 – 2026-08-23

Hinzugefügt

  • Wiederkehrende Zahlungen aufspüren (#3). Am Anfang einer Betreuung weiß niemand, welche Verträge es gibt — es liegt kein Ordner bereit, und die betreute Person kann es oft selbst nicht mehr sagen. Die Antwort steht aber schon im Kontoauszug: Wer regelmäßig abbucht, hat einen Vertrag.

    Neu unter Vermögen & Kasse → Wiederkehrende Zahlungen: Die importierten Kontobewegungen werden nach Empfänger gruppiert und nach Jahresbetrag sortiert. Je Zeile stehen Rhythmus, Betrag, Zeitraum und ob dazu schon ein Vertrag in der Akte liegt. Aus der Zeile heraus geht es weiter — Vertrag anlegen mit vorbelegter Gesellschaft und vorbelegtem Beitrag, oder kein Vertrag mit Begründung.

    Die Seite wertet nur aus. Sie legt von sich aus nichts an; jede Zeile endet in einer Entscheidung, die ein Mensch trifft.

    Was sie nennt, begründet sie. Statt „monatlich" zu behaupten, steht daneben „6 Zahlungen, etwa monatlich" — man soll widersprechen können. Schwankt der Betrag, wird die Spanne genannt statt eines Mittelwerts, der Genauigkeit vortäuscht. Und ohne erkennbaren Abstand wird nicht aufs Jahr hochgerechnet, sondern gezeigt, was tatsächlich geflossen ist.

    Zusammengefasst wird nur, was sicher dasselbe ist: Groß- und Kleinschreibung, Satzzeichen, Umlaute und die Rechtsform am Ende. „Stadtwerke Bamberg" und „Stadtwerke Bayreuth" unterscheiden sich in drei Zeichen und bleiben zwei Zeilen. Zwei Zeilen zu viel sind harmlos — eine falsch zusammengefasste Gruppe verbirgt dagegen einen Vertrag, und der fehlt dann im Vermögensverzeichnis.

  • Einzelne größere Zahlungen stehen in einem eigenen Abschnitt darunter. Grund: Die Gruppierung braucht mindestens zwei Zahlungen, eine jährlich abgebuchte Prämie erscheint bei einem importierten Jahr aber nur einmal — und ausgerechnet Versicherungen werden oft jährlich gezahlt. Ohne diese zweite Liste wäre die Suche genau dort blind, wo sie am meisten bringen soll.

  • Hinweis auf „Heute", sobald es unbearbeitete Kandidaten gibt. Er steht in der Kachel Unverbuchte Belege, nicht in einer eigenen: Es ist dieselbe Frage — wozu gehört diese Zahlung? —, nur eine Ebene höher.

Zu beachten

  • Eine Datenbank-Migration ist nötig (20260823000500_zahlungsgruppe_geklaert). Sie läuft beim Start des Behälters automatisch mit und legt nur eine neue Tabelle an; bestehende Daten bleiben unberührt.
  • Ausgewertet werden nur Ausgaben der betreuten Person. Umbuchungen zwischen eigenen Konten und Auslagen des Betreuers bleiben außen vor — wer monatlich aufs Sparbuch legt, hat deswegen keinen Vertrag.

Geprüft

  • 37 Einheitstests (tests/wiederkehrend.test.ts), die Hälfte davon in der Gegenrichtung: dass ähnliche, aber verschiedene Namen nicht zusammenfallen.

  • Vier End-to-End-Tests gegen einen echten Browser: Erkennung, getrennte Liste der Einzelzahlungen, Übernahme ins Vertragsformular, Abhaken und Zurückholen samt Neuladen.

    Zwei Fehler hat erst der Browsertest gefunden. Einer davon hätte die Vorbelegung des Beitrags stillschweigend verschluckt — Typprüfung und Einheitstests waren grün.

1.1.2 – 2026-08-23

Behoben

  • „Mein Konto" war am Schreibtisch praktisch nicht zu finden (#1). Damit kam man dort auch nicht an den Passwortwechsel, den zweiten Faktor und die frisch eingebaute Passkey-Verwaltung.

    Ursache: Die Seitenleiste hatte keine feste Höhe und wuchs mit der Seite mit. Ihr Fuß — und damit das Benutzermenü — landete deshalb am Ende der Seite statt am unteren Bildschirmrand. Auf „Heute" waren das 1632 Pixel bei 900 Pixel Fensterhöhe: Man musste bis ganz nach unten scrollen, um an sein eigenes Konto zu kommen.

    Der Fehler sah nach nichts aus. Kein Element fehlte, nichts war kaputt, die Seite sah richtig aus — und genau deshalb sucht man an der falschen Stelle.

    Die Leiste bleibt jetzt stehen (sticky, Fensterhöhe). Kopf, Betreutenauswahl und Fuß sind immer sichtbar; die Navigation dazwischen scrollt bei Bedarf in sich selbst. Am Handy war es nie ein Problem — dort sitzt das Menü in der ohnehin festen Kopfzeile.

Geprüft

  • Fünf End-to-End-Tests (e2e/benutzermenue.spec.ts) fragen nicht, ob das Menü im DOM ist, sondern ob es im sichtbaren Bereich steht: auf fünf verschiedenen Seiten, an drei Scrollpositionen, auf einem flachen Laptopfenster (1280 × 620) und am Handy.

    Die Scrollposition in der Mitte ist Absicht. Nur oben und unten zu messen hätte nicht gereicht: Am Seitenende wird eine mitwachsende Leiste zufällig doch sichtbar — der Test wäre grün gewesen und der Fehler trotzdem da. Beide Sichtbarkeitstests sind gegen den kaputten Zustand gegengeprüft und schlagen dort an.

1.1.1 – 2026-08-23

Behoben

  • ./scripts/update.sh endete in „Permission denied". Die Shell-Skripte lagen ohne Ausführungsrecht im Repository (Modus 644 statt 755). Die Anleitung sagt ./scripts/update.sh — auf Linux ging genau das nicht.

    Ursache ist der Entwicklungsrechner: Unter Windows steht core.filemode=false, dort merkt git von einem fehlenden Ausführungsrecht nichts. Aufgefallen ist es erst auf dem Server.

    Wer von 1.1.0 oder älter kommt, braucht einmalig den Umweg — das alte Skript ist ja noch das nicht ausführbare:

    bash scripts/update.sh
    

    Danach stimmt das Recht, und der Punktschrägstrich funktioniert.

  • update.sh setzt das Recht nach dem Umschalten selbst. Wer Dateien von Hand kopiert hat — etwa um an das Skript zu kommen, bevor es in der laufenden Fassung existierte —, verliert es dabei. Ein chmod +x nach dem Umschalten fängt das ab.

  • Das Versionsskript datierte in UTC. Eine Veröffentlichung nach 22 Uhr deutscher Sommerzeit bekam im Changelog das Datum des Vortages — diese Fassung hier war der erste Fall. Es rechnet jetzt in Europe/Berlin, wie alles andere in dieser Anwendung auch.

Geprüft

  • Vier neue Prüfungen (tests/skripte.test.ts) sehen sich nicht das Programm an, sondern die Verpackung: Liegt jedes .sh ausführbar im Index? Hat es eine Shebang-Zeile? Kommt scripts/ ins Docker-Abbild? Sind die Sicherungsskripte in der Compose-Datei eingehängt?

    Das ist der zweite Fehler dieser Art — vorher fehlte scripts/ ganz im Abbild (1.0.1). Beide Male war der Code richtig und kein Test schlug an, weil keiner hinsah, wie die Dateien beim Server ankommen. Jetzt tut es einer. Die Gegenprobe ist gemacht: Mit zurückgesetztem Recht schlägt er fehl und nennt die Datei.

1.1.0 – 2026-08-22

Hinzugefügt

  • Anmelden mit Passkey. Auf der Anmeldeseite steht jetzt unter dem Formular ein zweiter Weg: Mit Passkey anmelden. Ein Fingerabdruck, ein Blick in die Kamera oder die Geräte-PIN — keine E-Mail, kein Passwort, kein abgetippter Code.

    Der Passkey ersetzt den zweiten Faktor, er kommt nicht zusätzlich. Das ist kein Nachlassen: Ein Passkey verlangt den Besitz des Geräts und dessen Entsperrung, das sind dieselben zwei Faktoren wie vorher. Die Anwendung fordert die Nutzerverifikation ausdrücklich an und weist eine Antwort ohne sie zurück. Ein Gerät, das auf blosses Antippen hin signiert, kommt nicht herein.

    In einem Punkt ist er dem bisherigen Weg sogar überlegen: Ein Passkey ist an die Adresse gebunden, unter der er eingerichtet wurde. Auf einer nachgebauten Anmeldeseite funktioniert er nicht — und Phishing ist der übliche Weg, an einen TOTP-Code zu kommen.

    Die Authenticator-App muss trotzdem eingerichtet sein, bevor sich ein Passkey anlegen lässt. Ein Passkey hängt an einem Gerät. Ginge das verloren und wäre er der einzige Weg hinein, käme niemand mehr an die Akte — und darin stehen Unterlagen, die eine betreute Person braucht. Der Passkey ist die bequeme Tür, nicht die einzige.

    Verwaltet werden sie unter Mein Konto → Passkeys: einrichten, benennen, entfernen. Die Liste zeigt, wann ein Gerät zuletzt benutzt wurde und ob der Schlüssel gesichert ist (iCloud, Google, Bitwarden) oder nur auf diesem einen Gerät liegt. Einrichten und Entfernen stehen im Protokoll, jede Anmeldung nennt den verwendeten Passkey namentlich.

  • Bestätigen mit Passkey. Export, endgültiges Löschen und die Benutzerverwaltung verlangen eine frische Anmeldung. Auch die geht jetzt mit dem Passkey. Geprüft wird zusätzlich, dass er zum angemeldeten Zugang gehört — sonst liesse sich mit dem eigenen Finger eine fremde, offen stehende Sitzung freischalten. Genau der Fall, gegen den diese Zwischenfrage gebaut ist.

Zu beachten

  • Passkeys brauchen https. Der Browser gibt das Verfahren nur in einem sicheren Kontext frei. Läuft die Anwendung ohne TLS, erscheint der Knopf gar nicht erst, statt beim Klick mit einer kryptischen Meldung abzubrechen.

  • AUTH_URL muss stimmen — jetzt noch mehr als vorher. Aus ihr wird die Kennung abgeleitet, an die der Authenticator den Schlüssel bindet. Steht dort eine andere Adresse als die im Browser, lässt sich zwar ein Passkey einrichten, aber nie wieder verwenden.

    Ein Wechsel der Domain macht alle Passkeys unbrauchbar. Das ist keine Panne, sondern der Phishingschutz. Nach einem Umzug richtet man sie neu ein; die Anmeldung mit Passwort und Code bleibt währenddessen offen.

  • Eine Datenbank-Migration ist nötig (20260822160000_passkey_anmeldung). Sie läuft beim Start des Behälters automatisch mit. Bestehende Zugänge sind nicht betroffen: Ohne eingerichteten Passkey ändert sich nichts.

Geprüft

  • 21 neue Prüfungen (tests/passkey.test.ts), vor allem für die Herleitung von Kennung und Herkunft aus AUTH_URL: Port, Schrägstrich am Ende, Unterdomain, http gegen https, localhost. Das ist die Stelle, an der eine Installation still kaputtginge — dieselbe Fehlerklasse wie seinerzeit bei APP_BIND und ENC_KEY_V2.
  • Drei End-to-End-Tests gegen einen echten Browser (e2e/passkey.spec.ts), mit Chromiums virtuellem Authenticator: einrichten, abmelden, mit Passkey anmelden, Benutzung vermerkt, entfernen. Dazu die Bestätigung vor dem Vollexport und der Fall, dass ein Gerät ohne Nutzerverifikation nicht hereinkommt.

1.0.5 – 2026-08-22

Hinzugefügt

  • scripts/update.sh — aktualisiert die Anwendung mit einem Befehl.

    ./scripts/update.sh              # auf die neueste Fassung
    ./scripts/update.sh --pruefen    # nur nachsehen, nichts ändern
    ./scripts/update.sh v1.2.0       # auf eine bestimmte Fassung
    

    Es nimmt die Schritte ab, die man von Hand vergisst: Sicherung anstoßen und bei Misserfolg abbrechen, den Changelog zwischen altem und neuem Stand anzeigen, umschalten, neu bauen, warten bis die Anwendung antwortet, die beiden SQL-Skripte ausführen und zum Schluss prüfen, ob wirklich die neue Fassung läuft.

    Zwei Eigenschaften, die dabei zählen:

    Bis zur Rückfrage wird nichts verändert. Bricht etwas vorher ab — Server nicht erreichbar, falsche Versionsangabe — findest du alles so vor wie zuvor. Kein Halbzustand.

    Eigene Änderungen an versionierten Dateien blockieren nicht. Im Betrieb passt man die docker-compose.yml an, bis etwas läuft; genau diese Anpassungen sind später oft schon eingearbeitet. Das Skript legt sie vor dem Umschalten mit git stash beiseite und sagt, wie man sie zurückholt. Mit --verwerfen werden sie stattdessen weggeworfen. Die .env bleibt immer unangetastet — sie ist nicht versioniert.

    Schlägt der Bau fehl, nennt das Skript den Weg zurück auf den vorherigen Stand.

Behoben

  • Der Port der MinIO-Konsole ließ sich nicht ändern. Er stand fest auf 9001; lief dort schon etwas, startete der ganze Stapel nicht (port is already allocated). Jetzt über MINIO_KONSOLE_PORT in der .env einstellbar — dieselbe Möglichkeit, die APP_PORT schon hatte.

1.0.4 – 2026-08-22

Behoben

  • Die Ersteinrichtung ließ sich nicht abschließen. Schritt 3 meldete „Bitte prüfe die markierten Felder" — markierte aber keines. Man kam an dieser Stelle nicht weiter.

    Ursache: Das kurze Formular der Ersteinrichtung schickt neun Felder, das vollständige unter Stammdaten alle. Beide gehen durch dasselbe Schema, und die optionalen Felder waren zwar nullable, aber nicht optional — ein Feld, das gar nicht abgeschickt wurde, ist undefined, nicht null. Beanstandet wurden also zwei Dutzend Felder, die auf dem Bildschirm nie standen.

  • Eine Meldung ohne zugehöriges Feld kann nicht mehr unsichtbar bleiben. Beanstandet die Prüfung ein Feld, das das Formular gar nicht gesendet hat, sagt die Anwendung das jetzt ausdrücklich und schreibt es ins Serverlog — statt es als Eingabefehler auszugeben, den niemand finden kann. Das ist ein Fehler im Programm, und er soll auch so aussehen.

  • Eine betreute Person ließ sich nicht endgültig löschen. Beim Löschen setzt Postgres den Verweis im Audit-Log auf NULL (ON DELETE SET NULL), und genau dieses UPDATE hat der Unveränderlichkeits-Trigger abgewiesen. Betroffen war damit auch das Leeren des Papierkorbs nach 30 Tagen und das Entfernen des Demofalls.

    Der Trigger erlaubt jetzt genau eine Ausnahme: das Nullen der beiden Fremdschlüssel betreuteId und userId. Jede andere Änderung bleibt verboten, auch das Setzen eines Fremdschlüssels auf einen anderen Wert. Der Nachweis bleibt vollständig — Zeitpunkt, Aktion, Bezeichnung, die verschlüsselte Änderung und die Momentaufnahmen von Name und E-Mail sind unberührt. Es verschwindet nur der Verweis auf einen Datensatz, den es nicht mehr gibt.

    Beim Update nötig: das SQL-Skript erneut ausführen, sonst bleibt der alte Trigger stehen.

    docker compose exec app node node_modules/prisma/build/index.js db execute     --schema prisma/schema.prisma --file prisma/sql/audit-schutz.sql
    

Geprüft

  • Sieben neue Tests (tests/stammdaten.test.ts) prüfen genau die Formularinhalte der Ersteinrichtung, dazu das vollständige Formular mit leeren Feldern und die weiterhin verlangten Pflichtangaben.
  • Der Ablauf ist zusätzlich im Browser durchgespielt worden: Anmeldung, zweiter Faktor, Schritt 3, Landung auf dem Dashboard — und die daraus abgeleiteten Pflichtfristen samt Ausschlussfrist für die Aufwandspauschale.
  • Der geänderte Trigger ist gegen eine laufende Datenbank geprüft: Löschen gelingt, Fälschen und Löschen von Einträgen scheitert weiterhin.

1.0.3 – 2026-08-22

Keine Änderung am Programm — nur an der Konfigurationsvorlage und der Anleitung. Ein Neubau des Abbilds ist nicht nötig.

Behoben

  • .env.example band die Anwendung stillschweigend an 127.0.0.1. Der Wert stand dort als fertig ausgefüllte Zeile zwischen lauter anderen fertigen Zeilen. Wer die Datei kopiert hat und seinen Reverse Proxy auf einem anderen Server betreibt, kam nicht an die Anwendung heran — und der Fehler sah aus, als läge es am Proxy.

    Jetzt steht dort eine Entscheidung mit drei benannten Fällen statt eines Vorgabewerts. Der sichere Standard bleibt 127.0.0.1; er wird nur nicht mehr als „schon erledigt" präsentiert.

    Für bestehende Installationen genügt eine Zeile in der .env:

    APP_BIND=10.0.0.5      # Adresse, über die der Proxy diesen Server erreicht
    docker compose up -d
    

Geändert

  • docs/INSTALLATION.md nennt APP_BIND jetzt schon in Schritt 3, wo die .env ausgefüllt wird — nicht erst in Schritt 7, wo der Proxy drankommt. Dazu ein eigener Abschnitt in der Fehlersuche: „Der Proxy erreicht die Anwendung nicht", mit den zwei curl-Proben, die den Unterschied zwischen falscher Bindeadresse und Firewall zeigen.

1.0.2 – 2026-08-22

Behoben

  • Die Einrichtung des zweiten Faktors brach mit einem Serverfehler ab („Application error: a server-side exception has occurred"). Im Serverlog stand Umgebungsvariable ENC_KEY_V2 fehlt — obwohl niemand einen zweiten Schlüssel wollte.

    Ursache: docker-compose.yml reicht ENC_KEY_V2 immer an den Behälter durch, mit leerem Wert, wenn in der .env keiner steht. Die Anwendung erkannte Schlüssel aber am Variablennamen statt am Inhalt, fand also ein leeres ENC_KEY_V2 und brach ab. Leere Schlüsselvariablen werden jetzt übersprungen.

    Betroffen war jede Stelle, die verschlüsselte Felder schreibt oder liest — also praktisch alles außer der reinen Anmeldung. Die Anmeldung ging durch, weil sie ohne Verschlüsselung auskommt; der Fehler trat deshalb erst auf der nächsten Seite auf.

  • Die Meldung beim Schlüsselwechsel nennt jetzt, welche Versionen tatsächlich vorhanden sind, und die richtige Reihenfolge: erst den neuen Schlüssel eintragen, dann ENC_KEY_AKTIV umstellen.

Hinzugefügt

  • scripts/anmeldung-pruefen.mjs — beantwortet die Frage, warum eine Anmeldung nicht klappt. Das Formular sagt bewusst nicht, woran es lag, sonst ließe sich daran ablesen, welche Adressen es gibt. Auf dem Server darf man es wissen: Jeder Versuch wird mit Grund protokolliert, und das Skript liest ihn vor — dazu den Zustand des Zugangs, den Stand der Login-Sperre und die eingestellte AUTH_URL.

    docker compose exec app node scripts/anmeldung-pruefen.mjs deine@adresse.de
    

    Es ändert nichts, es liest nur.

Geprüft

  • Sieben neue Tests (tests/umgebung.test.ts) decken die Schlüsselauswertung ab, darunter genau die Konstellation aus dem Fehlerbericht: gesetztes ENC_KEY_V1, leeres ENC_KEY_V2.

1.0.1 – 2026-08-22

Behoben

  • Betriebsskripte fehlten im Docker-Abbild. Das Verzeichnis scripts/ wurde beim Bauen nie in die Laufzeitstufe übernommen. docker compose exec app node scripts/totp-geheimnis.mjs … endete deshalb mit Cannot find module. Betroffen waren alle Skripte, die im laufenden Behälter gedacht sind — auch wartungsschluessel.mjs und schluessel-erzeugen.mjs.

    Nach dem Update funktioniert der Befehl wie dokumentiert. Wer nicht gleich aktualisieren will, kommt einmalig auch so an das Skript:

    docker compose cp scripts/totp-geheimnis.mjs app:/app/totp-geheimnis.mjs
    docker compose exec app node totp-geheimnis.mjs deine@adresse.de
    

Hinzugefügt

  • scripts/totp-geheimnis.mjs — liest das TOTP-Geheimnis eines Zugangs aus, um denselben Zugang auf einem zweiten Gerät einzurichten (Handy und Tablet, oder ein Ersatzgerät). Die Anwendung zeigt das Geheimnis sonst nur einmal an, beim Einrichten; bisher blieb nur, den zweiten Faktor zurückzusetzen und alle Wiederherstellungscodes neu zu erzeugen.

    Das Skript läuft nur auf dem Server und nur mit Zugriff auf die Datenbank und auf ENC_KEY_V1. Wer beides hat, kann ohnehin alles lesen — es ist also keine Hintertür, sondern erspart eine unnötige Neueinrichtung.

1.0.0 – 2026-08-22

Erste vollständige Fassung. Alle acht Etappen umgesetzt, alle Abnahmekriterien als Test hinterlegt.

Hinzugefügt

Der Alltag

  • Dashboard „Heute" — beantwortet morgens, was ansteht: Fristen-Ampel (überfällig / diese Woche / diesen Monat), wer gerade am Zug ist, offene Nachforderungen des Bezirks, ungeprüfter Posteingang, unverbuchte Belege, Kennzahlen zu Vermögen und Heimkosten.
  • Fristen — die gesetzlichen Pflichtfristen entstehen von selbst aus dem Bestellungsdatum: Vermögensverzeichnis und Anfangsbericht nach drei Monaten, Jahresbericht und Vermögensübersicht zum Ende jedes Betreuungsjahres, Aufwandspauschale, Landespflegegeld, Zuzahlungsbefreiung, Rückkaufswerte. Liste, Monatskalender und ein ICS-Feed zum Abonnieren im eigenen Kalender.
  • Vorgänge als Fallakte mit Zeitstrahl über Dokumente, Protokolle, Fristen und Buchungen. Neun Vorlagen mit vorbefüllter Aufgabenliste, darunter Heimeinzug, Antrag Hilfe zur Pflege, Wohnungsauflösung, Hausverkauf, Darlehen nach § 91 SGB XII und Widerspruch gegen einen Bescheid.
  • Kontakte und Kontaktprotokoll — Verzeichnis aller Stellen mit Aktenzeichen, dazu eine Schnellerfassung, die am Handy in unter zwanzig Sekunden zu bedienen ist.

Papier

  • Dokumentenablage mit Drag & Drop, Sammel-Upload und Handy-Foto. Texterkennung auf Deutsch, Volltextsuche über alle Schreiben, Posteingangsbuch mit den Stufen neu → gesichtet → zugeordnet → beantwortet, Feld für den Ablageort des Papieroriginals.
  • Beim Import werden Absender, Datum, Aktenzeichen, Dokumentart und eine im Text genannte Frist vorgeschlagen — mit der Textstelle daneben, damit man prüfen kann. Übernommen wird nur auf Klick.
  • Belegmappe: alle Dokumente eines Vorgangs oder Zeitraums als eine chronologisch sortierte, paginierte PDF mit Deckblatt und Inhaltsverzeichnis.

Geld

  • Kassenbuch mit Belegzwang, Kategorien, CSV- und CAMT.053-Import. Harte Trennung zwischen dem Vermögen der betreuten Person und eigenen Auslagen, mit Warnung bei Buchungen auf ein als privat markiertes Konto.
  • Konten mit verschlüsselter IBAN und Saldoständen je Stichtag, Vermögensposten mit vollständiger Wert-Historie und Pflichtangabe zur Wertquelle. Werte werden nie überschrieben.
  • Vermögensverzeichnis (§ 1835 BGB) und Vermögensübersicht bzw. Rechnungslegung (§§ 1859, 1865 BGB) als druckfertige PDF, in zwei Ausgabevarianten für befreite und nicht befreite Betreuer.

Behörde

  • Sozialhilfe-Modul für das Verfahren beim Bezirk: Antragsakte, Nachforderungs-Tracker mit Fortschrittsbalken, vorbefüllte Checkliste der Standardunterlagen mit Begründung, warum der Träger sie will.
  • Bescheid-Prüfung mit Berechnung der Rechtsbehelfsfrist ab dem Zugangsdatum, einschließlich Wochenende, bayerischer Feiertage und dem Sonderfall fehlender Rechtsbehelfsbelehrung. Der Rechenweg wird ausgegeben.
  • Heimkosten-Gegenüberstellung Monat für Monat: Kosten gegen Pflegekasse, Leistungszuschlag nach § 43c SGB XI, Rente und Sozialhilfeanteil — die Deckungslücke wird sichtbar.
  • Schonvermögens-Bewertung je Posten (verwertbar / geschützt / strittig) mit Begründungsfeld und Textbausteinen zu § 90 SGB XII.
  • Katalog weiterer Leistungen: Landespflegegeld, Zuzahlungsbefreiung, Rundfunkbeitragsbefreiung, Schwerbehindertenausweis, Grundsicherung.

Substanz

  • Immobilie mit Grundbuchdaten, Belastungen nach Abteilung II und III, Wert-Historie, Status im Sozialhilfeverfahren und einer Pflichten-Checkliste bei Leerstand — zehn Punkte, jeder mit Begründung.
  • Versicherungen und Verträge mit Kündigungsfristen-Rechner, der den spätesten Absendetag nennt, Anschreiben zur Rückkaufswert-Anfrage mit automatischer Wiedervorlage und einem Kündigungs-Assistenten.
  • Heim und Pflege mit Heimvertrag, Leistungszuschlag-Staffel, Pflegegrad-Historie, Abwesenheitstagen und einem Gesundheitsverlauf mit COPD-Bezug: Exazerbationen, Sauerstoff, Stürze, Krankenhaus, Hilfsmittel, Impfungen nach STIKO-Plan.

Ausgabe

  • Jahresbericht (§ 1863 BGB) als Entwurf zum Überarbeiten, gespeist aus Kontaktprotokollen, Gesundheitsereignissen und Vorgangsstatus. Ausgabe als PDF und als DOCX.
  • Unterlagenpaket für den Bezirk: die im Tracker markierten Dokumente als eine PDF mit Anschreiben und Inhaltsverzeichnis.
  • Vollexport als ZIP mit allen Originaldateien, allen Daten als entschlüsseltes JSON, den erzeugten Berichten, einer LIESMICH und SHA-256-Prüfsummen.
  • Wissensbasis mit 37 Hinweiskarten, pflegbar als JSON-Datei ohne Neustart. Jede mit Rechtsgrundlage, Link und dem stehenden Vermerk, dass sie keine Rechtsberatung ersetzt.

Verwaltung

  • Mitleser-Rolle mit modulweiser Freigabe und ausdrücklicher Warnung bei Gesundheit, Finanzen und Sozialhilfe.
  • Papierkorb mit 30 Tagen Aufbewahrung.
  • Wartungslauf über /api/wartung: Fristerinnerungen per E-Mail, Papierkorb leeren, alte Anmeldeversuche entfernen.

Sicherheit

  • Pflicht-Zweitfaktor (TOTP nach RFC 6238). Lässt sich nicht abschalten. Acht Wiederherstellungscodes, einzeln Argon2id-gehasht.
  • Anwendungsseitige Feldverschlüsselung mit AES-256-GCM für Diagnosen, den ermittelten Willen, IBANs, Versicherungs-, Renten- und Steuernummern sowie alle Freitext-Notizen. Der Feldname wird mitauthentifiziert — ein Geheimtext lässt sich nicht von einem Feld in ein anderes umhängen. Schlüsselrotation ohne Datenverlust vorgesehen.
  • Argon2id nach OWASP-Empfehlung, mit automatischem Nachziehen bei späterer Parametererhöhung.
  • Rate-Limiting am Login nach E-Mail und Anschluss. Die Sperre wird geprüft, bevor überhaupt gerechnet wird, und die Antwortzeit ist gestreckt — sie verrät nicht, welche Adressen existieren.
  • Unveränderliches Audit-Log: ein Datenbank-Trigger weist UPDATE und DELETE ab, auch bei direktem Zugriff mit psql.
  • Strenge Content-Security-Policy mit Nonce pro Anfrage. Keine externen Schriften, kein CDN, keine Tracker — nachgewiesen durch einen Test, der jede Anfrage an einen fremden Host als Fehler wertet.
  • Uploads werden an den Magic Bytes geprüft, nicht an Endung oder gemeldetem MIME-Typ. Ausgeliefert wird nur über kurzlebige signierte URLs, immer als Anhang mit nosniff.
  • Erneute Anmeldung vor Export, endgültigem Löschen und Rollenänderungen. Ein Passwortwechsel beendet alle offenen Sitzungen.

Betrieb

  • Docker Compose mit Anwendung, PostgreSQL, MinIO und Sicherungsdienst. Ohne Reverse Proxy — der ist auf dem Zielserver vorhanden. Die Datenbank hat keine Portfreigabe.
  • Tägliche verschlüsselte Sicherung um 03:15 Uhr mit Selbstprüfung: lässt sich die Datei nicht wieder entschlüsseln, endet der Lauf mit Fehler statt mit einem stillen Scheinerfolg.
  • Verarbeitungsverzeichnis und Datenschutzhinweise als ausfüllbare Textbausteine.
  • Bauprotokoll aus den Commit-Trailern.

Bekannte Einschränkungen

  • Die Texterkennung ist gegen ein echtes Tesseract nicht end-to-end geprüft. Der Weg „nicht verfügbar, Upload funktioniert trotzdem" ist getestet.
  • Der CAMT.053-Import ist nur gegen selbst gebaute Beispiele geprüft, nicht gegen einen echten Bankauszug.
  • Das Kostenkonto der Immobilie wertet über Buchungskategorien aus und wäre bei einem zweiten Grundstück falsch. Die Oberfläche sagt das an der Auswertung dazu.
  • Eine Aufgabe aus einer Vorgangs-Vorlage lässt sich nicht entfernen — passt sie im Einzelfall nicht, bleibt sie offen stehen.
  • @react-pdf/renderer braucht in diesem Abhängigkeitsbaum eine Krücke (src/lib/pdf/standardschrift.ts), weil seine Unterabhängigkeiten für Standardschriften kein Schriftobjekt mehr liefern.

Was davon wann angegangen wird, steht in docs/ROADMAP.md.