Phase 7: Benachrichtigungen und Termine

Terminkalender mit Serienterminen, Selbstanmeldung, Warteliste und
Anwesenheitsliste. Vier Zustellwege hinter Schnittstellen: echtes SMTP,
ntfy (selbst gehostet), Telegram und Web-Push. Kalenderabonnement als
ICS-Feed, digitaler Dienstausweis mit signiertem QR und Pruefseite.

Niemand wird ungefragt benachrichtigt: ein neuer Zustellweg hat eine leere
Ereignisliste, und der Seed legt bewusst keine an. Was das Netz der Wehr
verlaesst, bekommt nur die Kurzfassung ohne Namen und Details.

Kein CalDAV (Lesen genuegt, ICS kann jeder Kalender) und kein WhatsApp
(Verarbeitung ueber Meta, Kosten je Konversation, Telefonbuchabgleich) --
beides im README begruendet.

56 neue Unit-Tests, 17 neue E2E-Tests, Version 0.8.0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Florian Wilde
2026-09-04 08:39:38 +02:00
co-authored by Claude Opus 5
parent c779266450
commit 0b8874da26
134 changed files with 9340 additions and 123 deletions
+250 -11
View File
@@ -1,10 +1,10 @@
# Anleitung
Bedienung von FLORIAN, Stand Phase 6 (Version 0.7.0). Die Bilder zeigen die
Bedienung von FLORIAN, Stand Phase 7 (Version 0.8.0). Die Bilder zeigen die
Beispielwehr aus dem Seed und werden mit `npm run screenshots` neu erzeugt.
> Benachrichtigungen, lokale KI und die Kassenverwaltung kommen in den
> folgenden Phasen dazu. Siehe [ROADMAP.md](ROADMAP.md).
> Die lokale KI und die Kassenverwaltung kommen in den folgenden Phasen dazu.
> Siehe [ROADMAP.md](ROADMAP.md).
---
@@ -1279,7 +1279,230 @@ GEOCODING_LAENDER=de,at,ch
Ohne Konfiguration bleibt die Suche leer. Koordinaten lassen sich dann von Hand
eintragen oder weglassen.
## 39. Rollen und was sie dürfen
## 39. Der Terminkalender
![Termine](screenshots/37-termine-light.png)
Unter **Termine** steht, was ansteht: Dienste, Übungen, Lehrgänge,
Arbeitsdienste, Veranstaltungen, Sitzungen. Die Liste blickt nach vorn — das
ist, was fast immer gemeint ist.
An jeder Zeile stehen zwei Knöpfe: **Zusagen** und **Absagen**. Mehr braucht
das normale Mitglied nicht.
### Rückmeldung ist die Ausnahme
Beim Übungsabend meldet sich niemand an, man kommt oder man kommt nicht. Erst
beim Lehrgang mit zwölf Plätzen und beim Ausflug mit Busbestellung wird beim
Anlegen **Rückmeldung verlangen** angekreuzt.
Wer dann Plätze begrenzt, bekommt automatisch eine **Warteliste**: Zusagen über
die Platzzahl hinaus landen dort, nummeriert in der Reihenfolge der Anmeldung.
Sagt jemand ab, rückt der Erste von selbst nach und erfährt es. Niemand muss
eine Liste führen.
### Serientermine
Beim Anlegen unter **Wiederholung** wählen: wöchentlich, alle zwei Wochen,
monatlich, jährlich. Dazu ein Datum, bis zu dem die Serie läuft.
Darunter steht dann in einem Kasten, **wie viele Termine daraus werden** —
lesen Sie das, bevor Sie auf „Anlegen" drücken. Wöchentlich über ein Jahr sind
52 Einträge.
FLORIAN legt jeden Abend als eigenen Termin an, nicht als Regel. Das ist
Absicht: so lässt sich der Abend im August absagen, der im Dezember eine Woche
vorziehen, und für jeden gibt es eine eigene Teilnehmer- und Anwesenheitsliste.
Bei „monatlich" bleibt der Tag im Monat gleich — der 31. rutscht im Februar auf
den 28., nicht in den März.
### Absagen statt löschen
Ein Termin, zu dem schon jemand zugesagt hat, lässt sich nicht löschen. Er wird
**abgesagt**, mit Grund. Er bleibt dann durchgestrichen im Kalender stehen, der
Grund steht daneben, und wer zugesagt hatte, bekommt eine Nachricht — nicht die
ganze Wehr.
Gehört der Termin zu einer Serie, können Sie im selben Schritt **alle folgenden
Termine** absagen. Vergangene bleiben unberührt; man sagt nicht rückwirkend ab,
was schon stattgefunden hat.
### Anwesenheitsliste
Auf jedem Termin oben rechts. Sie zeigt **alle aktiven Mitglieder**, nicht nur
die Angemeldeten — auf einem Blatt zum Abhaken muss jeder stehen. Daneben, was
jemand gemeldet hatte.
Wer das Recht dazu hat, hakt gleich hier ab; sonst führt **Drucken** zu einem
Blatt mit leeren Kästchen.
> Zusage und Anwesenheit sind zwei verschiedene Dinge. Wer zugesagt hat und
> nicht kam, steht genau so in der Liste — das ist der Zweck der Trennung.
---
## 40. Benachrichtigungen einrichten
![Benachrichtigungen](screenshots/38-benachrichtigungen-light.png)
> **Niemand wird ungefragt benachrichtigt.** Wer hier nichts einträgt, bekommt
> nichts. Es gibt keine Voreinstellung, die alle anmeldet.
Unter **Benachrichtigungen** richten Sie Ihre eigenen Wege ein — Ihre, nicht
die von jemand anderem. Auch der Kommandant kann niemanden für Sie anmelden.
### Die vier Wege
| Weg | Was Sie brauchen | Bleibt im Haus? |
|---|---|---|
| **E-Mail** | nichts, es gilt Ihre hinterlegte Adresse | ja |
| **ntfy** | die ntfy-App und ein Thema | ja, wenn der Server der Wehr gehört |
| **Telegram** | Ihre Chat-Kennung vom Bot | **nein** |
| **Browser-Push** | nur die Erlaubnis des Browsers | **nein** |
Neben den Wegen, die das Netz der Wehr verlassen, steht ein Warnhinweis. Dorthin
gehen nur **Kurzfassungen**: „3 Prüfungen fällig", nicht welche. Wer es genau
wissen will, bekommt es per E-Mail oder schaut in FLORIAN nach.
### ntfy einrichten
Der bequemste Weg, wenn die Wehr einen eigenen ntfy betreibt:
1. Die App „ntfy" aus dem Store laden.
2. In der App den Server eintragen, der auf dieser Seite steht.
3. In FLORIAN **ntfy** wählen; das vorgeschlagene Thema übernehmen.
4. In der App dasselbe Thema abonnieren.
> **Das Thema ist Ihr Schlüssel.** Wer den Namen kennt, liest mit. Deshalb
> schlägt FLORIAN einen zufälligen vor — nehmen Sie nicht „florian-mueller".
### Browser-Push
**Einrichten** drücken; der Browser fragt nach Erlaubnis. Das Abo gilt für
**diesen einen Browser auf diesem einen Gerät** — auf dem Diensthandy und am
Rechner im Büro also zweimal einrichten.
Auf dem iPhone funktioniert es erst, wenn FLORIAN über „Zum Home-Bildschirm"
abgelegt wurde. Vorher bietet der Browser es gar nicht an.
### Wofür?
Unter jedem Weg stehen die sechs Anlässe zum Ankreuzen:
| Anlass | Wann er kommt |
|---|---|
| Prüfung fällig | im morgendlichen Lauf |
| Mangel gemeldet | sofort |
| Qualifikation läuft ab | 90, 30 und 7 Tage vorher |
| Neuer Termin | beim Anlegen |
| Erinnerung an einen Termin | 7 Tage und 1 Tag vorher |
| Einsatzbericht freigegeben | bei der Freigabe |
### Der Probeknopf
**Drücken Sie ihn.** Er steht direkt an jedem Weg und schickt eine
Probenachricht durch dieselbe Maschinerie wie alles andere. Ohne ihn merken Sie
einen Tippfehler im Thema erst in drei Wochen — dann, wenn die Nachricht
wichtig gewesen wäre.
Sie geht mit dem nächsten Lauf raus, üblicherweise binnen einer Minute.
### Was ankam
Ganz unten steht, was FLORIAN Ihnen zuletzt geschickt hat und ob es angekommen
ist. Steht dort mehrfach **Fehlgeschlagen**, ist der Weg kaputt — der Grund
steht daneben.
---
## 41. Den Kalender aufs Handy holen
Auf derselben Seite unter **Kalender abonnieren**. Namen für das Gerät eingeben,
**Adresse erzeugen** — und die Adresse gleich übernehmen.
> **Sie wird genau einmal angezeigt.** FLORIAN speichert nur ihre Prüfsumme.
> Wer sie verliert, erzeugt eine neue und widerruft die alte.
Die Adresse dann eintragen:
| Gerät | Weg |
|---|---|
| **iPhone/iPad** | Einstellungen → Kalender → Accounts → Account hinzufügen → Andere → Kalenderabo hinzufügen |
| **Android** | in Google Kalender am Rechner: Andere Kalender → Per URL |
| **Thunderbird** | Neuer Kalender → Im Netzwerk → iCalendar (ICS) |
| **Outlook** | Kalender hinzufügen → Aus dem Internet abonnieren |
Danach stehen die Termine der Wehr neben allem anderen im Kalender. Neue
Termine und Absagen kommen von selbst nach; die meisten Programme fragen
stündlich nach.
**Nur eigene Termine** angekreuzt heißt: nur die, zu denen Sie sich
zurückgemeldet haben.
> **Die Adresse ist ein Schlüssel.** Wer sie hat, sieht die Termine der Wehr —
> ohne Anmeldung. Geben Sie sie nicht weiter; bei einem verlorenen Handy
> genügt ein Klick auf **Widerrufen**.
Ausgeliefert werden ausschließlich Termine — keine Teilnehmerlisten, keine
Mängel, keine Einsätze. Wer aus der Wehr austritt, verliert das Abo.
---
## 42. Textvorlagen und der Dienstausweis
### Textvorlagen
![Textvorlagen](screenshots/39-vorlagen-light.png)
Für Kommandant, Schriftführer und Administrator: unter **Benachrichtigungen →
Vorlagen bearbeiten** steht, was in den Nachrichten steht. Was hier geändert
wird, gilt für **alle**.
Links der Text, rechts die Vorschau mit erfundenen Beispielwerten. Die
**Platzhalter** darunter sind anklickbar und werden beim Versand ersetzt:
`{titel}` wird zu „Übungsabend", `{datum}` zum Datum.
Ein Platzhalter, den es für diesen Anlass nicht gibt, wird beim Speichern
abgewiesen — mit der Liste der erlaubten daneben. Und einer, der stehen bleibt,
bleibt auch in der fertigen Nachricht sichtbar: eine Lücke, die niemand
bemerkt, wäre schlimmer.
Ohne eigene Vorlage greift der eingebaute Text. **Auf Standard zurücksetzen**
stellt ihn wieder her.
> Bei Telegram und Browser-Push steht ein Warnhinweis über dem Feld. Was Sie
> dort hineinschreiben, läuft über einen fremden Server — also keine Namen,
> keine Adressen, keine Einsatzdetails.
### Der digitale Dienstausweis
![Dienstausweis](screenshots/40-dienstausweis-light.png)
Unter **Dienstausweis**: ein QR-Code mit Ihrem Namen, Ihrer Wehr, Ihrer
Funktion und Ihren gültigen Qualifikationen. Zum Vorzeigen an der Absperrung,
beim Lehrgang oder bei einer Kontrolle.
Wer ihn scannt, landet auf einer Prüfseite und sieht genau das — **ohne sich
anzumelden**. Denn wer prüft, hat keinen Zugang zu FLORIAN.
Drei Dinge sollten Sie darüber wissen:
- **Der Code gilt fünf Minuten.** Danach zeigt die Seite ihn selbst neu an. Ein
abfotografierter Code nützt nichts.
- **Er öffnet nichts.** Die Prüfseite zeigt an, sie lässt nicht hinein.
- **Es steht nicht mehr darauf als auf einem Ausweis aus Papier.** Keine
Anschrift, kein Geburtsdatum, keine Telefonnummer.
Die Prüfseite nennt außerdem, wann der Code erzeugt wurde. Das ist der Punkt,
auf den ein Prüfender schauen sollte: „vor zwei Minuten" ist ein Ausweis,
„gültig" allein wäre wertlos.
Wer aus der Wehr ausgetreten ist, bekommt dort **Kein aktives Mitglied** — auch
wenn sein Code technisch noch stimmt.
---
## 43. Rollen und was sie dürfen
Neun Rollen, jede mit einem festen Satz Rechte. Die Zuordnung steht zentral in
`src/lib/authz.ts` und wird beim Seed in die Datenbank gespiegelt — eine Wehr
@@ -1292,9 +1515,9 @@ kann sie also nachträglich zuschneiden, ohne dass jemand Code ändert.
| **Gerätewart** | Fahrzeuge und Geräte anlegen, ändern, aussondern; Prüfungen planen und durchführen |
| **Atemschutzgerätewart** | zusätzlich Atemschutzgeräte, Träger und die Überwachung nach FwDV 7 |
| **Kassier** | Buchungen und Kassenabschluss (Modul noch nicht geplant, siehe Roadmap) |
| **Schriftführer** | Mitglieder pflegen, Einsätze und Berichte erfassen |
| **Ausbilder** | Übungen planen, Teilnahme und Qualifikationen erfassen |
| **Mitglied** | eigene Daten, Listen lesen |
| **Schriftführer** | Mitglieder pflegen, Einsätze und Berichte erfassen, den Terminkalender führen |
| **Ausbilder** | Übungen und Übungstermine planen, Teilnahme, Anwesenheit und Qualifikationen erfassen |
| **Mitglied** | eigene Daten, Listen lesen, Termine sehen und sich zurückmelden, eigene Benachrichtigungswege einrichten |
| **Terminal** | nur anmelden und erfassen — nie verwalten |
Zwei Dinge sind bewusst so gebaut:
@@ -1306,9 +1529,14 @@ Trennung nach Verantwortung, nicht nach Bequemlichkeit.
zusätzlich mit PIN oder Karte an und handelt dann unter seiner eigenen Person.
Das Terminal selbst ist nur die Tür.
**Seine Benachrichtigungswege richtet jeder selbst ein.** Das ist ein
Grundrecht jedes Mitglieds und keine Sache des Kommandanten — es gibt bewusst
keinen Weg, jemand anderem einen Zustellweg einzutragen. Was für alle gilt,
sind nur die Textvorlagen, und die hängen an einem eigenen Recht.
---
## 40. Anmeldung über authentik einrichten
## 44. Anmeldung über authentik einrichten
authentik läuft **getrennt** von FLORIAN und ist nicht Teil dieses Stacks.
@@ -1361,7 +1589,7 @@ ganze Wehr aus.
---
## 41. PIN und Ausweiskarte verwalten
## 45. PIN und Ausweiskarte verwalten
Wie sich am Terminal angemeldet wird, steht in Kapitel 24. Hier geht es darum,
was dahinter liegt.
@@ -1384,7 +1612,7 @@ Huber), PIN `471203`.
---
## 42. Was protokolliert wird
## 46. Was protokolliert wird
Jede schreibende Änderung erzeugt einen Eintrag mit Zeitpunkt, Person,
betroffenem Datensatz und den geänderten Feldern im Vorher-Nachher-Vergleich.
@@ -1409,7 +1637,7 @@ jeweiligen Detailseite sichtbar.
---
## 43. Wenn etwas nicht geht
## 47. Wenn etwas nicht geht
| Beobachtung | Wahrscheinliche Ursache | Was hilft |
|---|---|---|
@@ -1438,6 +1666,17 @@ jeweiligen Detailseite sichtbar.
| Nach dem Import steht überall „ungeprüft" | Die Quelle hat keine Statusspalte | Absicht: ohne Angabe wird nicht „einsatzbereit" behauptet. Zustand nachpflegen |
| Die Lagekarte gleicht nicht ab | Der Ereignisstrom ist unterbrochen | Steht oben in der Lagekarte. Bei einem Reverse Proxy `X-Accel-Buffering: no` durchreichen |
| Die Förderstrecke braucht unerwartet viele Pumpen | Fördermenge zu hoch für den Durchmesser | Der Verlust steigt im Quadrat: 800 statt 400 l/min kostet die vierfache Reibung. Größeren Schlauch wählen oder weniger fördern |
| Es kommt keine Benachrichtigung an | Kein Zustellweg eingerichtet, oder kein Anlass angekreuzt | Unter **Benachrichtigungen** einen Weg einrichten und ankreuzen, wofür. Ohne beides kommt absichtlich nichts |
| Die Probenachricht bleibt aus | Der Kanal ist auf dem Server nicht eingerichtet | In der Auswahl steht „(nicht eingerichtet)". `MAIL_ENABLED`, `NTFY_ENABLED`, `TELEGRAM_ENABLED` oder `WEBPUSH_ENABLED` setzen |
| Im Verlauf steht mehrfach „Fehlgeschlagen" | Der Weg ist kaputt — der Grund steht daneben | Bei ntfy meist ein Tippfehler im Thema, bei Telegram eine falsche Chat-Kennung |
| Browser-Push lässt sich nicht einrichten | Keine VAPID-Schlüssel auf dem Server | `npm run vapid` und die Ausgabe in die `.env` übernehmen |
| Push kam bisher an, jetzt nicht mehr | Der öffentliche VAPID-Schlüssel wurde gewechselt | Alle Abos sind damit wertlos. Jeder muss Push neu erlauben — deshalb gehören die Schlüssel ins Backup |
| Auf dem iPhone gibt es keinen Push-Knopf | Web-Push geht dort nur als abgelegte App | Über „Teilen → Zum Home-Bildschirm" ablegen, dann erneut versuchen |
| Der Kalender im Handy aktualisiert sich nicht | Das Programm fragt nur stündlich nach | Abwarten oder im Kalenderprogramm „Aktualisieren" auslösen |
| Der Kalender ist plötzlich leer | Der Zugang wurde widerrufen, oder die Person ist ausgetreten | Unter **Benachrichtigungen** eine neue Adresse erzeugen |
| Eine Vorlage lässt sich nicht speichern | Ein Platzhalter gehört nicht zu diesem Anlass | Die Meldung nennt ihn und listet die erlaubten auf |
| Ein Termin lässt sich nicht löschen | Es liegen schon Rückmeldungen vor | Absagen statt löschen — dann sehen die Angemeldeten den Grund |
| Die Zusage wurde zur Warteliste | Die Plätze sind belegt | Sagt jemand ab, rücken Sie von selbst nach und werden benachrichtigt |
Zustand aller Randsysteme auf einen Blick: