1290 lines
59 KiB
Markdown
1290 lines
59 KiB
Markdown
# Änderungen
|
||
|
||
Alle nennenswerten Änderungen an dieser Anwendung, in umgekehrter
|
||
Reihenfolge. Aufbau nach [Keep a Changelog](https://keepachangelog.com/de/1.1.0/),
|
||
Versionsnummern nach [Semantic Versioning](https://semver.org/lang/de/).
|
||
|
||
**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.11.0] – 2026-08-24
|
||
|
||
Diese Fassung geht aus einer Sicherheitsprüfung hervor. Sie ändert nichts
|
||
an der Bedienung, schließt aber mehrere Lücken — darunter drei, bei denen
|
||
im Code eine Zusage stand, die so nicht galt.
|
||
|
||
### Vor dem Update: zwei neue Zeilen in der `.env`
|
||
|
||
```bash
|
||
ERSTEINRICHTUNG_GEHEIMNIS=<zufälliger Wert, npm run schluessel erzeugt einen>
|
||
VERTRAUE_PROXY=true
|
||
```
|
||
|
||
Beide sind nicht zwingend, aber beide haben Folgen, wenn sie fehlen:
|
||
|
||
- Ohne `ERSTEINRICHTUNG_GEHEIMNIS` läuft alles weiter — nur der **erste**
|
||
Zugang ließe sich nicht mehr anlegen. Auf einer bestehenden Installation
|
||
ist das genau richtig; bei einer Neuinstallation brauchst du den Wert.
|
||
- Ohne `VERTRAUE_PROXY=true` zählt die Anmeldesperre nur noch nach
|
||
E-Mail-Adresse, nicht mehr zusätzlich nach Anschluss. Beim ersten Mal
|
||
steht eine erklärende Zeile im Log.
|
||
|
||
### Nach dem Update, nur mit Objektspeicher
|
||
|
||
Bereits abgelegte Dateien liegen weiter unverschlüsselt, bis sie einmal
|
||
umgeschrieben werden. Lesen funktioniert durchgehend, der Lauf lässt sich
|
||
jederzeit abbrechen und wiederholen:
|
||
|
||
```bash
|
||
npm run speicher:verschluesseln # erst schauen
|
||
npm run speicher:verschluesseln -- --anwenden
|
||
```
|
||
|
||
Wer beim Dateitreiber bleibt, muss nichts tun — dort wurde immer schon
|
||
verschlüsselt.
|
||
|
||
### Behoben
|
||
|
||
- **Der zweite Faktor war eine Anzeige, keine Grenze.** „TOTP ist Pflicht"
|
||
galt nur für Seiten. Server Actions und Downloads liefen daran vorbei:
|
||
Wer sich mit Passwort angemeldet, die Einrichtung aber nie abgeschlossen
|
||
hatte, kam an die Daten. Die Prüfung sitzt jetzt an der Stelle, durch die
|
||
alles muss.
|
||
|
||
- **Ein Dokumenten-Download fragte nur nach der Anmeldung.** Dieselbe
|
||
Lücke, an einer Stelle, die bei der ersten Durchsicht übersehen wurde.
|
||
|
||
- **Die Anmeldesperre sperrte dauerhaft aus.** Jeder Versuch während einer
|
||
laufenden Sperre verlängerte sie um die volle Dauer. Wer alle zehn
|
||
Minuten ein falsches Passwort an eine fremde Adresse schickte, sperrte
|
||
deren Inhaber aus — ohne das Passwort zu kennen. Nebenbei wuchs die
|
||
Tabelle mit jedem Versuch.
|
||
|
||
- **Ein Code aus der Authenticator-App galt mehrfach.** Bis zu 90 Sekunden
|
||
lang ließ sich derselbe Code erneut einlösen — abgelesen, abgefangen
|
||
oder aus dem Browserverlauf. Jetzt gilt jeder genau einmal.
|
||
|
||
- **Passkeys ließen sich ohne Rückfrage anlegen und entfernen.** An einem
|
||
unbeaufsichtigten Rechner waren das zwei Klicks zu einem dauerhaften
|
||
eigenen Zugang, der auch einen Passwortwechsel überlebt hätte. Jetzt
|
||
fragt die Anwendung vorher nach Passwort und Code — wie beim Export.
|
||
|
||
- **Die Ersteinrichtung stand offen.** Zwischen dem ersten Start und dem
|
||
Anlegen des Zugangs konnte jeder, der die Seite fand, Administrator
|
||
werden. Zwei gleichzeitige Anfragen legten außerdem beide einen Zugang
|
||
an.
|
||
|
||
- **Dateien im Objektspeicher lagen mit dem Schlüssel des Anbieters da.**
|
||
Gegen eine verlorene Festplatte im Rechenzentrum half das, gegen den
|
||
Anbieter und gegen gestohlene Zugangsdaten zum Speicher nicht. Jetzt
|
||
liegt derselbe Umschlag darum wie bei der Ablage auf dem eigenen Server,
|
||
mit einem Schlüssel, der die Anwendung nie verlässt.
|
||
|
||
- **Ein präpariertes PDF konnte den Server umbringen.** Beim Auslesen des
|
||
eingebetteten Texts gab es keine Obergrenze: Wenige Kilobyte Füllung
|
||
blähen sich beim Auspacken auf Gigabyte auf. Ebenso beim Umwandeln in
|
||
Bilder — die Seitengröße steht im Dokument, und bei fester Auflösung
|
||
ergab eine künstlich große Seite ein Bild von mehreren Gigabyte.
|
||
|
||
- **32 Schwachstellen in mitgelieferten Paketen, davon 5 kritische.**
|
||
Jetzt keine.
|
||
|
||
### Geändert
|
||
|
||
- **Downloads laufen jetzt immer über die Anwendung**, auch mit
|
||
Objektspeicher. Das ist die Folge der Verschlüsselung — entschlüsseln
|
||
kann nur die Anwendung. Nebeneffekt: Jeder Abruf prüft die Berechtigung
|
||
und wird protokolliert. Ein weitergeleiteter Link allein öffnet nichts
|
||
mehr.
|
||
|
||
- **`docs/SICHERHEIT.md`** ist neu: Bedrohungsmodell, der Durchgang entlang
|
||
der OWASP Top 10 — und ein Abschnitt darüber, was ausdrücklich **nicht**
|
||
geschützt ist.
|
||
|
||
## [1.10.2] – 2026-08-24
|
||
|
||
### Behoben
|
||
|
||
- **Das Update brach ohne Meldung ab.** Beim Sprung von 1.5.0 auf 1.10.1
|
||
endete `scripts/update.sh` mitten in der Ausgabe — kein Fehler, keine
|
||
Zeile, einfach zurück zur Eingabeaufforderung. Ursache war eine
|
||
abgeschnittene Leitung:
|
||
|
||
```
|
||
git log --oneline "HEAD..$ZIEL" | head -15 | sed ...
|
||
```
|
||
|
||
`head` schließt die Leitung nach 15 Zeilen, `git log` schreibt weiter
|
||
und bekommt SIGPIPE. Weil das Skript mit `set -o pipefail` und
|
||
`set -e` läuft, gilt die ganze Kette als gescheitert und das Skript
|
||
beendet sich — stumm.
|
||
|
||
Das ist zeitabhängig und deshalb monatelang nicht aufgefallen: Solange
|
||
`git log` fertig war, bevor `head` zumachte, ging alles gut. Genau bei
|
||
1.10.0 lagen zum ersten Mal **mehr als 15 Commits** dazwischen.
|
||
|
||
- **Dieselbe Falle in der Selbstprüfung der Sicherung.** `sicherung.sh`
|
||
prüfte mit `openssl … | head -c 5 | grep -q "PGDMP"`, ob sich die
|
||
frische Sicherung wieder entschlüsseln lässt. Bei kleiner Datenbank
|
||
ging das gut, weil alles im Puffer stand. Mit wachsender Datenbank
|
||
hätte es gekippt — und dann hätte das Skript eine **völlig intakte
|
||
Sicherung als kaputt gemeldet** und das Update verweigert.
|
||
|
||
### Geändert
|
||
|
||
- **Ein stummer Abbruch ist nicht mehr möglich.** `update.sh` meldet
|
||
jetzt bei jedem unerwarteten Ende die Zeilennummer und den Exitcode,
|
||
und erklärt bei 141 ausdrücklich, dass es sich um SIGPIPE handelt und
|
||
um einen Fehler im Skript, nicht um einen Bedienfehler.
|
||
- Stehen mehr als 15 Commits an, steht jetzt „… und N weitere" darunter,
|
||
statt sie wortlos wegzulassen.
|
||
|
||
### Geprüft
|
||
|
||
- Ein Test verbietet das Muster künftig in allen Betriebsskripten:
|
||
Wer wieder `| head` in eine Leitung schreibt, bekommt die Zeilennummer
|
||
genannt. Gegenprobe gemacht — der Test schlägt an.
|
||
- Der Ablauf von 1.5.0 auf 1.10.1 einmal nachgestellt: läuft durch.
|
||
|
||
## [1.10.1] – 2026-08-23
|
||
|
||
### Geändert
|
||
|
||
- **Der Beispielfall hat jetzt ein Jahr Kontobewegungen**
|
||
([#22](https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/issues/22)).
|
||
Bisher brachte er Konten und Kontostände mit, aber keine einzige
|
||
Buchung — Kassenbuch, Belegpflicht, Dauerzahlungen und die Erkennung
|
||
wiederkehrender Zahlungen liefen darin also leer. Wer die Anwendung zum
|
||
ersten Mal ansah, musste erst eine CSV importieren.
|
||
|
||
Neu sind 107 Buchungen über zwölf Monate: Rente, Betriebsrente und
|
||
Pflegekasse als Einnahmen, Heimentgelt, Barbetrag, Sterbegeldbeitrag,
|
||
Telefon und Kontoführung als monatliche Ausgaben, dazu Rundfunkbeitrag
|
||
und Grundsteuer vierteljährlich sowie eine Handvoll Einzelposten.
|
||
|
||
Das betrifft nur neue Installationen mit `SEED_DEMO=true` — an einem
|
||
bestehenden Bestand ändert sich nichts.
|
||
|
||
### Behoben
|
||
|
||
- **„gGmbH" wurde nicht als Rechtsform erkannt.** Beim Zusammenfassen
|
||
wiederkehrender Zahlungen galten „Seniorenzentrum St. Katharina" und
|
||
„Seniorenzentrum St. Katharina gGmbH" als zwei verschiedene Empfänger —
|
||
und damit zerfiel die Gruppe genau dort, wo sie am meisten zählt: Heime,
|
||
Sozialdienste und Träger sind fast durchweg gGmbH.
|
||
|
||
### Was der Beispielfall jetzt zeigt
|
||
|
||
- Das Heimentgelt steht in **drei Schreibweisen** auf dem Auszug und wird
|
||
trotzdem als eine monatliche Zahlung von 2.489 € geführt.
|
||
- Genau **eine** Buchung hat weder Quittung noch Begründung — damit die
|
||
Belegpflicht etwas zu zeigen hat, aber die Liste nicht rot leuchtet.
|
||
- Die Sterbegeld-Lastschriften sind bewusst **nicht** zugeordnet: So lässt
|
||
sich der Handgriff „zwölf Zahlungen als belegt zuordnen" ausprobieren.
|
||
Der Beitrag steigt im Mai von 18,40 € auf 19,80 €, damit auch die
|
||
Abweichungsprüfung sichtbar wird.
|
||
- Der Kontostand zum 31.07.2026 wird aus dem Anfangsstand und den
|
||
Buchungen **gerechnet**, nicht behauptet. Ein Beispielfall, der sich
|
||
selbst widerspricht, wäre schlimmer als einer ohne Buchungen.
|
||
|
||
### Geprüft
|
||
|
||
- Ein Einheitstest für die gGmbH-Erkennung.
|
||
- Vier End-to-End-Tests am Beispielfall: Umfang und Zeitraum der
|
||
Buchungen, die Übereinstimmung von Kontostand und Buchungssumme, die
|
||
erkannten Zahlungsgruppen und das Kassenbuch.
|
||
|
||
## [1.10.0] – 2026-08-23
|
||
|
||
### Hinzugefügt
|
||
|
||
- **Deine Anschrift steht jetzt in jedem Schreiben**
|
||
([#21](https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/issues/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](https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/issues/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](https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/issues/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](https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/issues/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](https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/issues/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](https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/issues/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](https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/issues/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](https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/issues/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](https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/issues/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](https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/issues/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
|
||
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.
|
||
|
||
```bash
|
||
./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.
|
||
|
||
```bash
|
||
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`:
|
||
|
||
```bash
|
||
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`.
|
||
|
||
```bash
|
||
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:
|
||
|
||
```bash
|
||
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`](docs/ROADMAP.md).
|
||
|
||
---
|
||
|
||
[Unveröffentlicht]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.11.0...HEAD
|
||
[1.11.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.10.2...v1.11.0
|
||
[1.10.2]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.10.1...v1.10.2
|
||
[1.10.1]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.10.0...v1.10.1
|
||
[1.10.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.9.0...v1.10.0
|
||
[1.9.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.8.0...v1.9.0
|
||
[1.8.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.7.0...v1.8.0
|
||
[1.7.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.6.0...v1.7.0
|
||
[1.6.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.5.0...v1.6.0
|
||
[1.5.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.4.0...v1.5.0
|
||
[1.4.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.3.0...v1.4.0
|
||
[1.3.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.2.0...v1.3.0
|
||
[1.2.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.1.2...v1.2.0
|
||
[1.1.2]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.1.1...v1.1.2
|
||
[1.1.1]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.1.0...v1.1.1
|
||
[1.1.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.5...v1.1.0
|
||
[1.0.5]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.4...v1.0.5
|
||
[1.0.4]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.3...v1.0.4
|
||
[1.0.3]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.2...v1.0.3
|
||
[1.0.2]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.1...v1.0.2
|
||
[1.0.1]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.0...v1.0.1
|
||
[1.0.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/releases/tag/v1.0.0
|