Passkeys (WebAuthn/FIDO2) als zweiter Anmeldeweg - auf der Anmeldeseite und bei der erneuten Bestaetigung vor sensiblen Aktionen. Verwaltet unter "Mein Konto". Der Passkey ERSETZT den zweiten Faktor, statt zu ihm hinzuzukommen. Das ist tragbar, weil er zwei Faktoren in sich vereint: Besitz des Geraets und dessen Entsperrung. Damit das keine Annahme bleibt, wird die Nutzerverifikation angefordert (userVerification: 'required') und serverseitig nachgeprueft - eine Antwort ohne sie wird abgewiesen. TOTP muss vorher eingerichtet sein. Ein Passkey haengt an einem Geraet; waere er der einzige Weg hinein, koennte ein verlorenes Handy die Akte schliessen. Aufbau: - Die Pruefung laeuft vollstaendig im Credentials-Provider "passkey", nicht in der Server Action davor. Ein "war schon geprueft" ueber die Grenze zu reichen waere die Stelle, an der sich Anmeldungen faelschen lassen. - Challenges liegen serverseitig und werden per DELETE genau einmal verbraucht - die Datenbank entscheidet, wer sie bekommt. - Bereichskennung und Herkunft kommen aus AUTH_URL, nicht aus einer zweiten Konfigurationsquelle. - Ohne https wird der Knopf gar nicht erst angeboten. - Rate-Limiting, Kontosperre und Audit-Log gelten unveraendert; die Anmeldung nennt den verwendeten Passkey namentlich. Zwei Anmerkungen zur Migration: - "prisma migrate diff" wollte zusaetzlich die Trigramm-Indizes aus prisma/sql/suche.sql loeschen, die Prisma nicht kennt. Die Zeilen sind entfernt und im Migrationskopf vermerkt - ein DROP haette die unscharfe Suche stillgelegt, ohne dass etwas fehlgeschlagen waere. - "prisma format" hat das Schema durchgaengig neu ausgerichtet. Ohne Whitespace betrachtet sind es 88 hinzugefuegte Zeilen und keine geloeschte. Geprueft: 21 Einheitstests, drei End-to-End-Tests gegen Chromiums virtuellen Authenticator (einrichten, anmelden, bestaetigen, entfernen, Geraet ohne Verifikation abgewiesen), beide Geraeteprofile. 496 Tests, null Typfehler, Produktionsbau steht. Nebenbei: Die Zahlen im README waren veraltet (24 statt 33 Modelle, 46 statt 79 Seiten). Sie stehen jetzt mit dem Befehl daneben, mit dem man sie nachzaehlt.
477 lines
22 KiB
Markdown
477 lines
22 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.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.1.0...HEAD
|
||
[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
|