Phase 11: Freigabereife (#16)
This commit was merged in pull request #16.
This commit is contained in:
+119
-2
@@ -1,6 +1,6 @@
|
||||
# Anleitung
|
||||
|
||||
Bedienung von FLORIAN, Stand Phase 10 (Version 0.11.0). Die Bilder zeigen die
|
||||
Bedienung von FLORIAN, Stand Phase 11 (Version 0.12.0). Die Bilder zeigen die
|
||||
Beispielwehr aus dem Seed und werden mit `npm run screenshots` neu erzeugt.
|
||||
|
||||
---
|
||||
@@ -2253,7 +2253,124 @@ jeweiligen Detailseite sichtbar.
|
||||
|
||||
---
|
||||
|
||||
## 61. Wenn etwas nicht geht
|
||||
## 61. Wenn jemand Auskunft über seine Daten verlangt
|
||||
|
||||
Jede Person darf verlangen zu erfahren, welche Daten über sie verarbeitet
|
||||
werden — Art. 15 DSGVO. Die Anfrage muss **innerhalb eines Monats** beantwortet
|
||||
werden, und sie ist kostenlos.
|
||||
|
||||
### So geht es
|
||||
|
||||
1. **Mitglieder** öffnen, die Person anklicken.
|
||||
2. Rechts oben auf **Datenauskunft**.
|
||||
3. **Auskunft erstellen**.
|
||||
|
||||
Danach stehen drei Dinge bereit:
|
||||
|
||||
| | Wofür |
|
||||
|---|---|
|
||||
| **Die Anzeige** | Was ausgehändigt wird — vor dem Aushändigen |
|
||||
| **PDF** | Das Schreiben an die Person. Ausdrucken oder als Datei geben |
|
||||
| **JSON** | Nur, wenn die Person die Daten maschinenlesbar verlangt (Art. 20) |
|
||||
|
||||
Das Recht dazu heißt `person.export` und liegt bei Kommandant und
|
||||
Administrator.
|
||||
|
||||
### Was drinsteht
|
||||
|
||||
Dreizehn Abschnitte: Stammdaten, Zugang, Rollen, Qualifikationen,
|
||||
arbeitsmedizinische Vorsorge, Belastungsübungen, Einsatz- und
|
||||
Übungsbeteiligung, Anwesenheiten, Fahrten, Beiträge, Benachrichtigungswege,
|
||||
Ausweise.
|
||||
|
||||
Über jedem steht, **wozu** diese Daten vorliegen. Das ist kein Beiwerk: Art. 15
|
||||
verlangt neben den Daten auch die Zwecke und den Hinweis auf die weiteren
|
||||
Rechte. Eine bloße Liste erfüllt die Auskunftspflicht nicht.
|
||||
|
||||
**Auch das Unangenehme steht drin** — ein gemahnter Beitrag, eine nicht
|
||||
bestandene G26. Eine Auskunft, die auswählt, was gut aussieht, ist keine.
|
||||
|
||||
**Leere Abschnitte bleiben stehen.** „Dazu liegen keine Daten vor" ist eine
|
||||
Auskunft.
|
||||
|
||||
**Gesundheitsdaten sind gekennzeichnet.** G26 und Belastungsübungen sind eine
|
||||
besondere Kategorie nach Art. 9 — das steht im Bericht ausdrücklich dabei.
|
||||
|
||||
### Was nicht drinsteht
|
||||
|
||||
Was die Person **getan** hat, erscheint nur als Zahl: „12 durchgeführte
|
||||
Prüfungen", „3 gemeldete Mängel".
|
||||
|
||||
Das ist Absicht. Die Prüfprotokolle selbst gehören zum Nachweisbestand der
|
||||
Feuerwehr und nicht zu den personenbezogenen Daten eines Mitglieds. Würden sie
|
||||
mitgeliefert, käme jeder über eine Selbstauskunft an die kompletten
|
||||
Geräteakten — die Auskunftspflicht wäre eine Hintertür.
|
||||
|
||||
### Der Vorgang wird protokolliert
|
||||
|
||||
Dass eine Auskunft erteilt wurde, steht danach unter **Protokoll**. Das ist
|
||||
richtig so: die Auskunft legt alles offen, was über einen Menschen gespeichert
|
||||
ist, einschließlich seiner Gesundheitsdaten. Wer sie erstellt hat und wann,
|
||||
gehört festgehalten.
|
||||
|
||||
### Wenn die Person in zwei Wehren geführt wird
|
||||
|
||||
Dann gibt es **zwei** Auskünfte, eine je Wehr. Das ist kein Versehen: jede Wehr
|
||||
ist eine eigene Verantwortliche im Sinne der Verordnung und kann nur über die
|
||||
Daten Auskunft geben, die sie selbst führt.
|
||||
|
||||
---
|
||||
|
||||
## 62. Sicherung und Wiederherstellung
|
||||
|
||||
> **Der wichtigste Satz dieses Kapitels:** Eine Sicherung, die nie
|
||||
> zurückgespielt wurde, ist eine Vermutung.
|
||||
|
||||
### Sichern
|
||||
|
||||
```bash
|
||||
npm run sicherung
|
||||
npm run sicherung -- --ziel D:\backups
|
||||
```
|
||||
|
||||
Gesichert wird die Datenbank **und** der Dateispeicher — Prüfprotokolle,
|
||||
Einsatzberichte, Fotos, Rechnungen. Beides aus demselben Moment: eine
|
||||
Datenbank von heute mit Dateien von gestern ergibt Einträge, die auf nichts
|
||||
zeigen.
|
||||
|
||||
Das Ergebnis ist ein Verzeichnis mit Zeitstempel. Es gehört auf ein anderes
|
||||
Gerät — eine Sicherung auf derselben Festplatte hilft gegen einen
|
||||
Festplattenfehler nicht.
|
||||
|
||||
### Zurückspielen
|
||||
|
||||
```bash
|
||||
npm run wiederherstellen -- --quelle sicherungen/2026-09-05T14-16-48
|
||||
```
|
||||
|
||||
So passiert **nichts**. Es wird nur angezeigt, aus welchem Moment die
|
||||
Sicherung stammt und wie groß sie ist. Erst mit `--wirklich` am Ende wird
|
||||
zurückgespielt — und dabei **der gesamte vorhandene Bestand überschrieben**.
|
||||
|
||||
### Einmal im Jahr proben
|
||||
|
||||
Nicht im Notfall zum ersten Mal. Der Ordner kann leer sein, der Auszug
|
||||
abgeschnitten, das Passwort falsch — man erfährt es sonst an dem Tag, an dem
|
||||
man es nicht erfahren will.
|
||||
|
||||
Nach dem Zurückspielen prüft das Skript selbst nach, ob die Schutzsperren der
|
||||
Datenbank wieder stehen. Drei Handgriffe bleiben trotzdem:
|
||||
|
||||
1. **Anmelden** — kommt jemand hinein?
|
||||
2. **Ein Prüfprotokoll öffnen** — ist das PDF da?
|
||||
3. **Die Mitgliederzahl** mit der Erwartung vergleichen.
|
||||
|
||||
Erst danach gilt die Sicherung als geprüft. Das Datum der letzten geglückten
|
||||
Probe gehört ins Sicherungskonzept.
|
||||
|
||||
---
|
||||
|
||||
## 63. Wenn etwas nicht geht
|
||||
|
||||
| Beobachtung | Wahrscheinliche Ursache | Was hilft |
|
||||
|---|---|---|
|
||||
|
||||
@@ -41,7 +41,8 @@ Faktoren, die in die Schätzung eingehen:
|
||||
| 8 | Lokale KI | 9–12 PT | 2,5–3 h | **3:40 h** |
|
||||
| 9 | Kassenverwaltung | 8–11 PT | 2–3 h | **4:10 h** |
|
||||
| 10 | Mandantenfähigkeit | 4–6 PT | 1–1,5 h | **4:20 h** |
|
||||
| | **Summe** | **127–170 PT** | **29–38,5 h** | **32:50 h** |
|
||||
| 11 | Freigabereife | 5–7 PT | 1,5–2 h | **2:40 h** |
|
||||
| | **Summe** | **132–177 PT** | **30,5–40,5 h** | **35:30 h** |
|
||||
|
||||
123–164 Personentage entsprechen etwa **6 bis 8 Monaten Vollzeitarbeit** einer
|
||||
einzelnen Person. Zum Vergleich: eine kommerzielle Feuerwehrverwaltung kostet
|
||||
|
||||
+81
-1
@@ -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
|
||||
|
||||
---
|
||||
|
||||
|
||||
+22
-2
@@ -20,6 +20,7 @@ Phase 7 ████████████████████ fertig
|
||||
Phase 8 ████████████████████ fertig 0.9.0
|
||||
Phase 9 ████████████████████ fertig 0.10.0
|
||||
Phase 10 ████████████████████ fertig 0.11.0
|
||||
Phase 11 ████████████████████ fertig 0.12.0
|
||||
Freigabe ░░░░░░░░░░░░░░░░░░░░ offen 1.0.0
|
||||
```
|
||||
|
||||
@@ -290,15 +291,34 @@ sie schlimmer als keine. Die Aufsicht sieht jede Wehr einzeln.
|
||||
jemand über die Grenze sieht — und die Kreisebene kann hineinschauen, ohne
|
||||
etwas anfassen zu können.
|
||||
|
||||
## Phase 11 — Freigabereife · fertig
|
||||
|
||||
Am 05.09.2026 umgesetzt. Kein Modul, sondern die drei Software-Voraussetzungen
|
||||
für die Freigabe.
|
||||
|
||||
- **Auskunft nach Art. 15 DSGVO.** Das Recht `person.export` stand seit Phase 0
|
||||
im Katalog und war zugewiesen — umgesetzt war nichts. Ohne Auskunftsseite ist
|
||||
ein Löschkonzept nicht abnehmbar.
|
||||
- **Sicherung und Wiederherstellung** mit einer durchgeführten Rückspielprobe.
|
||||
- **Pipeline** in Gitea Actions: typecheck, lint, Migrationen, Seed und Tests.
|
||||
|
||||
Die Rückspielprobe hat sich sofort bezahlt gemacht: der erste Versuch lief
|
||||
sauber durch und hatte dabei sämtliche Unveränderlichkeitsgarantien der
|
||||
Datenbank entfernt. Gefunden haben es die Datenbanktests unmittelbar danach —
|
||||
also genau die Probe, wegen der 1.0.0 sie verlangt.
|
||||
|
||||
**Die Wehr kann jetzt:** eine Selbstauskunft erteilen, ihren Bestand sichern
|
||||
und ihn nachweislich zurückholen.
|
||||
|
||||
## 1.0.0 — Freigabe
|
||||
|
||||
Kein neues Modul, sondern eine Entscheidung: die Wehr setzt FLORIAN im
|
||||
Echtbetrieb ein. Voraussetzungen:
|
||||
|
||||
- Datenübernahme aus der bisherigen Verwaltung abgeschlossen und abgeglichen
|
||||
- Sicherungskonzept steht und ist einmal wiederhergestellt worden
|
||||
- ~~Sicherungskonzept steht und ist einmal wiederhergestellt worden~~ — mit Phase 11 erledigt
|
||||
- Schulung von Kommandant, Gerätewart und Atemschutzgerätewart erfolgt
|
||||
- Löschkonzept nach DSGVO abgenommen
|
||||
- Löschkonzept nach DSGVO abgenommen (die Auskunftsseite dazu gibt es seit Phase 11)
|
||||
- Der Hinweis zur analogen Atemschutzüberwachung wird bewusst und
|
||||
dokumentiert abgeschaltet — oder bewusst stehen gelassen
|
||||
|
||||
|
||||
Reference in New Issue
Block a user