Phase 11: Freigabereife
Pruefung / pruefung (pull_request) Canceled after 0s
Pruefung / oberflaeche (pull_request) Canceled after 0s

Kein Modul, sondern die drei Software-Voraussetzungen fuer 1.0.0:
Auskunft nach Art. 15 DSGVO, ein geprueftes Sicherungskonzept und eine
Pipeline.

Das Auskunftsrecht war ein Versprechen ohne Umsetzung: `person.export`
stand seit Phase 0 im Katalog und war dem Kommandanten zugewiesen,
implementiert war nichts. Ohne Auskunftsseite ist ein Loeschkonzept nicht
abnehmbar. Jetzt sammelt FLORIAN dreizehn Abschnitte ueber eine Person,
mit dem Zweck ueber jedem - Art. 15 verlangt nicht nur die Daten, sondern
auch Zwecke und Rechte, und eine blosse Liste erfuellt die Pflicht nicht.
Ein Durchgang liefert Anzeige, PDF und JSON nach Art. 20.

Die Trennlinie ist "ueber mich" gegen "von mir": was ueber die Person
gespeichert ist, steht vollstaendig drin, auch das Unangenehme. Was sie
getan hat, steht als Zahl drin - die Pruefprotokolle gehoeren zum
Nachweisbestand der Wehr, und vollstaendig ausgeliefert kaeme jeder ueber
eine Selbstauskunft an die Geraeteakten.

Die Rueckspielprobe hat sich sofort bezahlt gemacht: der erste Versuch
lief sauber durch und hatte dabei saemtliche Unveraenderlichkeitsgarantien
der Datenbank entfernt. Die Vorgabeprivilegierung aus dem Init-Skript gibt
jeder von pg_restore neu angelegten Tabelle wieder alle Rechte, und GRANT
kann nur hinzufuegen. Die Anwendungsrolle durfte danach das Audit-Log
aendern, Wiki-Fassungen loeschen, Kiosk-Vorgaenge umschreiben - und nichts
haette darauf hingewiesen. Gefunden haben es vier Datenbanktests
unmittelbar nach der Probe, also genau die Probe, wegen der 1.0.0 sie
verlangt.

Die Pipeline ist geschrieben, aber NICHT erprobt: in Gitea ist kein
act_runner registriert. Das steht so im README und im Devlog, damit sich
niemand auf eine Pruefung verlaesst, die nicht stattfindet.

601 Unit-Tests gruen; Sicherung und Wiederherstellung einmal vollstaendig
durchgefuehrt und die Tests danach erneut gruen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-05 17:16:08 +02:00
co-authored by Claude Opus 5
parent 91742a0dd7
commit 9156dcc144
21 changed files with 2495 additions and 8 deletions
+81 -1
View File
@@ -23,7 +23,87 @@ Die aufgewendete Zeit wandert nach jedem Abschnitt in die Spalte
| Aufräumarbeiten (Issues #10–#12) | 1:20 h | 1 | 04.09.2026 |
| Phase 9 — Kassenverwaltung | 4:10 h | 1 | 04.09.2026 |
| Phase 10 — Mandantenfähigkeit | 4:20 h | 1 | 05.09.2026 |
| **Summe** | **32:50 h** | **13** | |
| Phase 11 — Freigabereife | 2:40 h | 1 | 05.09.2026 |
| **Summe** | **35:30 h** | **14** | |
---
## 2026-09-05 · Phase 11 — Freigabereife
**14:30 – 17:10 · 2:40 h · Version 0.12.0**
### Was entstanden ist
Kein Modul, sondern die drei Software-Voraussetzungen für 1.0.0.
| Bereich | Umfang |
|---|---|
| Auskunft | `lib/dsgvo/auskunft.ts` und `bericht.ts`, `person.auskunft`, Dialog auf der Mitgliederseite |
| Sicherung | `scripts/sicherung.ts`, `wiederherstellen.ts`, `sicherung-zugang.ts`, `sicherung-sperren.ts` |
| Pipeline | `.gitea/workflows/pruefung.yml` mit zwei Aufträgen |
| Tests | 18 neue: 9 gegen die Auskunft, 11 gegen die Sicherung |
### Entscheidungen
**Die Auskunft trennt „über mich" von „von mir".** Was über die Person
gespeichert ist, steht vollständig drin — auch der gemahnte Beitrag und die
nicht bestandene G26. Was die Person *getan* hat, steht als Zahl drin. Die
zwölf Prüfprotokolle, die sie unterschrieben hat, gehören zum Nachweisbestand
der Wehr; vollständig ausgeliefert käme jeder über eine Selbstauskunft an die
Geräteakten, und die Auskunftspflicht wäre eine Hintertür.
**Über jedem Abschnitt steht der Zweck.** Art. 15 Abs. 1 verlangt nicht nur
die Daten, sondern auch Zwecke, Empfänger und den Hinweis auf die weiteren
Rechte. Eine Liste ohne das sieht aus wie eine Auskunft und ist keine — das ist
der Unterschied zwischen einem Datenbankexport und einem Schreiben an einen
Menschen.
**Eine Mutation, keine Abfrage.** Das Erstellen der Auskunft *ist* die
Offenlegung, und die gehört ins Protokoll. Als Abfrage würde sie
zwischengespeichert und mehrfach ausgeführt — sie wäre entweder nicht oder
zwanzigmal vermerkt.
**Sicherung und Wiederherstellung gehören zusammen.** Deshalb sind es zwei
Skripte in einem Zug und nicht eines. Der Probelauf ist die Vorgabe; ohne
`--wirklich` geschieht nichts.
**Eine Liste, zwei Verwendungen.** `sicherung-sperren.ts` treibt sowohl das
Wiederherstellen der Sperren als auch deren Prüfung. Zwei Listen wären zwei
Wahrheiten, und die falsche fiele erst im Notfall auf.
**Die Pipeline baut das eigene Postgres-Image.** Ein Dienst-Container mit
`postgres:17` ließe die Migrationen durchlaufen und scheiterte erst bei der
ersten Umkreissuche — die Pipeline prüfte dann etwas anderes als den Betrieb.
### Wo es gehakt hat
| Problem | Ursache | Lösung |
|---|---|---|
| **Eine Wiederherstellung entfernte alle Unveränderlichkeitsgarantien** | Zuerst `--no-acl` im Dump. Und selbst ohne das Flag greift beim Zurückspielen die Vorgabeprivilegierung aus dem Init-Skript: jede von `pg_restore` neu angelegte Tabelle bekommt alle Rechte, und `GRANT` kann nur hinzufügen | Das Skript setzt die Sperren nach dem Zurückspielen neu und prüft danach nach. Gefunden haben es vier Datenbanktests direkt nach der ersten Rückspielprobe |
| `pg_dump` lehnte die Verbindungszeichenkette ab | Prisma hängt `?schema=public` an — „invalid URI query parameter" | Die URL wird zerlegt, Benutzer und Datenbank gehen als Flags, das Passwort über `PGPASSWORD` |
| Feldnamen im Auskunftssammler stimmten reihenweise nicht | Aus dem Gedächtnis geschrieben statt aus dem Schema gelesen: `alarmierung` statt `alarmiertUm`, `beginn` statt `beginnUm`, `gemeldetVonId` statt `melderId` | Der Typechecker hat sie alle einzeln benannt — zehn Durchgänge, jeder eine Zeile |
| Ein eigener Test war falsch, nicht der Code | `new URL("localhost:5432")` gelingt in Node: „localhost:" gilt als Protokoll | Die Zusicherung prüft jetzt, was wirklich greift — die Protokollprüfung eine Zeile später |
| Ein Vorlagentest fiel im vollen Lauf aus | Er klickte auf „Speichern“, bevor React lief — dann verschickt das Formular sich selbst, und die Fehlerfläche entsteht nie. Unter Last dauert das Hydrieren länger. Dasselbe Muster wie beim Anmeldeskript in Phase 8 | Er wartet jetzt auf einen client-seitig erzeugten Knopf, bevor er klickt |
### Abweichung von der Vorgabe
**Die Pipeline ist nicht erprobt.** Sie ist geschrieben und syntaktisch
geprüft, aber in Gitea war zum Zeitpunkt dieser Phase kein `act_runner`
registriert. Ohne Runner erscheinen die Läufe als „wartend" und laufen nie.
Ob der Ablauf durchläuft, zeigt sich erst, wenn einer eingerichtet ist — das
steht so auch im README, damit niemand sich auf eine Prüfung verlässt, die
nicht stattfindet.
### Nachweise
- `npm run typecheck` — ohne Ausgabe
- `npm run lint` — ohne Befund
- `npm run test` — 599 Tests grün, davon 18 neu
- Auskunft von Hand erzeugt: 13 Abschnitte, 28 Angaben, 58 kB PDF
- **Sicherung und Wiederherstellung vollständig durchgeführt**: ein nach der
Sicherung angelegter Datensatz war danach weg, alle Zahlen stimmten wieder,
und die 599 Tests liefen nach dem Zurückspielen grün — einschließlich derer,
die die Sperren prüfen
---