feat: Jahresbericht, Vollexport, Wissensbasis und Mitleser-Freigaben

Etappe 7. Die Ausgabeschicht - alles, was diese Anwendung nach aussen
abgibt.

Der Jahresbericht nach § 1863 BGB ist ein ENTWURF zum Ueberarbeiten,
kein fertiger Text. Er zieht sich die fuenf Gliederungspunkte aus
Kontaktprotokollen, Gesundheitsereignissen und Vorgangsstatus zusammen;
was davor abgegeben wird, entscheidet der Betreuer. Das sagt auch die
Oberflaeche. Ausgabe als PDF und als DOCX, damit sich weiterschreiben
laesst.

Vollexport als ZIP-Strom mit Gegendruck, damit auch grosse Bestaende
ohne Speicherausbruch durchgehen: Originaldateien nach Jahren sortiert,
alle Tabellen als entschluesseltes JSON, die erzeugten Berichte, ein
LIESMICH und SHA-256 je Datei. Damit laesst sich die Anwendung
verlassen - kein Datensilo.

Der Export ist eine sensible Aktion: nur BETREUER und ADMIN, nur nach
frischer Anmeldung, immer mit Audit-Eintrag. Ein Mitleser kommt nicht
heran.

37 Hinweiskarten in daten/hinweise.json, Zod-geprueft und ohne
Neustart pflegbar. Jede mit Rechtsgrundlage, Link und dem stehenden
Vermerk, dass sie keine Rechtsberatung ersetzt.

Modulweise Freigaben fuer Mitleser, mit ausdruecklicher Warnung bei
Gesundheit, Finanzen und Sozialhilfe. Rollen- und Freigabeaenderungen
erfordern eine frische Anmeldung und stehen im Audit-Log.

Nebenbei geloest: Webpack loest .tsx vor .ts auf, TypeScript und Vitest
umgekehrt. Ein Modul, das beide Endungen traegt, importiert sich unter
einem der beiden Werkzeuge selbst. Deshalb heissen die Bausteine jetzt
eindeutig (jahresbericht.entwurf.ts, .inhalt.tsx, .ausgabe.ts) und
werden ueber eine gemeinsame Fassade weitergereicht.

41 Tests.

Etappe: 7
Phase: Ausgabe
This commit is contained in:
Florian Wilde
2026-08-22 06:22:44 +02:00
parent b69a12da8f
commit 5cc7f5c140
29 changed files with 5573 additions and 3076 deletions
@@ -0,0 +1,71 @@
import { SeitenKopf } from '@/components/seiten-kopf'
import { Rechtshinweis } from '@/components/rechtshinweis'
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
import { BelegmappeFormular } from '@/components/berichte/belegmappe-formular'
import { berichtskontext } from '@/components/berichte/kontext'
import { HinweisKarten } from '@/components/hinweise/HinweisKarten'
import { db, nichtGeloescht } from '@/lib/db'
import { alsIsoTag, heuteAlsTag, tag } from '@/lib/fristen/datum'
export const metadata = { title: 'Belegmappe' }
/**
* Belegmappe zusammenstellen.
*
* Vorbelegt ist das vergangene Kalenderjahr - der Zeitraum, fuer den das
* Gericht die Belege sehen will. Wer eine Mappe zu einer einzelnen Sache
* braucht (weil der Bezirk nachfragt), waehlt stattdessen den Vorgang.
*/
export default async function BelegmappeSeite() {
const { betreuteId, darfBerichteSchreiben } = await berichtskontext('lesen')
const heute = heuteAlsTag()
const vorjahr = heute.getUTCFullYear() - 1
const vorgaenge = await db.vorgang.findMany({
where: { betreuteId, ...nichtGeloescht },
select: { id: true, titel: true, status: true },
orderBy: [{ status: 'asc' }, { erstelltAm: 'desc' }],
take: 200,
})
return (
<div className="space-y-8">
<SeitenKopf
titel="Belegmappe"
pfad={[{ titel: 'Berichte', href: '/berichte' }, { titel: 'Belegmappe' }]}
beschreibung="Alle Belege eines Zeitraums oder eines Vorgangs als ein PDF – mit Deckblatt, laufender Nummer und Verzeichnis, damit ein Beleg auch in zwei Jahren noch auffindbar ist."
/>
<Alert variant="hinweis">
<AlertTitle>Belege gehören zur Rechnungslegung</AlertTitle>
<AlertDescription>
Auch als befreiter Betreuer, der nur eine Vermögensübersicht schuldet, solltest du die
Belege sammeln und geordnet halten: Das Gericht kann sie anfordern, und am Ende der
Betreuung ist Schlussrechnung zu legen. Dann liegt die Beweislast bei dir.
</AlertDescription>
</Alert>
{darfBerichteSchreiben ? (
<BelegmappeFormular
betreuteId={betreuteId}
vorgaenge={vorgaenge.map((vorgang) => ({
id: vorgang.id,
titel:
vorgang.status === 'ERLEDIGT' ? `${vorgang.titel} (erledigt)` : vorgang.titel,
}))}
vorschlagVon={alsIsoTag(tag(vorjahr, 1, 1))}
vorschlagBis={alsIsoTag(tag(vorjahr, 12, 31))}
/>
) : (
<p className="text-sm text-muted-foreground">
Du hast nur Leserechte für die Berichte und kannst deshalb keine Belegmappe erzeugen.
</p>
)}
<HinweisKarten kontext={['BERICHTE', 'FINANZEN', 'DOKUMENTE']} />
<Rechtshinweis rechtsgrundlage="§ 1865, § 1872 BGB" />
</div>
)
}