Compare commits

..
4 Commits
Author SHA1 Message Date
florian.wilde c5db3baac0 Merge: Version 1.12.0 2026-09-01 14:40:22 +00:00
Florian Wilde 274d7666ea chore: Version 1.12.0 2026-09-01 16:39:59 +02:00
florian.wilde 890e00fb5c Merge #46: Wo die Daten liegen, und drei Fallen aus dem Betrieb 2026-09-01 14:37:25 +00:00
Florian Wilde 042e63812b Anleitung: wo die Daten liegen, und drei Fallen aus dem Betrieb
Aus einer Fehlersuche am 31.08.2026 sind vier Luecken in der Anleitung
uebriggeblieben. Keine davon war falsch formuliert - alle vier waren
schlicht nicht durchdacht.

1. Es stand nirgends, wo die Daten liegen. Der neue Abschnitt nennt die
   drei Orte, zeigt den Pfad auf der Platte, sagt ausdruecklich, dass dort
   keine anklickbaren PDFs liegen, und beschreibt den Abgleich zwischen
   Akte und Speicher: Zu jedem Eintrag muss eine Datei gehoeren, sonst
   belegt eine Pruefsumme ein Dokument, das es nicht mehr gibt.

2. Der mc-Alias wurde einmalig gesetzt. Er liegt in /root/.mc IM
   Behaelter und ist nach jedem "docker compose up -d minio" weg -
   "mc ls lokal" liefert dann kommentarlos nichts, und man haelt seine
   Dokumente fuer verschwunden. Genau das ist passiert. Jeder Aufruf setzt
   den Alias jetzt selbst, aus den Variablen des Behaelters.

3. Der Bucket-Name stand fest im Befehl, die Anwendung liest ihn aus
   S3_BUCKET. Weichen sie ab, zeigen beide aneinander vorbei.

4. "set -a && source .env" wurde empfohlen, ohne zu sagen, dass die
   exportierten Werte danach jedes "docker compose up" ueberstimmen. Wer
   spaeter die .env aendert und neu startet, sieht keine Wirkung und sucht
   den Fehler ueberall, nur nicht in der eigenen Shell. Der Kniff ist
   nicht mehr noetig - der neue Befehl kommt ohne ihn aus - und die Falle
   steht als Erklaerung daneben.

Dazu docker-compose.override.yml in der .gitignore und in der Anleitung
als vorgesehener Ort fuer Anpassungen, die ein Update ueberleben sollen:
update.sh prueft nur versionierte Dateien und laesst sie in Ruhe.

Die Aussage zur Sicherung ist mitgezogen - sie stimmt seit #41 nicht mehr,
die Dokumente sind jetzt enthalten.

Neun Pruefungen in tests/anleitung.test.ts, gegen vier Mutationen
geprueft: Name fest verdrahtet, Alias nicht gesetzt, source .env zurueck,
Abschnitt entfernt - jede wird rot.

Refs #46
2026-09-01 16:36:48 +02:00
9 changed files with 334 additions and 20 deletions
+8
View File
@@ -11,6 +11,14 @@ dist/
next-env.d.ts next-env.d.ts
*.tsbuildinfo *.tsbuildinfo
# Eigene Anpassungen der Installation.
#
# Docker Compose liest diese Datei automatisch zusaetzlich zur
# docker-compose.yml. Sie ist der vorgesehene Ort fuer Aenderungen, die ein
# Update ueberleben sollen: update.sh prueft nur versionierte Dateien
# (git status --untracked-files=no) und laesst sie deshalb in Ruhe.
docker-compose.override.yml
# Umgebung - enthaelt Schluessel, gehoert NIE ins Repo # Umgebung - enthaelt Schluessel, gehoert NIE ins Repo
.env .env
.env.local .env.local
+82 -1
View File
@@ -26,6 +26,86 @@ Wiederherstellung*.
_Noch nichts._ _Noch nichts._
## [1.12.0] – 2026-09-01
Diese Fassung geht aus einer Fehlersuche im laufenden Betrieb hervor. Ein
Schreiben ließ sich nicht in der Akte ablegen — und hinter derselben
Meldung lagen nacheinander drei verschiedene Ursachen. Beim Nachsehen kam
ein vierter Punkt dazu, der schwerer wiegt als alle anderen zusammen.
### Nach dem Update: einmal die Sicherung prüfen
```bash
docker compose up -d
docker compose exec sicherung /bin/sh /sicherung.sh
```
Erwartet werden drei Zeilen: `Datenbank gesichert`, `Dokumente gesichert`
und `Selbstpruefung bestanden - Datenbank und Dokumente.`
### Behoben
- **Deine Dokumente waren in keiner Sicherung.** Der Sicherungsdienst
machte täglich ein `pg_dump` und sonst nichts. Nach einem Plattenschaden
wäre die Akte vollständig wiederhergestellt worden — mit allen
Einträgen, Verweisen und Prüfsummen, aber ohne eine einzige Datei
dahinter. Die Prüfsumme in der Akte hätte dann ein Dokument belegt, das
es nicht mehr gibt.
Je Lauf entstehen jetzt zwei verschlüsselte Dateien mit demselben
Zeitstempel — der Datenbankstand und ein Archiv der Dokumente. Beide mit
Prüfsumme, beide in der Aufbewahrung, beide in der Selbstprüfung.
Schlägt der Dokumententeil fehl, bricht der Lauf ab und räumt den
angefangenen Datenbankstand weg: Eine Sicherung, die nur die halbe
Wahrheit enthält, aber vollständig aussieht, ist schlimmer als gar
keine.
- **Der mitgelieferte Objektspeicher konnte keine Dokumente aufnehmen.**
Die Anwendung verlangte bei jeder Ablage serverseitige Verschlüsselung,
das mitgelieferte MinIO kann sie ohne Zusatzdienst nicht. Wer der
Installationsanleitung folgte, landete zwangsläufig dort. Sie ist jetzt
abschaltbar und standardmäßig aus — gebraucht wird sie nicht, weil die
Anwendung seit 1.11.0 selbst verschlüsselt.
- **„Das Schreiben konnte nicht abgelegt werden" sagte nichts.** Jetzt
steht dort, was los ist: fehlender Ablagebereich mit Verweis auf den
Installationsschritt, abgelehnte Zugangsdaten, nicht erreichbarer
Speicher. Und in jedem Fall, ob deine Eingaben erhalten bleiben.
- **Zwei Einstellungen erreichten die Anwendung nie.**
`ERSTEINRICHTUNG_GEHEIMNIS` und `VERTRAUE_PROXY` standen zwar in der
Anleitung, wurden aber nicht an den Behälter durchgereicht. Bei
`VERTRAUE_PROXY` fiel das nicht auf: Die Anmeldesperre zählte still eine
Dimension weniger.
- **Die Beispielkonfiguration zeigte auf einen fremden Anbieter.**
`S3_ENDPOINT` war mit einer externen Adresse vorbelegt und hebelte damit
den richtigen Standard aus. Die Zeile ist jetzt auskommentiert.
### Neu
- **Die Anwendung prüft ihre Dateiablage selbst.** Sie schreibt eine
winzige Datei, liest sie zurück und räumt sie weg — und beantwortet
damit auf einmal, ob der Speicher erreichbar ist, der Ablagebereich
existiert und geschrieben werden darf. Das Ergebnis steht unter
`/api/gesundheit` und im Log. Bisher fiel eine kaputte Konfiguration
erst auf, wenn jemand ein Dokument ablegen wollte.
- **Ein neuer Abschnitt in der Anleitung: „Wo deine Daten liegen".**
Die drei Orte, der Pfad auf der Platte, welche Schlüssel unverzichtbar
sind — und wie man prüft, ob zu jedem Akteneintrag auch eine Datei
gehört.
### Geändert
- **Ausschlussfristen warnen nur noch, wenn sie näherrücken.** Auf dem
Dashboard standen dauerhaft drei rote Kästen mit Warndreieck — für
Aufwandspauschalen, die 2027, 2028 und 2029 ablaufen. Eine Warnung, die
monatelang dasteht und nichts von einem will, stumpft ab; man übersieht
die vierte, die etwas will. Ab drei Monaten vor Ablauf meldet sich eine
Frist wieder, Versäumtes immer. In der Fristenliste stehen sie
unverändert weiter.
## [1.11.0] – 2026-08-24 ## [1.11.0] – 2026-08-24
Diese Fassung geht aus einer Sicherheitsprüfung hervor. Sie ändert nichts Diese Fassung geht aus einer Sicherheitsprüfung hervor. Sie ändert nichts
@@ -1265,7 +1345,8 @@ 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.11.0...HEAD [Unveröffentlicht]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.12.0...HEAD
[1.12.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.11.0...v1.12.0
[1.11.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.10.2...v1.11.0 [1.11.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.10.2...v1.11.0
[1.10.2]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.10.1...v1.10.2 [1.10.2]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.10.1...v1.10.2
[1.10.1]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.10.0...v1.10.1 [1.10.1]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.10.0...v1.10.1
+128 -13
View File
@@ -34,6 +34,7 @@ durchgeht — dann weißt du im Fehlerfall genau, wo es hakt.
- [Schritt 9 — Sicherung prüfen](#schritt-9--sicherung-prüfen) - [Schritt 9 — Sicherung prüfen](#schritt-9--sicherung-prüfen)
- [Schritt 10 — Wartungslauf einrichten](#schritt-10--wartungslauf-einrichten) - [Schritt 10 — Wartungslauf einrichten](#schritt-10--wartungslauf-einrichten)
- [Schritt 11 — Schlüssel in Sicherheit bringen](#schritt-11--schlüssel-in-sicherheit-bringen) - [Schritt 11 — Schlüssel in Sicherheit bringen](#schritt-11--schlüssel-in-sicherheit-bringen)
- [Wo deine Daten liegen](#wo-deine-daten-liegen)
- [Aktualisieren](#aktualisieren) - [Aktualisieren](#aktualisieren)
- [Wenn etwas nicht klappt](#wenn-etwas-nicht-klappt) - [Wenn etwas nicht klappt](#wenn-etwas-nicht-klappt)
- [Abnahmeliste](#abnahmeliste) - [Abnahmeliste](#abnahmeliste)
@@ -322,7 +323,7 @@ betreuungs-cockpit-sicherung-1 Up
```bash ```bash
# Antwortet die Anwendung? (Port anpassen, falls du APP_PORT gesetzt hast) # Antwortet die Anwendung? (Port anpassen, falls du APP_PORT gesetzt hast)
curl -s http://127.0.0.1:3000/api/gesundheit curl -s http://127.0.0.1:3000/api/gesundheit
# {"status":"bereit","version":"1.11.1","commit":"...", # {"status":"bereit","version":"1.12.0","commit":"...",
# "speicher":{"status":"bereit","treiber":"s3"}} # "speicher":{"status":"bereit","treiber":"s3"}}
``` ```
@@ -375,22 +376,37 @@ nichts kaputtmacht.
Der Objektspeicher braucht einen Ablagebereich für die Dokumente: Der Objektspeicher braucht einen Ablagebereich für die Dokumente:
```bash ```bash
set -a && source .env && set +a docker compose exec minio sh -c '
mc alias set lokal http://localhost:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" >/dev/null &&
docker compose exec minio mc alias set lokal \ mc mb "lokal/$S3_BUCKET" 2>/dev/null || true
http://localhost:9000 "$S3_ACCESS_KEY_ID" "$S3_SECRET_ACCESS_KEY" mc ls lokal
'
docker compose exec minio mc mb lokal/betreuungs-cockpit
``` ```
### Kontrolle Es muss eine Zeile mit dem Namen deines Ablagebereichs erscheinen —
standardmäßig `betreuungs-cockpit/`.
```bash > **Warum der Befehl so umständlich aussieht.** Er holt die Zugangsdaten
docker compose exec minio mc ls lokal > aus den Variablen, die im MinIO-Behälter ohnehin stehen. Das hat drei
# [...] betreuungs-cockpit/ > Gründe, und jeder davon hat schon einmal Zeit gekostet:
``` >
> 1. **Kein Passwort in der Befehlszeile** — es stünde sonst in der
> Verlaufsdatei deiner Shell.
> 2. **Kein `source .env`** — exportierte Werte haben Vorrang vor der
> `.env`-Datei und überstimmen danach *jedes* `docker compose up`. Wer
> später die `.env` ändert und neu startet, sieht keine Wirkung und
> sucht den Fehler überall, nur nicht in der eigenen Shell.
> 3. **Der Alias überlebt kein Neuerstellen.** `mc alias set` schreibt
> nach `/root/.mc` **im Behälter**. Nach jedem `docker compose up -d
> minio` ist er weg, und `mc ls lokal` liefert dann kommentarlos nichts
> — man hält seine Dokumente für verschwunden. Deshalb setzt jeder
> Aufruf den Alias selbst.
>
> Der Bucket-Name kommt aus `$S3_BUCKET` und ist nicht fest verdrahtet:
> Sonst zeigen Anwendung und Ablagebereich aneinander vorbei, sobald
> jemand den Namen ändert.
> **Serverseitige Verschluesselung?** Brauchst du nicht. Die Anwendung > **Serverseitige Verschlüsselung?** Brauchst du nicht. Die Anwendung
> verschlüsselt jede Datei selbst, bevor sie den Server verlässt — mit > verschlüsselt jede Datei selbst, bevor sie den Server verlässt — mit
> `ENC_KEY_V1`, der den Anbieter nie erreicht. Das mitgelieferte MinIO > `ENC_KEY_V1`, der den Anbieter nie erreicht. Das mitgelieferte MinIO
> läuft ohne KMS und würde jede Ablage ablehnen, sobald `S3_SSE` in der > läuft ohne KMS und würde jede Ablage ablehnen, sobald `S3_SSE` in der
@@ -913,6 +929,105 @@ Denk an die letzten Pflichten:
--- ---
## Wo deine Daten liegen
Drei Orte, und keiner davon ist ein Ordner, den du einfach öffnest.
| Was | Wo | In der täglichen Sicherung? |
|---|---|---|
| **Dokumente** (Bescheide, Schreiben, Belege) | Docker-Volume `minio-daten` | ja |
| **Datenbank** (Akte, Fristen, Buchungen) | Docker-Volume `postgres-daten` | ja |
| **Sicherungen** | `./backups` neben der `docker-compose.yml` | — |
### Den Pfad auf der Platte finden
```bash
docker volume inspect betreuungs-cockpit_minio-daten --format '{{.Mountpoint}}'
# /var/lib/docker/volumes/betreuungs-cockpit_minio-daten/_data
```
Heißt dein Projektverzeichnis anders, heißen auch die Volumes anders —
Docker stellt den Verzeichnisnamen voran:
```bash
docker volume ls | grep -E "minio-daten|postgres-daten"
```
> **Dort hineinzusehen bringt nichts.** MinIO legt jedes Dokument als
> eigenes Verzeichnis mit Metadatei und Datenteilen ab, und der Inhalt ist
> verschlüsselt. Du fändest dort keine anklickbaren PDFs, sondern
> Fragmente. Wer die Dokumente sehen will, nimmt die Anwendung.
### Nachsehen, was abgelegt ist
```bash
docker compose exec minio sh -c '
mc alias set lokal http://localhost:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" >/dev/null &&
mc ls --recursive "lokal/$S3_BUCKET"
'
```
Je Dokument eine Zeile unter `betreute/<id>/dokumente/<uuid>.pdf`.
### Prüfen, ob Akte und Speicher übereinstimmen
Die wichtigste Kontrolle: Zu **jedem** Eintrag in der Akte muss eine Datei
gehören. Fehlt sie, belegt eine Prüfsumme ein Dokument, das es nicht mehr
gibt — gegenüber dem Betreuungsgericht der schlechteste Zustand.
```bash
docker compose exec -T db sh -c 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -At -c "SELECT \"objektSchluessel\" FROM dokument WHERE \"geloeschtAm\" IS NULL ORDER BY 1;"' | sort > /tmp/erwartet.txt
docker compose exec minio sh -c '
mc alias set lokal http://localhost:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" >/dev/null &&
mc ls --recursive "lokal/$S3_BUCKET"
' | awk '{print $NF}' | sort > /tmp/vorhanden.txt
echo "In der Akte: $(wc -l < /tmp/erwartet.txt) Im Speicher: $(wc -l < /tmp/vorhanden.txt)"
echo "--- Fehlt im Speicher (Handlungsbedarf): ---"
comm -23 /tmp/erwartet.txt /tmp/vorhanden.txt
echo "--- Verwaist im Speicher (harmlos): ---"
comm -13 /tmp/erwartet.txt /tmp/vorhanden.txt
```
Beide Zahlen gleich und beide Listen leer — dann passt es.
Ein Eintrag unter *„Fehlt im Speicher"* ist ein Akteneintrag ohne Datei.
Er entsteht, wenn eine Ablage scheitert. Solche Einträge löschen und das
Dokument neu anlegen.
### Ohne welche Schlüssel nichts davon lesbar ist
| Schlüssel | Ohne ihn |
|---|---|
| `ENC_KEY_V1` | Diagnosen, IBANs, Notizen und alle Dokumente bleiben unlesbar — auch aus jeder Sicherung |
| `SICHERUNG_PASSWORT` | keine Sicherung lässt sich öffnen |
| `MINIO_KMS_SECRET_KEY` | nur falls gesetzt: MinIO gibt die Objekte nicht mehr heraus |
Alle gehören an die zwei Orte aus Schritt 11, und keiner davon ist dieser
Server.
### Eigene Anpassungen, die ein Update überleben
Änderungen an der `docker-compose.yml` legt `scripts/update.sh` bei jedem
Update per `git stash` beiseite — sie sind versioniert. Wer etwas dauerhaft
ändern will, legt stattdessen eine **`docker-compose.override.yml`**
daneben:
```yaml
services:
app:
environment:
EIGENER_WERT: ${EIGENER_WERT:-}
```
Docker Compose liest sie automatisch mit. `update.sh` prüft nur
versionierte Dateien (`git status --untracked-files=no`) und lässt sie
deshalb unangetastet.
---
## Aktualisieren ## Aktualisieren
```bash ```bash
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "betreuungs-cockpit", "name": "betreuungs-cockpit",
"version": "1.11.0", "version": "1.12.0",
"private": true, "private": true,
"description": "Arbeits- und Dokumentationswerkzeug fuer die ehrenamtliche rechtliche Betreuung", "description": "Arbeits- und Dokumentationswerkzeug fuer die ehrenamtliche rechtliche Betreuung",
"engines": { "engines": {
+2 -2
View File
@@ -100,7 +100,7 @@ echo "$(date -Iseconds) Datenbank wiederhergestellt."
# --- Dokumente --------------------------------------------------------------- # --- Dokumente ---------------------------------------------------------------
# Zu "cockpit_2026-09-01_0315.dump.enc" gehoert # Zu "cockpit_2026-09-01_0315.dump.enc" gehoert
# "dokumente_2026-09-01_0315.tar.gz.enc" - gleicher Zeitstempel, anderer # "dokumente_2026-09-01_0315.tar.gz.enc" - gleicher Zeitstempel, anderer
# Name. Fehlt sie, stammt die Sicherung aus einer Fassung vor v1.11.1. # Name. Fehlt sie, stammt die Sicherung aus einer Fassung vor v1.12.0.
ZEITSTEMPEL="$(basename "$DATEI" | sed -n 's/^cockpit_\(.*\)\.dump\.enc$/\1/p')" ZEITSTEMPEL="$(basename "$DATEI" | sed -n 's/^cockpit_\(.*\)\.dump\.enc$/\1/p')"
DOKUMENTE_DATEI="$(dirname "$DATEI")/dokumente_${ZEITSTEMPEL}.tar.gz.enc" DOKUMENTE_DATEI="$(dirname "$DATEI")/dokumente_${ZEITSTEMPEL}.tar.gz.enc"
AUSPACKZIEL="$(dirname "$DATEI")/dokumente-wiederhergestellt_${ZEITSTEMPEL}" AUSPACKZIEL="$(dirname "$DATEI")/dokumente-wiederhergestellt_${ZEITSTEMPEL}"
@@ -109,7 +109,7 @@ if [ ! -f "$DOKUMENTE_DATEI" ]; then
echo "" echo ""
echo "WARNUNG: Zu dieser Sicherung gibt es kein Dokumentenarchiv." echo "WARNUNG: Zu dieser Sicherung gibt es kein Dokumentenarchiv."
echo " Erwartet wurde: $DOKUMENTE_DATEI" echo " Erwartet wurde: $DOKUMENTE_DATEI"
echo " Sicherungen aus Fassungen vor v1.11.1 enthalten nur die" echo " Sicherungen aus Fassungen vor v1.12.0 enthalten nur die"
echo " Datenbank. Die Akte ist dann vollstaendig, die Dateien" echo " Datenbank. Die Akte ist dann vollstaendig, die Dateien"
echo " dahinter fehlen." echo " dahinter fehlen."
else else
+1 -1
View File
@@ -6,7 +6,7 @@ import { speicherfehlerErkennen } from '@/lib/speicher/fehler'
/** /**
* Ist die Dateiablage benutzbar? * Ist die Dateiablage benutzbar?
* *
* Bis v1.11.1 fiel eine kaputte Speicherkonfiguration erst auf, wenn * Bis v1.12.0 fiel eine kaputte Speicherkonfiguration erst auf, wenn
* jemand ein Dokument ablegen wollte. Auf dem Livesystem waren das * jemand ein Dokument ablegen wollte. Auf dem Livesystem waren das
* mehrere Wochen nach der Installation - und dann mitten in der Arbeit, * mehrere Wochen nach der Installation - und dann mitten in der Arbeit,
* mit einer Meldung, die nichts sagte. * mit einer Meldung, die nichts sagte.
+1 -1
View File
@@ -17,7 +17,7 @@
*/ */
/** Muss zur "version" in der package.json passen. */ /** Muss zur "version" in der package.json passen. */
export const VERSION = '1.11.0' export const VERSION = '1.12.0'
/** /**
* Kurzer Git-Stand, beim Bauen hineingereicht: * Kurzer Git-Stand, beim Bauen hineingereicht:
+110
View File
@@ -0,0 +1,110 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
/**
* Die Installationsanleitung muss ausführbar sein, nicht nur lesbar.
*
* Anlass ist eine Fehlersuche vom 31.08.2026. Drei Stellen der Anleitung
* haben dabei Zeit gekostet — keine davon war falsch formuliert, alle drei
* waren schlicht nicht durchdacht:
*
* 1. `mc alias set` wurde einmalig gesetzt. Der Alias liegt in `/root/.mc`
* **im Behälter** und ist nach jedem `docker compose up -d minio` weg.
* `mc ls lokal` liefert dann kommentarlos nichts — man hält seine
* Dokumente für verschwunden.
* 2. Der Bucket-Name stand fest im Befehl, die Anwendung liest ihn aus
* `S3_BUCKET`. Weichen sie ab, zeigen beide aneinander vorbei.
* 3. `set -a && source .env` exportiert alle Werte in die Shell — und die
* haben danach Vorrang vor der `.env`-Datei. Wer später etwas ändert
* und neu startet, sieht keine Wirkung.
*
* Diese Prüfungen lesen den Text. Sie können die Anleitung nicht
* ausführen, aber sie schlagen an, sobald jemand in eine der Fallen
* zurückfällt.
*/
const anleitung = readFileSync('docs/INSTALLATION.md', 'utf8')
/** Alle Zeilen mit einem mc-Aufruf, ohne Fließtext und Zitate. */
function mcZeilen(): string[] {
return anleitung
.split('\n')
.filter((zeile) => /\bmc (ls|mb|mirror|cp|rm|stat)\b/.test(zeile))
.filter((zeile) => !zeile.trim().startsWith('>'))
}
describe('Installationsanleitung', () => {
it('setzt bei jedem mc-Aufruf den Alias selbst', () => {
// Sonst funktioniert der Befehl nur, solange der Behaelter nicht neu
// erstellt wurde - und das sagt einem niemand.
const abschnitte = anleitung.split('```')
const ohneAlias = abschnitte
.filter((block) => /\bmc (ls|mb|mirror|cp|rm|stat)\b/.test(block))
.filter((block) => !block.includes('mc alias set'))
expect(
ohneAlias.length,
'Ein mc-Befehl ohne "mc alias set" im selben Block läuft nur, solange ' +
'der MinIO-Behälter nicht neu erstellt wurde.',
).toBe(0)
})
it('verdrahtet den Namen des Ablagebereichs nicht fest', () => {
const festVerdrahtet = mcZeilen().filter((zeile) => /lokal\/betreuungs-cockpit/.test(zeile))
expect(
festVerdrahtet,
'Der Name gehört aus $S3_BUCKET - sonst zeigen Anwendung und ' +
'Ablagebereich aneinander vorbei, sobald jemand ihn ändert.',
).toEqual([])
})
it('empfiehlt kein "source .env" mehr', () => {
// Exportierte Werte ueberstimmen danach jedes "docker compose up".
const zeilen = anleitung
.split('\n')
.filter((zeile) => !zeile.trim().startsWith('>'))
.filter((zeile) => !zeile.trim().startsWith('#'))
.filter((zeile) => /source \.env/.test(zeile))
expect(zeilen).toEqual([])
})
it('erklärt trotzdem, warum es nicht empfohlen wird', () => {
// Weglassen allein hilft nicht: Wer den Kniff von woanders kennt,
// benutzt ihn weiter.
expect(anleitung).toMatch(/Vorrang vor der/)
})
it('sagt, wo die Daten liegen', () => {
expect(anleitung).toMatch(/## Wo deine Daten liegen/)
expect(anleitung).toMatch(/docker volume inspect/)
expect(anleitung).toMatch(/minio-daten/)
expect(anleitung).toMatch(/postgres-daten/)
})
it('zeigt, wie man Akte und Speicher abgleicht', () => {
// Die wichtigste Kontrolle: Zu jedem Akteneintrag muss eine Datei
// gehoeren, sonst belegt eine Pruefsumme ein Dokument, das es nicht
// mehr gibt.
expect(anleitung).toMatch(/objektSchluessel/)
expect(anleitung).toMatch(/comm -23/)
})
it('nennt die Schlüssel, ohne die nichts mehr lesbar ist', () => {
const abschnitt = anleitung.slice(anleitung.indexOf('## Wo deine Daten liegen'))
for (const schluessel of ['ENC_KEY_V1', 'SICHERUNG_PASSWORT', 'MINIO_KMS_SECRET_KEY']) {
expect(abschnitt, `${schluessel} fehlt in der Aufzählung`).toContain(schluessel)
}
})
it('weist docker-compose.override.yml als Ort für eigene Anpassungen aus', () => {
expect(anleitung).toMatch(/docker-compose\.override\.yml/)
expect(readFileSync('.gitignore', 'utf8')).toMatch(/docker-compose\.override\.yml/)
})
it('behauptet nicht mehr, die Dokumente seien ungesichert', () => {
// Stand bis v1.12.0 so drin und stimmt seit der Sicherung nicht mehr.
expect(anleitung).not.toMatch(/Was das Backup nicht enthält:.*Dateien im Objektspeicher/s)
})
})
+1 -1
View File
@@ -6,7 +6,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
/** /**
* Die Bereitschaftsprüfung der Dateiablage. * Die Bereitschaftsprüfung der Dateiablage.
* *
* Bis v1.11.1 fiel eine kaputte Speicherkonfiguration erst auf, wenn * Bis v1.12.0 fiel eine kaputte Speicherkonfiguration erst auf, wenn
* jemand ein Dokument ablegen wollte. Auf dem Livesystem waren das * jemand ein Dokument ablegen wollte. Auf dem Livesystem waren das
* mehrere Wochen nach der Installation — und dann mitten in der Arbeit, * mehrere Wochen nach der Installation — und dann mitten in der Arbeit,
* mit einer Meldung, die nichts sagte. * mit einer Meldung, die nichts sagte.