Files
Florian Wilde 0cdd4edfdc feat: Fristen, Pflichtfristen aus dem Bestellungsdatum und ICS-Feed
Die gesetzlichen Fristen entstehen von selbst, sobald das
Bestellungsdatum in den Stammdaten steht - Vermoegensverzeichnis und
Anfangsbericht nach drei Monaten, Jahresbericht und Vermoegensuebersicht
zum Ende jedes Betreuungsjahres, Aufwandspauschale, Landespflegegeld,
Zuzahlungsbefreiung, Rueckkaufswerte.

Zwei Punkte, an denen es sonst schiefgeht:

Das Betreuungsjahr endet am Tag VOR dem Jahrestag (§ 188 Abs. 2 BGB),
bei Bestellung am 29. Februar am 28. (§ 188 Abs. 3). Ohne diese Regel
verrutscht die ganze Kette um einen Tag.

Faellt eine Frist auf Samstag, Sonntag oder Feiertag, wird sie NICHT
verschoben. § 193 BGB verschiebt zwar den Ablauf, aber als Betreuer will
ich frueher fertig sein, nicht spaeter. Stattdessen steht ein Hinweis in
der Beschreibung. Bayerische Feiertage inklusive, ueber die Osterformel
berechnet.

Pflichtfristen tragen bewusst keine RRULE: sonst entstuende beim
Erledigen eine Dublette neben der ohnehin abgeleiteten Folgefrist. Beim
erneuten Ableiten werden nur offene Fristen nachgezogen, Erledigtes
bleibt unangetastet.

Der ICS-Feed kommt ohne Token-Feld im Schema aus - die Signatur ist ein
HMAC ueber betreuteId und userId. VALARM je Vorwarnstufe, Zeilenfaltung
nach RFC 5545.

51 Tests.

Etappe: 2
Phase: Alltag
2026-08-22 02:24:32 +02:00

3.4 KiB

Schema-Wünsche aus dem Modul „Fristen & Kalender"

Das Modul ist vollständig mit dem bestehenden model Frist umgesetzt — nichts davon blockiert. Die folgenden Punkte sind Verbesserungen, die jeweils eine Behelfslösung ersetzen würden. prisma/schema.prisma wurde nicht angefasst.


1. Getrennte Felder für Erledigungsnotiz, Verschiebungs- und Entfallgrund

Behelf heute: Beim Erledigen, Verschieben und Entfallenlassen hängen die Server Actions den Grund als Textzeile an beschreibung an ("Verschoben vom 14.03.2026: Unterlagen fehlten noch.").

Warum das stört: beschreibung ist der Text, der sagt, was zu tun ist — er wandert unverändert in den ICS-Feed und in die Vorwarnungen. Mit angehängter Historie wird er über die Jahre unlesbar, und die Ableitung der Pflichtfristen überschreibt ihn bei offenen Fristen ohnehin wieder (dann ist die Notiz weg). Ausserdem lässt sich nicht auswerten, wie oft eine Frist verschoben wurde — genau die Zahl, die im Jahresbericht auffällt.

Wunsch:

/// Freitext beim Abhaken: wie wurde erledigt, was ging raus, an wen.
erledigtNotiz     String?
/// Grund der letzten Verschiebung bzw. des Entfallens.
statusGrund       String?
/// Wie oft wurde diese Frist schon verschoben? Fuer die Selbstkontrolle.
verschobenAnzahl  Int      @default(0)

2. Wer hat die Frist erledigt?

Behelf heute: Steht nur im Audit-Log (AuditLog.userId).

Warum das stört: Für die Anzeige („erledigt am 14.03. von Florian Wilde") müsste die Liste für jede Frist im Audit-Log nachschlagen. Bei mehreren Betreuern oder einem mitlesenden Geschwisterteil ist das die erste Frage, die gestellt wird.

Wunsch: analog zu Vorgang.angelegtVonId

erledigtVonId String?
erledigtVon   User?   @relation("FristErledigtVon", fields: [erledigtVonId], references: [id], onDelete: SetNull)

3. vorgaengerFristId ist @unique — die Kette ist einspurig

Behelf heute: Funktioniert für den Normalfall (eine erledigte Frist → genau eine Nachfolgefrist).

Warum das stört: Beim Verschieben und bei der Wiederholung zeigt die neue Frist auf dieselbe Vorgängerin. Wird eine verschobene Frist später irrtümlich noch einmal verschoben, läuft das in eine Verletzung der Eindeutigkeit statt in eine verständliche Meldung. Ein einfacher @@index statt @unique würde reichen; die Kette bliebe über vorgaengerFristId weiterhin rückwärts lesbar.


4. Kein Feld für den Kalender-Token — bewusst so

Zur Klarstellung, damit niemand später eines nachrüstet: Der abonnierbare ICS-Feed kommt ohne Schemafeld aus. Die Adresse trägt eine Signatur base64url(<betreuteId>.<userId>.<HMAC-SHA256>), berechnet mit AUTH_SECRET (siehe src/lib/fristen/ics.ts).

Vorteil: Es liegt kein dauerhaft gültiges Geheimnis in der Datenbank, das bei einem Datenbank-Leck mitgelesen werden könnte. Die Route prüft bei jedem Abruf zusätzlich, ob der Benutzer noch aktiv ist und noch Lesezugriff auf das Modul FRISTEN hat — ein entzogener Zugang leert den Kalender sofort.

Nachteil, der in Kauf genommen wird: Eine einzelne Adresse lässt sich nicht gezielt widerrufen, nur durch Wechsel von AUTH_SECRET (was alle Anmeldungen beendet). Falls das je gebraucht wird, wäre ein kalenderGeneration Int @default(0) an BetreuungsZugang die kleinste Lösung: Sie geht in den HMAC ein, und ein Hochzählen entwertet nur die Adressen dieses einen Zugangs.