Im Schreiben-Editor gibt es jetzt den Umschalter Brief/E-Mail. Die E-Mail-Fassung wird aus dem - womoeglich bearbeiteten - Brieftext abgeleitet: ohne Absenderblock, Anschrift und Datumszeile, aber mit dem Bestellungsabsatz. Betreff und Text einzeln kopierbar. Die offene Entscheidung aus dem Issue (mailto oder .eml) ist nach Rueckfrage mit BEIDES beantwortet: - mailto fuer kurze Texte. Der Knopf verschwindet, sobald der kodierte Link 1800 Zeichen uebersteigt - mailto uebergibt den Text in der Adresszeile, deren Laenge nirgends zugesichert ist, und ein halbierter Brief faellt erst beim Empfaenger auf. Die Grenze wird NACH der URL-Kodierung gerechnet; 900 Umlaute sind roh harmlos und kodiert weit drueber. - .eml immer: RFC 5322 mit X-Unsent: 1, quoted-printable fuer den Rumpf, RFC-2047-Kodierung fuer Umlaute im Betreff. Bewusst ohne From-Kopf - ein erfundener Absender wuerde je nach Programm uebernommen. Beide Knoepfe erscheinen nur mit E-Mail-Adresse (aus dem Kontakt uebernommen oder von Hand). Ohne Adresse bleibt das Kopieren. Die Ablage kennt den Unterschied: Eine E-Mail heisst in der Akte "E-Mail: ...", und abgelegt wird die E-Mail-Fassung samt Empfaengeradresse im Kopf der PDF - in der Akte soll stehen, was tatsaechlich hinausging. Sicherung in emailFassung(): Findet sich keine Anrede (frei umgebauter Text), wird NICHTS entfernt. Lieber ein Briefkopf zu viel in der Mail als stillschweigend verlorener Inhalt. Geprueft: 20 Einheitstests, vier End-to-End-Tests auf beiden Geraeteprofilen. 590 Unit-Tests, 81 e2e, null Typfehler. Refs #5
832 lines
38 KiB
Markdown
832 lines
38 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.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.5.0...HEAD
|
||
[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
|