From 8cbfb8b69d29609b7d6ba653878c44f98c5e4037 Mon Sep 17 00:00:00 2001 From: Schalli Date: Tue, 22 Sep 2026 15:25:31 +0200 Subject: [PATCH] docs(quick-260922-hk4): Changelog, Betriebsanleitung und Todo zur data-Spalte - Changelog unter Unveroeffentlicht -> Geaendert: Bilder liegen im Dateibereich, vorhandene ziehen beim ersten Start automatisch um - Betriebsanleitung Kap. 6: user-files nennt die Bilderrahmen-Bilder und haelt fest, dass pg_dump allein sie nicht mehr enthaelt - Todo fuer Stufe 2 (DROP data, storagePath NOT NULL) mit Vorbedingung, Migrationsname und den Nacharbeiten an Spec und Klassifikation Co-Authored-By: Claude Opus 5 (1M context) --- ...2-dashboard-image-data-spalte-entfernen.md | 82 +++++++++++++++++++ CHANGELOG.md | 4 + docs/anleitung-betrieb.md | 13 ++- 3 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 .planning/todos/pending/2026-09-22-dashboard-image-data-spalte-entfernen.md diff --git a/.planning/todos/pending/2026-09-22-dashboard-image-data-spalte-entfernen.md b/.planning/todos/pending/2026-09-22-dashboard-image-data-spalte-entfernen.md new file mode 100644 index 0000000..e5cbc7f --- /dev/null +++ b/.planning/todos/pending/2026-09-22-dashboard-image-data-spalte-entfernen.md @@ -0,0 +1,82 @@ +--- +created: 2026-09-22 +title: DashboardImage — Spalte "data" entfernen und "storagePath" auf NOT NULL setzen (Stufe 2 der Umstellung aus quick-260922-hk4) +area: apps/api/prisma +severity: cleanup +trigger: erst wenn alpha UND live je einmal mit einer Version >= der Freigabe nach 1.3.0 gelaufen sind — dann hat der Bootstrap-Umzug auf beiden Servern gearbeitet und die Bytes liegen im Dateibereich. +relates_to: quick-260922-hk4 (.planning/quick/260922-hk4-bilderrahmen-bilder-auf-die-festplatte/) +--- + +## Worum es geht + +Die Bilder des Bilderrahmen-Widgets sind mit `quick-260922-hk4` aus der +Datenbank in den Dateibereich gezogen (`user-files/dashboard-images/ +/.`, Pfad in der Spalte `storagePath`). Die Umstellung ist +BEWUSST ZWEISTUFIG: + +- **Stufe 1, ausgeliefert** (Migration `20260922120000_dashboard_image_to_disk`): + `storagePath` dazu (NULLbar), `data` wird NULLbar — aber NICHT gelöscht. + Der Umzug der vorhandenen Zeilen passiert beim ersten Start automatisch + (`DashboardImagesService.onApplicationBootstrap()`). +- **Stufe 2, dieser Zettel:** `data` löschen, `storagePath` auf NOT NULL. + +Warum nicht sofort: `prisma migrate deploy` läuft VOR dem Anwendungsstart. +Ein sofortiges `DROP COLUMN "data"` hätte die Bytes vernichtet, bevor der +Umzug beim Start sie lesen konnte (T-HK4-03). + +## Was zu tun ist + +1. **Vorbedingung prüfen** (auf BEIDEN Servern, alpha und live): + + ```sql + SELECT count(*) FROM "DashboardImage" WHERE "storagePath" IS NULL; + ``` + + Muss überall `0` sein. Ist sie es nicht, ist der Umzug dort noch nicht + gelaufen (Server noch auf einer älteren Version) — dann NICHT ausliefern. + +2. **Neue Migration** `20260922120100_dashboard_image_drop_data`: + + ```sql + ALTER TABLE "DashboardImage" ALTER COLUMN "storagePath" SET NOT NULL; + ALTER TABLE "DashboardImage" DROP COLUMN "data"; + ``` + +3. **Schema** `apps/api/prisma/schema.prisma`: Feld `data Bytes?` entfernen, + `storagePath String?` → `storagePath String`. + +4. **Dienst** `apps/api/src/dashboard/dashboard-images.service.ts`: + `onApplicationBootstrap()` samt `forSystem()`-Aufruf entfernt sich damit + — der Umzug hat seine Arbeit getan. Danach: + - Eintrag `apps/api/src/dashboard/dashboard-images.service.ts` aus + `FORSYSTEM_ALLOWED_CALL_SITES` in `apps/api/src/prisma/rls-access-inventory.spec.ts` + wieder ENTFERNEN (die Liste ist ein „genau", ein veralteter Eintrag + macht die Spec rot). + - In `docs/mandantentrennung-zugriffsklassifikation.md` den Stand der Zeile + `dashboard-images.service.ts`/`dashboardImage` von `system-gebunden` + zurück auf `gebunden` setzen und die Zahlen der Bereichszeile + `dashboard` sowie die Summe neu messen (Gate-Schleife, nicht + abschreiben). + - Die Tests 18, 21, 22 und 23 der Dienst-Spec (Zeile ohne `storagePath`, + Bootstrap-Umzug) entfallen mit dem Umzug. + - Die Regel `system_read_policy` auf `"DashboardImage"` (angelegt in + 20260922120000) kann bleiben oder mit `DROP POLICY` fallen — bleibt sie, + gehört sie in der Klassifikation erwähnt; fällt sie, ist die + Aufzählung „fünf/sechs Tabellen" dort nachzuziehen. + +5. **Prüfen**, dass die Datenbank kleiner wird: + + ```sql + SELECT pg_size_pretty(pg_total_relation_size('"DashboardImage"')); + ``` + + (Nach dem DROP zusätzlich `VACUUM FULL "DashboardImage";`, sonst gibt + PostgreSQL den Platz nicht ans Dateisystem zurück.) + +## Was passiert, wenn es liegen bleibt + +Nichts Schlimmes: die Spalte steht leer herum und kostet je neuer Zeile +nichts. Der Gewinn der Umstellung (kleiner `pg_dump`) ist bereits da, weil +neue Uploads keine Bytes mehr in die Zeile schreiben. Nur die Bytes der +ALTEN Bilder bleiben bis dahin doppelt vorhanden — einmal in der Datei, +einmal in der Spalte. diff --git a/CHANGELOG.md b/CHANGELOG.md index 046c9fb..912670a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ Diese Liste beschreibt in einfachen Worten, was sich von Version zu Version an T ## Unveröffentlicht +### Geändert + +- Bilderrahmen: hochgeladene Bilder liegen jetzt im Dateibereich des Servers statt in der Datenbank — die Datenbanksicherung bleibt dadurch klein; vorhandene Bilder ziehen beim ersten Start automatisch um + ## 1.3.0 – 2026-09-22 ### Neu diff --git a/docs/anleitung-betrieb.md b/docs/anleitung-betrieb.md index 386f0ca..b85b94f 100644 --- a/docs/anleitung-betrieb.md +++ b/docs/anleitung-betrieb.md @@ -283,8 +283,11 @@ Restores stattfinden. - **Verschlüsselungsschlüssel** `TESSERA_ENCRYPTION_KEY`: liegt nur in `.env` auf dem Host, **nicht** im Datenbank-Dump. Getrennt sichern (siehe Kapitel 2/3) – ohne ihn sind alle per `pg_dump` gesicherten verschlüsselten Zugangsdaten wertlos. -- **Hochgeladene Dateien** (Avatare unter `user-files/avatars/`, generierte - DKV-Exporte unter `user-files/`, siehe `apps/api/src/user/user.controller.ts` und +- **Hochgeladene Dateien** (Avatare unter `user-files/avatars/`, Bilder des + Bilderrahmen-Widgets unter `user-files/dashboard-images//`, + generierte DKV-Exporte unter `user-files/`, siehe + `apps/api/src/user/user.controller.ts`, + `apps/api/src/dashboard/dashboard-images.service.ts` und `apps/api/src/dkv/dkv-export.service.ts`): Diese Dateien liegen im benannten Docker-Volume `user-files`, gemountet auf `/app/user-files` im Dienst `api`. Der Mount ist in `docker-compose.yml` und `docker-compose.prod.yml` eingetragen: @@ -296,7 +299,11 @@ Restores stattfinden. user-files: ``` - Damit überstehen Avatare und DKV-Exporte ein `--force-recreate` von `api`. Wie bei + Damit überstehen Avatare, Bilderrahmen-Bilder und DKV-Exporte ein + `--force-recreate` von `api`. Seit den Bilderrahmen-Bildern (Version nach 1.3.0) + gehört dieses Volume zwingend zur Sicherung: `pg_dump` allein enthält diese + Bilder nicht mehr — genau das ist der Zweck der Umstellung, der + Datenbank-Abzug bleibt dadurch klein. Wie bei `pgdata` zeigt `docker volume ls` das Volume mit vorangestelltem Projektnamen an (`_user-files`). Gesichert werden die Dateien weiterhin mit `docker compose cp api:/app/user-files ./user-files-backup`, alternativ über eine