Zeilenenden der 24 verbliebenen Dateien normalisieren
Ausschliesslich Zeilenenden. Nachgewiesen mit "git diff --cached --ignore-cr-at-eol": Der Diff ist leer, es hat sich kein Zeichen Inhalt geaendert. Deshalb ein eigener Commit: 7448 geaenderte Zeilen in einem Commit mit echten Aenderungen zu verstecken, macht die Historie an dieser Stelle unlesbar. So laesst er sich beim Durchsehen ueberspringen. Refs #26
This commit is contained in:
+187
-187
@@ -1,187 +1,187 @@
|
||||
# Schema-Wünsche aus Etappe 3 „Papier“
|
||||
|
||||
Gesammelt beim Bau der Dokumentenakte. `prisma/schema.prisma` wurde
|
||||
absprachegemäß **nicht** angefasst; alles hier ist umgangen worden und
|
||||
funktioniert, wäre aber sauberer, wenn es im Modell stünde.
|
||||
|
||||
Reihenfolge: was am meisten weh tut, steht oben.
|
||||
|
||||
---
|
||||
|
||||
## 1. `DokumentVerknuepfung`: genau eine Zielspalte — nur in der Anwendung erzwungen
|
||||
|
||||
**Stand:** Zwölf nullbare Fremdschlüsselspalten. Der Kommentar im Schema sagt
|
||||
„Die Anwendung stellt sicher, dass genau eine Ziel-Spalte gesetzt ist“ — genau
|
||||
so ist es umgesetzt (`ZIEL_SPALTE` in `src/lib/validierung/dokumente.ts`,
|
||||
Prüfung in `dokumentVerknuepfen`).
|
||||
|
||||
**Wunsch:** Ein CHECK-Constraint in der Datenbank, damit auch ein Skript, ein
|
||||
Seed oder ein späterer Import das nicht verletzen kann:
|
||||
|
||||
```sql
|
||||
ALTER TABLE dokument_verknuepfung ADD CONSTRAINT genau_ein_ziel CHECK (
|
||||
(("vorgangId" IS NOT NULL)::int + ("fristId" IS NOT NULL)::int
|
||||
+ ("buchungId" IS NOT NULL)::int + ("vermoegenspostenId" IS NOT NULL)::int
|
||||
+ ("immobilieId" IS NOT NULL)::int + ("vertragId" IS NOT NULL)::int
|
||||
+ ("kontaktprotokollId" IS NOT NULL)::int + ("gesundheitsereignisId" IS NOT NULL)::int
|
||||
+ ("genehmigungId" IS NOT NULL)::int + ("nachforderungId" IS NOT NULL)::int
|
||||
+ ("bescheidId" IS NOT NULL)::int + ("kontaktId" IS NOT NULL)::int) = 1
|
||||
);
|
||||
```
|
||||
|
||||
Ließe sich als eigenes SQL-Skript neben `volltextsuche.sql` legen, ohne das
|
||||
Prisma-Schema zu ändern. **Warum wichtig:** Eine Akte, in der eine Verknüpfung
|
||||
auf zwei Dinge gleichzeitig zeigt, ist gegenüber dem Gericht nicht mehr
|
||||
erklärbar.
|
||||
|
||||
**Zusätzlich:** Es fehlt eine Eindeutigkeit je Paar. Doppelte Verknüpfungen
|
||||
werden derzeit vor dem Anlegen abgefragt (`findFirst`) — ein Race zwischen zwei
|
||||
Klicks kann sie trotzdem erzeugen. Ein partieller Unique-Index je Zielspalte,
|
||||
z. B. `CREATE UNIQUE INDEX ... ON dokument_verknuepfung ("dokumentId", "vorgangId")
|
||||
WHERE "vorgangId" IS NOT NULL;`, würde das schließen.
|
||||
|
||||
---
|
||||
|
||||
## 2. `Dokument.ocrStatus` ist ein freier String
|
||||
|
||||
**Stand:** `ocrStatus String?` mit dem Kommentar
|
||||
`"ausstehend" | "laeuft" | "fertig" | "fehlgeschlagen" | "nicht_verfuegbar"`.
|
||||
|
||||
**Wunsch:** Ein Enum `OcrStatus` mit genau diesen fünf Werten. Der Vertrag in
|
||||
`docs/SCHNITTSTELLEN.md` Abschnitt 3 gibt sie ohnehin vor, und die Oberfläche
|
||||
(`OcrAbzeichen`) schaltet darauf. Ein Tippfehler beim Zurückschreiben fällt
|
||||
heute erst auf, wenn das Abzeichen leer bleibt.
|
||||
|
||||
---
|
||||
|
||||
## 3. Kein Index auf `Dokument.objektSchluessel`
|
||||
|
||||
**Stand:** Die Ausliefer-Route `/api/dokumente/datei/[signatur]` sucht das
|
||||
Dokument über `objektSchluessel`, um Anzeigename und Protokolleintrag zu
|
||||
bekommen. Ohne Index ist das ein Seq-Scan bei jedem Dateiabruf.
|
||||
|
||||
**Wunsch:** `@@unique([objektSchluessel])` (der Schlüssel ist eine UUID, also
|
||||
ohnehin eindeutig) oder mindestens `@@index([objektSchluessel])`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Keine Dublettenerkennung über die Prüfsumme
|
||||
|
||||
**Stand:** `pruefsumme String?` (SHA-256, wird beim Ablegen gefüllt). Wer
|
||||
denselben Bescheid zweimal fotografiert, bekommt zwei Datensätze.
|
||||
|
||||
**Wunsch:** `@@index([betreuteId, pruefsumme])`. Dann ließe sich beim Upload
|
||||
sagen „dieses Blatt liegt schon in der Akte, angelegt am 12.03.2026“ — ohne den
|
||||
zweiten Upload zu verbieten (manchmal ist die zweite Kopie gewollt).
|
||||
|
||||
---
|
||||
|
||||
## 5. `Nachforderung` und `Bescheid` tragen keine `betreuteId`
|
||||
|
||||
**Stand:** Beide hängen nur am `SozialhilfeAntrag`. Die Zugriffsprüfung beim
|
||||
Verknüpfen muss deshalb über die Beziehung gehen
|
||||
(`where: { id, antrag: { betreuteId } }`, siehe `zielGehoertZurAkte`).
|
||||
|
||||
**Wunsch:** Eine denormalisierte `betreuteId` wie bei allen anderen
|
||||
Fachentitäten. Die Konvention „jede Abfrage ist auf `betreuteId` eingegrenzt“
|
||||
ist sonst an genau diesen zwei Stellen nicht wörtlich einhaltbar — und
|
||||
Ausnahmen von einer Sicherheitsregel sind die Stellen, an denen später Fehler
|
||||
passieren.
|
||||
|
||||
---
|
||||
|
||||
## 6. Seitenzahl und OCR-Lauf ohne Zeitstempel
|
||||
|
||||
**Stand:** `seitenzahl Int?` wird von der Texterkennung nachgetragen. Wann ein
|
||||
OCR-Lauf zuletzt versucht wurde, steht nirgends.
|
||||
|
||||
**Wunsch:** `ocrVersuchtAm DateTime?`. `ocrNachziehen()` in
|
||||
`src/lib/dokumente/ocr-nachlauf.ts` holt heute alles nach, was auf
|
||||
`ausstehend`/`fehlgeschlagen` steht — mit einem Zeitstempel ließe sich ein
|
||||
dauerhaft kaputtes Dokument nach dem dritten Versuch in Ruhe lassen, statt es
|
||||
bei jedem Nachziehen erneut durch Tesseract zu schicken.
|
||||
|
||||
---
|
||||
|
||||
## 7. Anmerkung zur Verschlüsselung der abgelegten Dateien
|
||||
|
||||
Kein Schema-Wunsch, aber eine Abweichung vom Kommentar im Schema, die
|
||||
festgehalten gehört. Bei `Dokument.ocrText` steht:
|
||||
|
||||
> „die Datei selbst liegt verschlüsselt im Objektspeicher“
|
||||
|
||||
Umgesetzt ist das **nur beim Dateitreiber**: `src/lib/speicher/datei.ts`
|
||||
verschlüsselt jede Datei anwendungsseitig mit AES-256-GCM (eigener Binär-
|
||||
Umschlag `BCD1 | Schlüsselversion | IV | Tag | Geheimtext`, Schlüssel aus
|
||||
`ENC_KEY_V*`). Beim S3-Treiber geht das nicht: Der Vertrag verlangt für
|
||||
`signierteUrl()` eine presigned URL, die der Objektspeicher selbst ausliefert —
|
||||
ein anwendungsseitig verschlüsselter Blob käme dort als Datenmüll an. Dort
|
||||
läuft der Schutz deshalb über `ServerSideEncryption: AES256` plus den
|
||||
AV-Vertrag nach Art. 28 DSGVO mit dem Anbieter.
|
||||
|
||||
Die SHA-256-Prüfsumme wird in **beiden** Fällen über den Klartext gebildet —
|
||||
sonst wäre sie als Nachweis gegenüber dem Gericht wertlos.
|
||||
|
||||
Wer das vereinheitlichen will, müsste den Vertrag ändern: `signierteUrl()`
|
||||
würde auch beim S3-Treiber auf die eigene Route zeigen, die den Blob holt,
|
||||
entschlüsselt und ausliefert. Das kostet Durchsatz bei großen Scans, wäre aber
|
||||
konsequenter. Bewusst offengelassen, weil es Abschnitt 1 der Schnittstellen
|
||||
berührt.
|
||||
|
||||
---
|
||||
|
||||
# Anhang: kein Schema-Wunsch, aber dringend
|
||||
|
||||
## `@react-pdf/renderer` kann ohne Krücke keinen Buchstaben setzen
|
||||
|
||||
Beim Bau der Belegmappe aufgefallen und **betrifft jedes PDF der Anwendung**,
|
||||
also auch die Berichte aus Etappe 5.
|
||||
|
||||
**Befund:** Jeder Aufruf von `renderToBuffer` scheitert mit
|
||||
|
||||
```
|
||||
TypeError: Cannot read properties of undefined (reading 'unitsPerEm')
|
||||
at @react-pdf/textkit/lib/textkit.js:3090
|
||||
```
|
||||
|
||||
— auch bei einem Dokument ganz ohne Stilangaben. Nicht die Testumgebung ist
|
||||
schuld: in reinem Node reproduziert es genauso.
|
||||
|
||||
**Ursache:** In `package.json` ist nur `@react-pdf/renderer` auf `4.1.6`
|
||||
festgelegt. Seine Unterabhängigkeiten stehen als Caret-Bereiche darin und sind
|
||||
inzwischen weitergewandert:
|
||||
|
||||
| Paket | installiert | von renderer 4.1.6 erwartet |
|
||||
|---|---|---|
|
||||
| `@react-pdf/font` | 3.1.0 | `^3.0.1` |
|
||||
| `@react-pdf/layout` | 4.7.1 | `^4.2.0` |
|
||||
| `@react-pdf/textkit` | 6.4.1 | (kommt über `layout`) |
|
||||
|
||||
`@react-pdf/font@3.1.0` gibt für die Standardschriften `null` zurück — früher
|
||||
löste die Schicht darunter den bloßen Namen selbst auf.
|
||||
`@react-pdf/textkit@6.4.1` verlangt dagegen ein echtes Schriftobjekt mit
|
||||
`layout()` und wirft bei einem Namen ausdrücklich `Invalid font`. Zwischen
|
||||
beiden klafft eine Lücke.
|
||||
|
||||
**Was ich getan habe:** `src/lib/pdf/standardschrift.ts` baut das fehlende
|
||||
Schriftobjekt aus den Metriken, die `@react-pdf/pdfkit` ohnehin mitbringt, und
|
||||
hängt sich vor die Schriftauflösung — aber nur, wenn sie kaputt ist. Kein neues
|
||||
Paket, kein Nachladen aus dem Netz. `pdfErzeugen()` ruft das von selbst auf,
|
||||
alle PDF-Wege dieser Anwendung sind damit wieder benutzbar (Test:
|
||||
„Aus einem Bericht und einem Beleg wird eine Mappe" in `tests/dokumente.test.ts`).
|
||||
|
||||
**Was noch zu tun ist** (außerhalb meiner Pfade, deshalb hier):
|
||||
`package.json` um Festlegungen ergänzen, damit die Pakete zueinander passen —
|
||||
|
||||
```jsonc
|
||||
"overrides": {
|
||||
"@react-pdf/layout": "4.2.x",
|
||||
"@react-pdf/textkit": "5.x"
|
||||
}
|
||||
```
|
||||
|
||||
Die genauen Stände bitte gegen `@react-pdf/renderer@4.1.6` prüfen; alternativ
|
||||
`@react-pdf/renderer` auf einen aktuellen Stand heben, dessen
|
||||
Unterabhängigkeiten wieder zusammenpassen. Danach kann
|
||||
`standardschrift.ts` ersatzlos entfallen — `standardschriftenSicherstellen()`
|
||||
merkt von selbst, dass es nicht mehr gebraucht wird, und hält sich heraus.
|
||||
# Schema-Wünsche aus Etappe 3 „Papier“
|
||||
|
||||
Gesammelt beim Bau der Dokumentenakte. `prisma/schema.prisma` wurde
|
||||
absprachegemäß **nicht** angefasst; alles hier ist umgangen worden und
|
||||
funktioniert, wäre aber sauberer, wenn es im Modell stünde.
|
||||
|
||||
Reihenfolge: was am meisten weh tut, steht oben.
|
||||
|
||||
---
|
||||
|
||||
## 1. `DokumentVerknuepfung`: genau eine Zielspalte — nur in der Anwendung erzwungen
|
||||
|
||||
**Stand:** Zwölf nullbare Fremdschlüsselspalten. Der Kommentar im Schema sagt
|
||||
„Die Anwendung stellt sicher, dass genau eine Ziel-Spalte gesetzt ist“ — genau
|
||||
so ist es umgesetzt (`ZIEL_SPALTE` in `src/lib/validierung/dokumente.ts`,
|
||||
Prüfung in `dokumentVerknuepfen`).
|
||||
|
||||
**Wunsch:** Ein CHECK-Constraint in der Datenbank, damit auch ein Skript, ein
|
||||
Seed oder ein späterer Import das nicht verletzen kann:
|
||||
|
||||
```sql
|
||||
ALTER TABLE dokument_verknuepfung ADD CONSTRAINT genau_ein_ziel CHECK (
|
||||
(("vorgangId" IS NOT NULL)::int + ("fristId" IS NOT NULL)::int
|
||||
+ ("buchungId" IS NOT NULL)::int + ("vermoegenspostenId" IS NOT NULL)::int
|
||||
+ ("immobilieId" IS NOT NULL)::int + ("vertragId" IS NOT NULL)::int
|
||||
+ ("kontaktprotokollId" IS NOT NULL)::int + ("gesundheitsereignisId" IS NOT NULL)::int
|
||||
+ ("genehmigungId" IS NOT NULL)::int + ("nachforderungId" IS NOT NULL)::int
|
||||
+ ("bescheidId" IS NOT NULL)::int + ("kontaktId" IS NOT NULL)::int) = 1
|
||||
);
|
||||
```
|
||||
|
||||
Ließe sich als eigenes SQL-Skript neben `volltextsuche.sql` legen, ohne das
|
||||
Prisma-Schema zu ändern. **Warum wichtig:** Eine Akte, in der eine Verknüpfung
|
||||
auf zwei Dinge gleichzeitig zeigt, ist gegenüber dem Gericht nicht mehr
|
||||
erklärbar.
|
||||
|
||||
**Zusätzlich:** Es fehlt eine Eindeutigkeit je Paar. Doppelte Verknüpfungen
|
||||
werden derzeit vor dem Anlegen abgefragt (`findFirst`) — ein Race zwischen zwei
|
||||
Klicks kann sie trotzdem erzeugen. Ein partieller Unique-Index je Zielspalte,
|
||||
z. B. `CREATE UNIQUE INDEX ... ON dokument_verknuepfung ("dokumentId", "vorgangId")
|
||||
WHERE "vorgangId" IS NOT NULL;`, würde das schließen.
|
||||
|
||||
---
|
||||
|
||||
## 2. `Dokument.ocrStatus` ist ein freier String
|
||||
|
||||
**Stand:** `ocrStatus String?` mit dem Kommentar
|
||||
`"ausstehend" | "laeuft" | "fertig" | "fehlgeschlagen" | "nicht_verfuegbar"`.
|
||||
|
||||
**Wunsch:** Ein Enum `OcrStatus` mit genau diesen fünf Werten. Der Vertrag in
|
||||
`docs/SCHNITTSTELLEN.md` Abschnitt 3 gibt sie ohnehin vor, und die Oberfläche
|
||||
(`OcrAbzeichen`) schaltet darauf. Ein Tippfehler beim Zurückschreiben fällt
|
||||
heute erst auf, wenn das Abzeichen leer bleibt.
|
||||
|
||||
---
|
||||
|
||||
## 3. Kein Index auf `Dokument.objektSchluessel`
|
||||
|
||||
**Stand:** Die Ausliefer-Route `/api/dokumente/datei/[signatur]` sucht das
|
||||
Dokument über `objektSchluessel`, um Anzeigename und Protokolleintrag zu
|
||||
bekommen. Ohne Index ist das ein Seq-Scan bei jedem Dateiabruf.
|
||||
|
||||
**Wunsch:** `@@unique([objektSchluessel])` (der Schlüssel ist eine UUID, also
|
||||
ohnehin eindeutig) oder mindestens `@@index([objektSchluessel])`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Keine Dublettenerkennung über die Prüfsumme
|
||||
|
||||
**Stand:** `pruefsumme String?` (SHA-256, wird beim Ablegen gefüllt). Wer
|
||||
denselben Bescheid zweimal fotografiert, bekommt zwei Datensätze.
|
||||
|
||||
**Wunsch:** `@@index([betreuteId, pruefsumme])`. Dann ließe sich beim Upload
|
||||
sagen „dieses Blatt liegt schon in der Akte, angelegt am 12.03.2026“ — ohne den
|
||||
zweiten Upload zu verbieten (manchmal ist die zweite Kopie gewollt).
|
||||
|
||||
---
|
||||
|
||||
## 5. `Nachforderung` und `Bescheid` tragen keine `betreuteId`
|
||||
|
||||
**Stand:** Beide hängen nur am `SozialhilfeAntrag`. Die Zugriffsprüfung beim
|
||||
Verknüpfen muss deshalb über die Beziehung gehen
|
||||
(`where: { id, antrag: { betreuteId } }`, siehe `zielGehoertZurAkte`).
|
||||
|
||||
**Wunsch:** Eine denormalisierte `betreuteId` wie bei allen anderen
|
||||
Fachentitäten. Die Konvention „jede Abfrage ist auf `betreuteId` eingegrenzt“
|
||||
ist sonst an genau diesen zwei Stellen nicht wörtlich einhaltbar — und
|
||||
Ausnahmen von einer Sicherheitsregel sind die Stellen, an denen später Fehler
|
||||
passieren.
|
||||
|
||||
---
|
||||
|
||||
## 6. Seitenzahl und OCR-Lauf ohne Zeitstempel
|
||||
|
||||
**Stand:** `seitenzahl Int?` wird von der Texterkennung nachgetragen. Wann ein
|
||||
OCR-Lauf zuletzt versucht wurde, steht nirgends.
|
||||
|
||||
**Wunsch:** `ocrVersuchtAm DateTime?`. `ocrNachziehen()` in
|
||||
`src/lib/dokumente/ocr-nachlauf.ts` holt heute alles nach, was auf
|
||||
`ausstehend`/`fehlgeschlagen` steht — mit einem Zeitstempel ließe sich ein
|
||||
dauerhaft kaputtes Dokument nach dem dritten Versuch in Ruhe lassen, statt es
|
||||
bei jedem Nachziehen erneut durch Tesseract zu schicken.
|
||||
|
||||
---
|
||||
|
||||
## 7. Anmerkung zur Verschlüsselung der abgelegten Dateien
|
||||
|
||||
Kein Schema-Wunsch, aber eine Abweichung vom Kommentar im Schema, die
|
||||
festgehalten gehört. Bei `Dokument.ocrText` steht:
|
||||
|
||||
> „die Datei selbst liegt verschlüsselt im Objektspeicher“
|
||||
|
||||
Umgesetzt ist das **nur beim Dateitreiber**: `src/lib/speicher/datei.ts`
|
||||
verschlüsselt jede Datei anwendungsseitig mit AES-256-GCM (eigener Binär-
|
||||
Umschlag `BCD1 | Schlüsselversion | IV | Tag | Geheimtext`, Schlüssel aus
|
||||
`ENC_KEY_V*`). Beim S3-Treiber geht das nicht: Der Vertrag verlangt für
|
||||
`signierteUrl()` eine presigned URL, die der Objektspeicher selbst ausliefert —
|
||||
ein anwendungsseitig verschlüsselter Blob käme dort als Datenmüll an. Dort
|
||||
läuft der Schutz deshalb über `ServerSideEncryption: AES256` plus den
|
||||
AV-Vertrag nach Art. 28 DSGVO mit dem Anbieter.
|
||||
|
||||
Die SHA-256-Prüfsumme wird in **beiden** Fällen über den Klartext gebildet —
|
||||
sonst wäre sie als Nachweis gegenüber dem Gericht wertlos.
|
||||
|
||||
Wer das vereinheitlichen will, müsste den Vertrag ändern: `signierteUrl()`
|
||||
würde auch beim S3-Treiber auf die eigene Route zeigen, die den Blob holt,
|
||||
entschlüsselt und ausliefert. Das kostet Durchsatz bei großen Scans, wäre aber
|
||||
konsequenter. Bewusst offengelassen, weil es Abschnitt 1 der Schnittstellen
|
||||
berührt.
|
||||
|
||||
---
|
||||
|
||||
# Anhang: kein Schema-Wunsch, aber dringend
|
||||
|
||||
## `@react-pdf/renderer` kann ohne Krücke keinen Buchstaben setzen
|
||||
|
||||
Beim Bau der Belegmappe aufgefallen und **betrifft jedes PDF der Anwendung**,
|
||||
also auch die Berichte aus Etappe 5.
|
||||
|
||||
**Befund:** Jeder Aufruf von `renderToBuffer` scheitert mit
|
||||
|
||||
```
|
||||
TypeError: Cannot read properties of undefined (reading 'unitsPerEm')
|
||||
at @react-pdf/textkit/lib/textkit.js:3090
|
||||
```
|
||||
|
||||
— auch bei einem Dokument ganz ohne Stilangaben. Nicht die Testumgebung ist
|
||||
schuld: in reinem Node reproduziert es genauso.
|
||||
|
||||
**Ursache:** In `package.json` ist nur `@react-pdf/renderer` auf `4.1.6`
|
||||
festgelegt. Seine Unterabhängigkeiten stehen als Caret-Bereiche darin und sind
|
||||
inzwischen weitergewandert:
|
||||
|
||||
| Paket | installiert | von renderer 4.1.6 erwartet |
|
||||
|---|---|---|
|
||||
| `@react-pdf/font` | 3.1.0 | `^3.0.1` |
|
||||
| `@react-pdf/layout` | 4.7.1 | `^4.2.0` |
|
||||
| `@react-pdf/textkit` | 6.4.1 | (kommt über `layout`) |
|
||||
|
||||
`@react-pdf/font@3.1.0` gibt für die Standardschriften `null` zurück — früher
|
||||
löste die Schicht darunter den bloßen Namen selbst auf.
|
||||
`@react-pdf/textkit@6.4.1` verlangt dagegen ein echtes Schriftobjekt mit
|
||||
`layout()` und wirft bei einem Namen ausdrücklich `Invalid font`. Zwischen
|
||||
beiden klafft eine Lücke.
|
||||
|
||||
**Was ich getan habe:** `src/lib/pdf/standardschrift.ts` baut das fehlende
|
||||
Schriftobjekt aus den Metriken, die `@react-pdf/pdfkit` ohnehin mitbringt, und
|
||||
hängt sich vor die Schriftauflösung — aber nur, wenn sie kaputt ist. Kein neues
|
||||
Paket, kein Nachladen aus dem Netz. `pdfErzeugen()` ruft das von selbst auf,
|
||||
alle PDF-Wege dieser Anwendung sind damit wieder benutzbar (Test:
|
||||
„Aus einem Bericht und einem Beleg wird eine Mappe" in `tests/dokumente.test.ts`).
|
||||
|
||||
**Was noch zu tun ist** (außerhalb meiner Pfade, deshalb hier):
|
||||
`package.json` um Festlegungen ergänzen, damit die Pakete zueinander passen —
|
||||
|
||||
```jsonc
|
||||
"overrides": {
|
||||
"@react-pdf/layout": "4.2.x",
|
||||
"@react-pdf/textkit": "5.x"
|
||||
}
|
||||
```
|
||||
|
||||
Die genauen Stände bitte gegen `@react-pdf/renderer@4.1.6` prüfen; alternativ
|
||||
`@react-pdf/renderer` auf einen aktuellen Stand heben, dessen
|
||||
Unterabhängigkeiten wieder zusammenpassen. Danach kann
|
||||
`standardschrift.ts` ersatzlos entfallen — `standardschriftenSicherstellen()`
|
||||
merkt von selbst, dass es nicht mehr gebraucht wird, und hält sich heraus.
|
||||
|
||||
+243
-243
@@ -1,243 +1,243 @@
|
||||
# Schema-Wünsche aus Etappe 5 „Behörde“
|
||||
|
||||
Das Schema wurde nicht angefasst. Was beim Bauen des Sozialhilfemoduls
|
||||
gefehlt hat, steht hier — nach Dringlichkeit sortiert, jeweils mit dem
|
||||
Behelf, der jetzt an seiner Stelle steht.
|
||||
|
||||
---
|
||||
|
||||
## 1. `Heimkostenmonat`: Kostenseite und Deckungsseite überschneiden sich — wichtig
|
||||
|
||||
Dieselbe Sache wie Punkt 1 in `docs/schema-wuensche/dashboard.md`, hier aus
|
||||
Sicht des Moduls, das die Gegenüberstellung baut.
|
||||
|
||||
**Das Problem.** `pflegeEigenanteilCent` heißt „einrichtungseinheitlicher
|
||||
Eigenanteil". Der ist definitionsgemäß **schon um die Pauschale der
|
||||
Pflegekasse nach § 43 Abs. 2 SGB XI gekürzt**. Steht in derselben Zeile
|
||||
zusätzlich `pflegekasseCent` als Deckung, wird dasselbe Geld zweimal
|
||||
gezählt — die Deckungslücke fällt um die Pauschale zu klein aus, bei
|
||||
Pflegegrad 3 um 1.319 Euro im Monat.
|
||||
|
||||
**Was ich entschieden habe.** Dieses Modul rechnet in der Lesart
|
||||
`EIGENANTEIL_NETTO` (siehe Kopfkommentar in
|
||||
`src/lib/sozialhilfe/heimkosten.ts`):
|
||||
|
||||
```
|
||||
Bedarf = pflegeEigenanteil (netto, wie auf der Heimrechnung)
|
||||
+ unterkunftVerpflegung + investitionskosten
|
||||
+ ausbildungsumlage + zusatzleistungen
|
||||
+ barbetrag + bekleidungspauschale
|
||||
|
||||
Deckung = leistungszuschlag + rente + sonstigeEinkuenfte
|
||||
+ sozialhilfe + eigenmittel
|
||||
|
||||
Deckungslücke = Bedarf − Deckung
|
||||
```
|
||||
|
||||
`pflegekasseCent` zählt **nicht** als Deckung. Der Wert wird als
|
||||
`pflegekasseNachrichtlichCent` mitgeführt und angezeigt; ist er ungleich
|
||||
null, gibt `heimkostenAuswerten()` einen Hinweis aus, der die
|
||||
Doppelzählung erklärt. Das Formular belegt das Feld nicht mehr vor.
|
||||
|
||||
`leistungszuschlagCent` zählt dagegen **sehr wohl** als Deckung: Der
|
||||
Zuschlag nach § 43c SGB XI mindert den Eigenanteil erst danach und steht
|
||||
auf der Heimrechnung als eigene Abzugsposition.
|
||||
|
||||
Die Alternative — durchgängig den Bruttosatz erfassen — ist als Lesart
|
||||
`PFLEGESATZ_BRUTTO` implementiert und getestet: Bei konsistenter Erfassung
|
||||
kommen beide Lesarten auf dieselbe Deckungslücke. Benutzt wird sie in der
|
||||
Oberfläche nicht, weil das Schema keinen Ort hat, um die Wahl zu
|
||||
speichern.
|
||||
|
||||
**Wunsch, in dieser Reihenfolge:**
|
||||
|
||||
1. Den Kommentar am Feld schärfen, damit die Lesart im Schema steht und
|
||||
nicht nur hier:
|
||||
|
||||
```prisma
|
||||
/// NETTO: der einrichtungseinheitliche Eigenanteil, wie er auf der
|
||||
/// Heimrechnung steht - bereits um § 43 Abs. 2 SGB XI gekuerzt, noch
|
||||
/// nicht um den Leistungszuschlag. pflegekasseCent zaehlt deshalb NICHT
|
||||
/// als Deckung, sondern nur nachrichtlich.
|
||||
pflegeEigenanteilCent BigInt @default(0)
|
||||
```
|
||||
|
||||
2. Wenn beide Lesarten gebraucht werden, ein Feld dafür — sonst muss jedes
|
||||
Modul raten, was in der Zeile steht:
|
||||
|
||||
```prisma
|
||||
enum Kostenlesart {
|
||||
EIGENANTEIL_NETTO
|
||||
PFLEGESATZ_BRUTTO
|
||||
}
|
||||
|
||||
lesart Kostenlesart @default(EIGENANTEIL_NETTO)
|
||||
```
|
||||
|
||||
3. Alternativ ein `heimrechnungGesamtCent`, das schlicht den
|
||||
Rechnungsbetrag trägt; die Aufteilung wäre dann nur noch informativ und
|
||||
die Summe könnte gegen sie geprüft werden.
|
||||
|
||||
**Verabredung bis dahin**: Wer `Heimkostenmonat` schreibt — dieses Modul,
|
||||
das Dashboard, ein Import — trägt als `pflegeEigenanteilCent` den Netto-
|
||||
Eigenanteil ein und lässt `pflegekasseCent` auf 0.
|
||||
|
||||
---
|
||||
|
||||
## 2. `Nachforderung.checklistenSchluessel` — wichtig
|
||||
|
||||
```prisma
|
||||
/// Stabiler Schluessel aus src/lib/sozialhilfe/checkliste.ts.
|
||||
/// Verhindert Dubletten beim erneuten Uebernehmen der Standardunterlagen.
|
||||
checklistenSchluessel String?
|
||||
|
||||
@@unique([antragId, checklistenSchluessel])
|
||||
```
|
||||
|
||||
**Warum**: `ausCheckliste: Boolean` merkt sich nur *dass* eine Zeile aus der
|
||||
Checkliste kam, nicht *welche* Position. Um beim zweiten Aufruf des Panels
|
||||
nicht dieselbe Unterlage noch einmal anzulegen, vergleicht
|
||||
`nochNichtUebernommen()` derzeit über die **Bezeichnung** (kleingeschrieben,
|
||||
getrimmt). Das reicht, solange niemand die Bezeichnung ändert — tut er es,
|
||||
entsteht beim nächsten Übernehmen eine Dublette.
|
||||
|
||||
**Behelf**: Vergleich über die Bezeichnung in
|
||||
`src/lib/sozialhilfe/checkliste.ts` und in `checklisteUebernehmen()`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Rückkaufswert am Vertrag — wichtig
|
||||
|
||||
```prisma
|
||||
model Vertrag {
|
||||
// ...
|
||||
rueckkaufswertCent BigInt?
|
||||
rueckkaufswertStichtag DateTime? @db.Date
|
||||
}
|
||||
```
|
||||
|
||||
**Warum**: Die Bewertungsansicht stellt Vermögensposten und Verträge
|
||||
nebeneinander. Ein Vermögensposten trägt seinen Wert über `Wertstand`,
|
||||
ein Vertrag hat gar kein Wertfeld — nur `beitragCent`, und das ist die
|
||||
Prämie, nicht der Wert. Verträge erscheinen deshalb ohne Betrag, und die
|
||||
Summe „verwertbar“ ist unvollständig, solange nicht zu jeder Versicherung
|
||||
zusätzlich ein Vermögensposten angelegt wurde.
|
||||
|
||||
Für das Sozialhilfeverfahren ist genau dieser Wert der entscheidende: Der
|
||||
Träger fragt nach Rückkaufswerten, nicht nach Versicherungssummen.
|
||||
|
||||
**Behelf**: Die Bewertungsansicht zeigt nur Verträge, die überhaupt einen
|
||||
Wert haben können (`MIT_RUECKKAUFSWERT` aus
|
||||
`src/lib/vertraege/konstanten.ts`), und markiert sie mit „Wert noch nicht
|
||||
ermittelt“. Wer den Betrag braucht, legt zusätzlich einen
|
||||
`Vermoegensposten` mit `vertragId` und einem `Wertstand` an — dann wird der
|
||||
Vertrag in der Liste ausgeblendet, damit die Summe nicht doppelt zählt.
|
||||
|
||||
---
|
||||
|
||||
## 4. `Bescheid.rechtsbehelfsbelehrungVorhanden` — mittel
|
||||
|
||||
```prisma
|
||||
/// Ausdrueckliche Einschaetzung, nicht aus der Fristlaenge abgeleitet.
|
||||
rechtsbehelfsbelehrungVorhanden Boolean @default(true)
|
||||
rechtsbehelfsbelehrungBemerkung String?
|
||||
```
|
||||
|
||||
**Warum**: Ob die Jahresfrist des § 66 Abs. 2 SGG gilt, ist eine bewusste
|
||||
Einschätzung mit Begründung („die Belehrung nennt die falsche Behörde“).
|
||||
Derzeit wird sie aus `rechtsbehelfsfristMonate === 12` zurückgeschlossen —
|
||||
das trägt, verliert aber die Begründung, und die bräuchte man genau dann,
|
||||
wenn man sich im Widerspruchsverfahren darauf beruft.
|
||||
|
||||
**Behelf**: `belehrungZuMonaten()` in
|
||||
`src/lib/sozialhilfe/rechtsbehelf.ts`. Die Begründung gehört bis auf
|
||||
Weiteres in `notizenVerschluesselt`.
|
||||
|
||||
---
|
||||
|
||||
## 5. `Bescheid.widerspruchFristId` → `Frist` — mittel
|
||||
|
||||
```prisma
|
||||
widerspruchFristId String? @unique
|
||||
widerspruchFrist Frist? @relation(fields: [widerspruchFristId], references: [id], onDelete: SetNull)
|
||||
```
|
||||
|
||||
**Warum**: Die angelegte Frist „Widerspruch möglich bis“ wird derzeit über
|
||||
`Frist.systemSchluessel = "sozialhilfe-widerspruch-<bescheidId>"` gefunden.
|
||||
Das funktioniert (`@@unique([betreuteId, systemSchluessel])` trägt es), ist
|
||||
aber eine Verknüpfung über eine zusammengesetzte Zeichenkette. Ein echter
|
||||
Fremdschlüssel wäre sauberer und ließe die Frist beim Löschen des Bescheids
|
||||
mitziehen. Dasselbe gilt für
|
||||
`"sozialhilfe-nachforderung-<nachforderungId>"`.
|
||||
|
||||
**Behelf**: `systemSchluessel` mit festem Präfix, `upsert` statt `create`.
|
||||
|
||||
---
|
||||
|
||||
## 6. `Heimkostenmonat` — Feld für die tatsächliche Zahlung — mittel
|
||||
|
||||
```prisma
|
||||
/// Was tatsaechlich vom Konto ging - fuer den Abgleich mit dem Bescheid.
|
||||
gezahltCent BigInt?
|
||||
gezahltAm DateTime? @db.Date
|
||||
rechnungsnummer String?
|
||||
```
|
||||
|
||||
**Warum**: Die Gegenüberstellung rechnet Bedarf gegen Deckung. Was
|
||||
tatsächlich abgebucht wurde, steht nirgends — und genau die Differenz
|
||||
zwischen „laut Bescheid“ und „tatsächlich abgebucht“ ist der Anlass, beim
|
||||
Träger nachzufragen.
|
||||
|
||||
**Behelf**: `bemerkung`.
|
||||
|
||||
---
|
||||
|
||||
## 7. `Heimkostenmonat.abwesenheitsminderungCent` — klein
|
||||
|
||||
```prisma
|
||||
/// Tatsaechliche Minderung laut Heimrechnung, nicht die Schaetzung.
|
||||
abwesenheitsminderungCent BigInt @default(0)
|
||||
```
|
||||
|
||||
**Warum**: `abwesenheitstage` ist da, die Wirkung schätzt
|
||||
`abwesenheitSchaetzen()` nach dem Rahmenvertrag (drei Karenztage, danach
|
||||
25 % auf Pflegeanteil sowie Unterkunft und Verpflegung). Was die
|
||||
Einrichtung wirklich abgezogen hat, steht auf der Rechnung und ließe sich
|
||||
nicht festhalten.
|
||||
|
||||
**Behelf**: Die Schätzung wird ausdrücklich als Schätzung ausgewiesen und
|
||||
neben die erfasste Lücke gestellt, nicht in sie hineingerechnet.
|
||||
|
||||
---
|
||||
|
||||
## 8. `Leistung.wiederholungsfristMonat/-tag` — klein
|
||||
|
||||
```prisma
|
||||
/// Fuer jaehrlich zu wiederholende Antraege: Stichtag im Jahr.
|
||||
antragsschlussMonat Int?
|
||||
antragsschlussTag Int?
|
||||
```
|
||||
|
||||
**Warum**: `jaehrlichNeuBeantragen: Boolean` sagt, *dass* wiederholt werden
|
||||
muss, nicht *bis wann*. Beim Landespflegegeld ist der 31.12. eine
|
||||
Ausschlussfrist — daraus ließe sich automatisch eine Frist ableiten,
|
||||
statt sie von Hand anzulegen.
|
||||
|
||||
**Behelf**: `antragsschluss` als Text im Katalog
|
||||
(`src/lib/sozialhilfe/leistungskatalog.ts`) und ein Hinweis in der
|
||||
Oberfläche. Die Fristableitung übernimmt `pflichtfristenAbleiten()` mit
|
||||
`landespflegegeld-<jahr>` (siehe `docs/SCHNITTSTELLEN.md`).
|
||||
|
||||
---
|
||||
|
||||
## 9. `Nachforderung.notizenVerschluesselt` — klein
|
||||
|
||||
**Warum**: `erlaeuterung` und `begruendungNichtVorhanden` liegen im
|
||||
Klartext. Beides ist meist harmlos („Grundbuchauszug beim Amtsgericht
|
||||
angefordert“), kann aber Gesundheits- oder Vermögensangaben enthalten
|
||||
(„Rückkaufswert 12.480 Euro, Police verpfändet“). Wäre mindestens die
|
||||
Begründung verschlüsselt, wäre das konsequenter zum Rest des Schemas.
|
||||
|
||||
**Behelf**: keiner. Die Felder werden benutzt, wie sie sind. Falls sie
|
||||
verschlüsselt werden sollen, gehört `Nachforderung` in
|
||||
`VERSCHLUESSELTE_FELDER` in `src/lib/crypto/feld.ts`.
|
||||
# Schema-Wünsche aus Etappe 5 „Behörde“
|
||||
|
||||
Das Schema wurde nicht angefasst. Was beim Bauen des Sozialhilfemoduls
|
||||
gefehlt hat, steht hier — nach Dringlichkeit sortiert, jeweils mit dem
|
||||
Behelf, der jetzt an seiner Stelle steht.
|
||||
|
||||
---
|
||||
|
||||
## 1. `Heimkostenmonat`: Kostenseite und Deckungsseite überschneiden sich — wichtig
|
||||
|
||||
Dieselbe Sache wie Punkt 1 in `docs/schema-wuensche/dashboard.md`, hier aus
|
||||
Sicht des Moduls, das die Gegenüberstellung baut.
|
||||
|
||||
**Das Problem.** `pflegeEigenanteilCent` heißt „einrichtungseinheitlicher
|
||||
Eigenanteil". Der ist definitionsgemäß **schon um die Pauschale der
|
||||
Pflegekasse nach § 43 Abs. 2 SGB XI gekürzt**. Steht in derselben Zeile
|
||||
zusätzlich `pflegekasseCent` als Deckung, wird dasselbe Geld zweimal
|
||||
gezählt — die Deckungslücke fällt um die Pauschale zu klein aus, bei
|
||||
Pflegegrad 3 um 1.319 Euro im Monat.
|
||||
|
||||
**Was ich entschieden habe.** Dieses Modul rechnet in der Lesart
|
||||
`EIGENANTEIL_NETTO` (siehe Kopfkommentar in
|
||||
`src/lib/sozialhilfe/heimkosten.ts`):
|
||||
|
||||
```
|
||||
Bedarf = pflegeEigenanteil (netto, wie auf der Heimrechnung)
|
||||
+ unterkunftVerpflegung + investitionskosten
|
||||
+ ausbildungsumlage + zusatzleistungen
|
||||
+ barbetrag + bekleidungspauschale
|
||||
|
||||
Deckung = leistungszuschlag + rente + sonstigeEinkuenfte
|
||||
+ sozialhilfe + eigenmittel
|
||||
|
||||
Deckungslücke = Bedarf − Deckung
|
||||
```
|
||||
|
||||
`pflegekasseCent` zählt **nicht** als Deckung. Der Wert wird als
|
||||
`pflegekasseNachrichtlichCent` mitgeführt und angezeigt; ist er ungleich
|
||||
null, gibt `heimkostenAuswerten()` einen Hinweis aus, der die
|
||||
Doppelzählung erklärt. Das Formular belegt das Feld nicht mehr vor.
|
||||
|
||||
`leistungszuschlagCent` zählt dagegen **sehr wohl** als Deckung: Der
|
||||
Zuschlag nach § 43c SGB XI mindert den Eigenanteil erst danach und steht
|
||||
auf der Heimrechnung als eigene Abzugsposition.
|
||||
|
||||
Die Alternative — durchgängig den Bruttosatz erfassen — ist als Lesart
|
||||
`PFLEGESATZ_BRUTTO` implementiert und getestet: Bei konsistenter Erfassung
|
||||
kommen beide Lesarten auf dieselbe Deckungslücke. Benutzt wird sie in der
|
||||
Oberfläche nicht, weil das Schema keinen Ort hat, um die Wahl zu
|
||||
speichern.
|
||||
|
||||
**Wunsch, in dieser Reihenfolge:**
|
||||
|
||||
1. Den Kommentar am Feld schärfen, damit die Lesart im Schema steht und
|
||||
nicht nur hier:
|
||||
|
||||
```prisma
|
||||
/// NETTO: der einrichtungseinheitliche Eigenanteil, wie er auf der
|
||||
/// Heimrechnung steht - bereits um § 43 Abs. 2 SGB XI gekuerzt, noch
|
||||
/// nicht um den Leistungszuschlag. pflegekasseCent zaehlt deshalb NICHT
|
||||
/// als Deckung, sondern nur nachrichtlich.
|
||||
pflegeEigenanteilCent BigInt @default(0)
|
||||
```
|
||||
|
||||
2. Wenn beide Lesarten gebraucht werden, ein Feld dafür — sonst muss jedes
|
||||
Modul raten, was in der Zeile steht:
|
||||
|
||||
```prisma
|
||||
enum Kostenlesart {
|
||||
EIGENANTEIL_NETTO
|
||||
PFLEGESATZ_BRUTTO
|
||||
}
|
||||
|
||||
lesart Kostenlesart @default(EIGENANTEIL_NETTO)
|
||||
```
|
||||
|
||||
3. Alternativ ein `heimrechnungGesamtCent`, das schlicht den
|
||||
Rechnungsbetrag trägt; die Aufteilung wäre dann nur noch informativ und
|
||||
die Summe könnte gegen sie geprüft werden.
|
||||
|
||||
**Verabredung bis dahin**: Wer `Heimkostenmonat` schreibt — dieses Modul,
|
||||
das Dashboard, ein Import — trägt als `pflegeEigenanteilCent` den Netto-
|
||||
Eigenanteil ein und lässt `pflegekasseCent` auf 0.
|
||||
|
||||
---
|
||||
|
||||
## 2. `Nachforderung.checklistenSchluessel` — wichtig
|
||||
|
||||
```prisma
|
||||
/// Stabiler Schluessel aus src/lib/sozialhilfe/checkliste.ts.
|
||||
/// Verhindert Dubletten beim erneuten Uebernehmen der Standardunterlagen.
|
||||
checklistenSchluessel String?
|
||||
|
||||
@@unique([antragId, checklistenSchluessel])
|
||||
```
|
||||
|
||||
**Warum**: `ausCheckliste: Boolean` merkt sich nur *dass* eine Zeile aus der
|
||||
Checkliste kam, nicht *welche* Position. Um beim zweiten Aufruf des Panels
|
||||
nicht dieselbe Unterlage noch einmal anzulegen, vergleicht
|
||||
`nochNichtUebernommen()` derzeit über die **Bezeichnung** (kleingeschrieben,
|
||||
getrimmt). Das reicht, solange niemand die Bezeichnung ändert — tut er es,
|
||||
entsteht beim nächsten Übernehmen eine Dublette.
|
||||
|
||||
**Behelf**: Vergleich über die Bezeichnung in
|
||||
`src/lib/sozialhilfe/checkliste.ts` und in `checklisteUebernehmen()`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Rückkaufswert am Vertrag — wichtig
|
||||
|
||||
```prisma
|
||||
model Vertrag {
|
||||
// ...
|
||||
rueckkaufswertCent BigInt?
|
||||
rueckkaufswertStichtag DateTime? @db.Date
|
||||
}
|
||||
```
|
||||
|
||||
**Warum**: Die Bewertungsansicht stellt Vermögensposten und Verträge
|
||||
nebeneinander. Ein Vermögensposten trägt seinen Wert über `Wertstand`,
|
||||
ein Vertrag hat gar kein Wertfeld — nur `beitragCent`, und das ist die
|
||||
Prämie, nicht der Wert. Verträge erscheinen deshalb ohne Betrag, und die
|
||||
Summe „verwertbar“ ist unvollständig, solange nicht zu jeder Versicherung
|
||||
zusätzlich ein Vermögensposten angelegt wurde.
|
||||
|
||||
Für das Sozialhilfeverfahren ist genau dieser Wert der entscheidende: Der
|
||||
Träger fragt nach Rückkaufswerten, nicht nach Versicherungssummen.
|
||||
|
||||
**Behelf**: Die Bewertungsansicht zeigt nur Verträge, die überhaupt einen
|
||||
Wert haben können (`MIT_RUECKKAUFSWERT` aus
|
||||
`src/lib/vertraege/konstanten.ts`), und markiert sie mit „Wert noch nicht
|
||||
ermittelt“. Wer den Betrag braucht, legt zusätzlich einen
|
||||
`Vermoegensposten` mit `vertragId` und einem `Wertstand` an — dann wird der
|
||||
Vertrag in der Liste ausgeblendet, damit die Summe nicht doppelt zählt.
|
||||
|
||||
---
|
||||
|
||||
## 4. `Bescheid.rechtsbehelfsbelehrungVorhanden` — mittel
|
||||
|
||||
```prisma
|
||||
/// Ausdrueckliche Einschaetzung, nicht aus der Fristlaenge abgeleitet.
|
||||
rechtsbehelfsbelehrungVorhanden Boolean @default(true)
|
||||
rechtsbehelfsbelehrungBemerkung String?
|
||||
```
|
||||
|
||||
**Warum**: Ob die Jahresfrist des § 66 Abs. 2 SGG gilt, ist eine bewusste
|
||||
Einschätzung mit Begründung („die Belehrung nennt die falsche Behörde“).
|
||||
Derzeit wird sie aus `rechtsbehelfsfristMonate === 12` zurückgeschlossen —
|
||||
das trägt, verliert aber die Begründung, und die bräuchte man genau dann,
|
||||
wenn man sich im Widerspruchsverfahren darauf beruft.
|
||||
|
||||
**Behelf**: `belehrungZuMonaten()` in
|
||||
`src/lib/sozialhilfe/rechtsbehelf.ts`. Die Begründung gehört bis auf
|
||||
Weiteres in `notizenVerschluesselt`.
|
||||
|
||||
---
|
||||
|
||||
## 5. `Bescheid.widerspruchFristId` → `Frist` — mittel
|
||||
|
||||
```prisma
|
||||
widerspruchFristId String? @unique
|
||||
widerspruchFrist Frist? @relation(fields: [widerspruchFristId], references: [id], onDelete: SetNull)
|
||||
```
|
||||
|
||||
**Warum**: Die angelegte Frist „Widerspruch möglich bis“ wird derzeit über
|
||||
`Frist.systemSchluessel = "sozialhilfe-widerspruch-<bescheidId>"` gefunden.
|
||||
Das funktioniert (`@@unique([betreuteId, systemSchluessel])` trägt es), ist
|
||||
aber eine Verknüpfung über eine zusammengesetzte Zeichenkette. Ein echter
|
||||
Fremdschlüssel wäre sauberer und ließe die Frist beim Löschen des Bescheids
|
||||
mitziehen. Dasselbe gilt für
|
||||
`"sozialhilfe-nachforderung-<nachforderungId>"`.
|
||||
|
||||
**Behelf**: `systemSchluessel` mit festem Präfix, `upsert` statt `create`.
|
||||
|
||||
---
|
||||
|
||||
## 6. `Heimkostenmonat` — Feld für die tatsächliche Zahlung — mittel
|
||||
|
||||
```prisma
|
||||
/// Was tatsaechlich vom Konto ging - fuer den Abgleich mit dem Bescheid.
|
||||
gezahltCent BigInt?
|
||||
gezahltAm DateTime? @db.Date
|
||||
rechnungsnummer String?
|
||||
```
|
||||
|
||||
**Warum**: Die Gegenüberstellung rechnet Bedarf gegen Deckung. Was
|
||||
tatsächlich abgebucht wurde, steht nirgends — und genau die Differenz
|
||||
zwischen „laut Bescheid“ und „tatsächlich abgebucht“ ist der Anlass, beim
|
||||
Träger nachzufragen.
|
||||
|
||||
**Behelf**: `bemerkung`.
|
||||
|
||||
---
|
||||
|
||||
## 7. `Heimkostenmonat.abwesenheitsminderungCent` — klein
|
||||
|
||||
```prisma
|
||||
/// Tatsaechliche Minderung laut Heimrechnung, nicht die Schaetzung.
|
||||
abwesenheitsminderungCent BigInt @default(0)
|
||||
```
|
||||
|
||||
**Warum**: `abwesenheitstage` ist da, die Wirkung schätzt
|
||||
`abwesenheitSchaetzen()` nach dem Rahmenvertrag (drei Karenztage, danach
|
||||
25 % auf Pflegeanteil sowie Unterkunft und Verpflegung). Was die
|
||||
Einrichtung wirklich abgezogen hat, steht auf der Rechnung und ließe sich
|
||||
nicht festhalten.
|
||||
|
||||
**Behelf**: Die Schätzung wird ausdrücklich als Schätzung ausgewiesen und
|
||||
neben die erfasste Lücke gestellt, nicht in sie hineingerechnet.
|
||||
|
||||
---
|
||||
|
||||
## 8. `Leistung.wiederholungsfristMonat/-tag` — klein
|
||||
|
||||
```prisma
|
||||
/// Fuer jaehrlich zu wiederholende Antraege: Stichtag im Jahr.
|
||||
antragsschlussMonat Int?
|
||||
antragsschlussTag Int?
|
||||
```
|
||||
|
||||
**Warum**: `jaehrlichNeuBeantragen: Boolean` sagt, *dass* wiederholt werden
|
||||
muss, nicht *bis wann*. Beim Landespflegegeld ist der 31.12. eine
|
||||
Ausschlussfrist — daraus ließe sich automatisch eine Frist ableiten,
|
||||
statt sie von Hand anzulegen.
|
||||
|
||||
**Behelf**: `antragsschluss` als Text im Katalog
|
||||
(`src/lib/sozialhilfe/leistungskatalog.ts`) und ein Hinweis in der
|
||||
Oberfläche. Die Fristableitung übernimmt `pflichtfristenAbleiten()` mit
|
||||
`landespflegegeld-<jahr>` (siehe `docs/SCHNITTSTELLEN.md`).
|
||||
|
||||
---
|
||||
|
||||
## 9. `Nachforderung.notizenVerschluesselt` — klein
|
||||
|
||||
**Warum**: `erlaeuterung` und `begruendungNichtVorhanden` liegen im
|
||||
Klartext. Beides ist meist harmlos („Grundbuchauszug beim Amtsgericht
|
||||
angefordert“), kann aber Gesundheits- oder Vermögensangaben enthalten
|
||||
(„Rückkaufswert 12.480 Euro, Police verpfändet“). Wäre mindestens die
|
||||
Begründung verschlüsselt, wäre das konsequenter zum Rest des Schemas.
|
||||
|
||||
**Behelf**: keiner. Die Felder werden benutzt, wie sie sind. Falls sie
|
||||
verschlüsselt werden sollen, gehört `Nachforderung` in
|
||||
`VERSCHLUESSELTE_FELDER` in `src/lib/crypto/feld.ts`.
|
||||
|
||||
Reference in New Issue
Block a user