docs: Einrichtung, Abläufe und Ausbauideen dokumentieren

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Paul SchoeneckandCopilot committed 2026-11-03 08:01:25 +01:00
1 parent ef52cc1218
commit 4df14584f2
2 files changed
+145

No files matched your search

+116
View File
@@ -0,0 +1,116 @@
# KIBU – Schritte 1 bis 3
Lokale Web-App für die Kinderbetreuung mit Next.js, TypeScript und einer echten PostgreSQL-Datenbank. Keine externen Dienste, Fonts oder Bild-Uploads. Kinderkarten verwenden Initialen.
## Starten
Voraussetzungen: Node.js 20.9 oder neuer, npm und Docker Desktop mit lokalem Linux-Container-Kontext.
```powershell
npm install
npm run configure
docker compose up -d --wait
npm run db:setup
npm run dev
```
App: <http://127.0.0.1:3000>. `db:setup` erstellt Tabellen und beim ersten Lauf einen Zugang `admin@kibu.local`. Das zufällige Passwort erscheint einmal im Terminal. Nach der Anmeldung über den Betreuungsnamen bzw. das Konto-Symbol ändern.
Alternativ vor dem ersten `db:setup` in `.env` eine `BOOTSTRAP_EMAIL` und ein `BOOTSTRAP_PASSWORD` mit mindestens 12 Zeichen setzen. Wiederholtes Setup verändert bestehende Konten nicht. `.env` nicht einchecken. Für diese lokale Testinstanz kann das vorhandene Passwort beibehalten werden.
Bei vorhandener Installation: App beenden, `npm run db:setup` und `npm run build` ausführen und mit `npm start` neu starten. `db:setup` wendet ausstehende SQL-Migrationen aus `scripts/migrations` einmalig, geordnet und transaktional an. Bestehende Konten, Kinder und Zeiten bleiben erhalten.
## Enthalten
- Betreuungs-Login mit gesalzenen scrypt-Passworthashes, gehashten Sitzungstokens, HTTP-only-Cookie, 12 Stunden Sitzungsdauer und Login-Limit (10 Versuche pro E-Mail/15 Minuten).
- Kinder anlegen/bearbeiten: Vorname, Nachname, Klasse/Gruppe und Wochenzeiten mit Abholslots von Montag bis Sonntag; individuelle Abholzeit als ausdrückliche Ausnahme.
- Für jedes Datum: Wochenplan übernehmen, andere Zeiten setzen oder für den Tag abmelden. Eine Abmeldung im Plan ist unabhängig von der Krankmeldung.
- Suche, Klassenfilter, Namens-/Abholzeitsortierung und Statusfilter.
- Tagesstatus: erwartet → angekommen → abgeholt; erwartet → krank. Krankmeldungen können am selben Tag aufgehoben werden. Auch außerplanmäßig ankommende Kinder können eingecheckt werden.
- Tatsächliche Ankunft und Abholung bleiben je Kalendertag in PostgreSQL gespeichert. Außerplanmäßige Abholung durch Eltern wird gesondert dokumentiert.
- „Jetzt abholen“ zeigt **anwesende** Kinder mit beginnendem Abholslot bis einschließlich der nächsten 15 Minuten, laufendem Fenster sowie überfälliger Abholung. Ein Slot wird erst nach seinem Ende überfällig (15:00–15:15 ist um 15:15 noch fällig, ab 15:16 überfällig). Bei individueller Zeit gilt diese als Beginn und Ende. Bereits abgeholte oder kranke Kinder erscheinen dort nicht.
- Tageswechsel und Zeiten verwenden `APP_TIMEZONE` (Standard `Europe/Berlin`), nicht die Browserzeitzone. Automatische Aktualisierung alle 30 Sekunden und beim Zurückkehren in den Tab.
- Andere Tage können geplant und angesehen werden. Schnelle Anwesenheitsaktionen im Dashboard gelten ausschließlich für heute.
### Abholslots und Filter
- Zentrale Verwaltung unter „Abholslots“ (`/slots`), nur für angemeldete Betreuung. Anfangs vier unbegrenzte Fenster: **14:00–14:15, 15:00–15:15, 16:00–16:15, 17:00–17:15**.
- Neue Kinder erhalten standardmäßig den aktiven 16-Uhr-Slot (oder den ersten aktiven Slot). Wochen- und Tagespläne bieten zuerst Slots an; „Individuelle Zeit (Ausnahme)“ blendet die freie Uhrzeit ein. Ohne aktive Slots bleibt die individuelle Zeit verfügbar.
- Zusätzliche Zeitfenster können angelegt, vorhandene aktiviert/deaktiviert werden. Zeitfenster selbst werden nicht nachträglich umgeschrieben: für andere Zeiten einen neuen Slot anlegen und den alten deaktivieren. So ändern sich bestehende Pläne nicht unbemerkt.
- Ein ausgewähltes Fenster wird mit Start, Ende und Slot-Referenz im Plan gespeichert. Deaktivierte Slots bleiben in vorhandenen Plänen sichtbar und bei deren Bearbeitung auswählbar, werden für neue Zuordnungen in den Formularen nicht angeboten. Wochenpläne/Tagespläne mit vorher exakt passender Abholzeit werden bei der Migration auf den jeweiligen Standardslot umgestellt; andere freie Zeiten bleiben unverändert.
- Dashboard mit Slot-Übersicht, Zahl aktuell anwesender Kinder je Slot und eigenem Slotfilter. Slot-Buttons filtern alle zugeordneten Kinder (einschließlich bereits abgeholter), nicht nur anwesende.
- Klick auf Statistik-, Slot- oder Abholhinweis-Buttons setzt widersprechende Such-/Klassen-/Slotfilter zurück und scrollt zur neu gefilterten Kinderliste; Fokus folgt der Liste. Wiederholte Klicks scrollen erneut. Bei reduzierter Bewegung erfolgt der Sprung ohne Animation.
### Aufnahme und Warteliste (Schritt 3)
Betreuungsbereich: `/admissions` über „Aufnahme & Warteliste“. Eltern-Einstieg: `/join`, alternativ der direkte Einladungslink.
1. **Aufnahmerunde erstellen:** Name und Anmeldefrist (einschließlich, in `APP_TIMEZONE`) festlegen. Der 48-stellige zufällige Einladungscode wird nur einmal angezeigt, in der Datenbank nur als SHA-256-Hash gespeichert. Einladungslink kopieren und selbst mit den Eltern teilen. Verlorene Codes können für offene Runden ersetzt werden; der alte Link wird sofort ungültig.
2. **Eltern melden ein Kind an:** Ohne Betreuungslogin, nur mit gültigem Code. Vor-/Nachname, Klasse zum Betreuungsstart, Kontaktname, E-Mail, optionale organisatorische Hinweise und ausdrückliche Verarbeitungsbestätigung. Keine anderen Anmeldungen, Profile oder Auslosungsergebnisse sind öffentlich sichtbar. Es gibt keinen automatischen E-Mail-Versand, kein Elternkonto und noch keine spätere Selbstverwaltung.
3. **Anmeldung schließen:** Manuell vor der Auslosung. Abgelaufene Codes nehmen auch bei noch offen markierter Runde keine Anmeldungen mehr an. Geschlossene Runden können nicht wieder geöffnet werden.
4. **Einmalig X Plätze auslosen:** X muss zwischen 1 und Anzahl der Anmeldungen liegen (maximal 10.000). Jede Anmeldung hat die gleiche Chance; `crypto.randomInt` mit partieller Fisher-Yates-Auswahl ohne Zurücklegen. Ausgewählte Kinder sind zunächst „Ausgewählt“, die übrigen „Warteliste“. Ziehungszeit, Zugang und Platzzahl werden gespeichert. Eine zweite Auslosung derselben Runde ist ausgeschlossen.
5. **Aufnahme einzeln bestätigen:** Erst dann wird ein Kind im Dashboard angelegt und die Anmeldung mit dem Profil verknüpft. Wiederholte Bestätigung erzeugt kein zweites Kind. Wochenplan und geprüfte Abholberechtigungen im Profil ergänzen; Kontaktangaben aus der Anmeldung bedeuten nicht automatisch Abholberechtigung. Vor Übernahme bitte auf bereits separat angelegte Kinder prüfen.
Anmeldung, Schließen, Auslosung und Bestätigung verwenden gemeinsame Datenbanksperren je Runde und Transaktionen. Damit rutscht keine neue Anmeldung in eine bereits geschlossene/ausgeloste Runde und doppelte Auslosungen/Übernahmen werden verhindert. Listen sind nach Runde getrennt und mit 25 Anmeldungen pro Seite paginiert.
Duplikate derselben Runde mit gleichem Kindernamen und gleicher Kontakt-E-Mail (unabhängig von Groß-/Kleinschreibung) werden abgelehnt. Pro Einladung und E-Mail sind maximal zehn Anmeldeversuche pro Stunde möglich. Es gibt noch keine E-Mail-/Identitätsprüfung: mehrfache Anmeldungen mit anderen Angaben lassen sich in dieser Testversion nicht zuverlässig erkennen. Vor echtem Betrieb sind Identitätsprüfung und belastbare Missbrauchsbegrenzung erforderlich. Ein Code ist ein vertraulich zu teilender Zugang zur Anmeldung, keine Platzzusage. Die App bleibt lokal gebunden; Links sind ohne separate Bereitstellung nicht von anderen Geräten erreichbar.
Nachrücken, Zusagen-Fristen, Rückzug/Löschen und Benachrichtigungsversand sind noch nicht implementiert; dazu stehen weitere Ideen unten in `KIBU.md`. Wartelistenanmeldungen sind keine Kinderprofile und bleiben vom Anwesenheits-Audit getrennt.
### Kinderprofile (Schritt 2)
- Über Namen, Initialen oder „Profil, Abholberechtigte & Verlauf“ auf jeder Karte erreichbar. Profile sind nur nach Anmeldung zugänglich.
- Tagesdetails und Anwesenheitsverlauf mit tatsächlichen Ankunfts-/Abholzeiten, Art des Verlassens und seitenweisem Verlauf (25 Datensätze). Die historischen tatsächlichen Zeiten werden durch Änderungen am heutigen Wochenplan nicht verändert. Historische Planansichten verwenden den aktuellen Wochenplan plus Tagesabweichungen, nicht einen versionierten Planstand.
- Vergessene Ankunft/Abholung nachtragen, Zeiten korrigieren, Krankmeldungen ändern oder falsche Einträge zurücksetzen. Datum in den Tagesdetails auswählen, dann „Anwesenheit korrigieren/nachtragen“. Ein Grund (5–500 Zeichen) ist Pflicht.
- Korrekturen sind nur für heute oder vergangene Tage möglich. Tatsächliche Zeiten dürfen nicht in der Zukunft liegen; Abholung nicht vor Ankunft. Alle Zeiten gelten in `APP_TIMEZONE`. Nicht existente bzw. mehrdeutige Zeiten während einer Zeitumstellung werden ausdrücklich abgelehnt.
- Versionsprüfung und gemeinsame Kind-Sperren verhindern, dass eine Korrektur neuere Anwesenheitsänderungen unbemerkt überschreibt. In diesem Fall Profil neu laden und aktuelle Werte prüfen.
- Abholpersonen mit Name, Beziehung, optional Telefon/Hinweisen und expliziter Berechtigung. Berechtigung entziehen statt Historie löschen. Die Elternabholungs-Bestätigung im Dashboard zeigt aktuell erlaubte Personen; fehlende Angaben bedeuten keine bestätigte Berechtigung.
- Pro Wochentag eine ausdrückliche Erlaubnis zum Alleingehen ab einer Uhrzeit. Ohne Regel kein Alleingang. Das Dashboard zeigt die Regel und erlaubt „Alleingang bestätigen“ nur für ein anwesendes Kind am erlaubten Tag ab der erlaubten Uhrzeit; die Regel wird auch serverseitig geprüft. Es erfolgt niemals ein automatischer Checkout. Geplante Abholzeit und früheste Alleingehzeit bleiben getrennte Angaben.
- Historische Korrekturen dokumentieren tatsächliche Ereignisse: Ein nachgetragener Alleingang wird nicht anhand der heutigen Erlaubnis blockiert. Der Grund und die Betreuungsperson bleiben sichtbar.
- Klassenwechsel über „Stammdaten & Wochenplan“: Klasse bearbeiten, ohne Kind neu anzulegen. Identität, Verlauf, Abholpersonen und Regeln bleiben erhalten; die Änderung erscheint im Audit-Log.
### Audit-Log
PostgreSQL-Trigger protokollieren Stammdaten, Wochenpläne, Tagesabweichungen, Anwesenheiten, Abholpersonen und Alleingehregeln in derselben Transaktion wie die Änderung. Pro Eintrag: alter/neuer Zustand, Betreuungstag soweit vorhanden, Änderungszeit, ausführender Zugang und Grund. Reine Änderungen ohne andere Werte erzeugen keinen zusätzlichen Log-Eintrag.
Das Profil zeigt Änderungen verständlich aufgeschlüsselt und seitenweise (25 Einträge), neueste zuerst. Auch Zurücksetzen/Entziehen ist nachvollziehbar. Bestehende Anwesenheiten vor Einführung werden einmalig als Bestandsübernahme markiert; frühere, damals nicht erfasste Änderungen werden nicht erfunden.
UPDATE, DELETE und TRUNCATE des Logs werden durch Datenbank-Trigger abgelehnt. Direkte Datenbankänderungen ohne Anwendungskontext werden als „Datenbank / Einrichtung“ gekennzeichnet. Das ist ein nachvollziehbares Anwendungsprotokoll, kein Schutz gegen privilegierte Datenbankadministratoren, die Trigger deaktivieren könnten. Der derzeit gemeinsam genutzte Testzugang identifiziert den Zugang, nicht einzelne reale Betreuungspersonen.
### Fiktive Testdaten
```powershell
npm run db:seed
```
Erstellt zwölf **rein fiktive** Kinder mit verschiedenen Klassen, Wochenzeiten, heutigen Status/Abholfenstern, Abholberechtigten, Alleingehregeln und zwei Wochen Anwesenheitsverlauf. Mila Sonnental hat im letzten Betreuungstag eine vergessene Abholung zum Korrigieren. Namen und Kontakte sind ausschließlich Testdaten; Telefonnummern werden nicht erfunden.
Das Skript verwendet feste Demo-IDs und überspringt vorhandene Kinder vollständig. Erneutes Ausführen überschreibt weder manuelle Tests noch Zugangsdaten und aktualisiert bewusst auch nicht die täglich wechselnden Demostatus. Die initialen heutigen Zeiten beziehen sich auf den Zeitpunkt des ersten Seeds; zum Testen später bei Bedarf Tagespläne und Anwesenheiten anpassen.
## Datenbank
PostgreSQL 17 läuft unter dem Compose-Projektnamen `kibu` und ist nur an `127.0.0.1:55432` gebunden. `npm run configure` erzeugt ein zufälliges Datenbankpasswort in der lokalen `.env`; vorhandene Konfiguration wird nicht überschrieben.
```powershell
docker compose ps
docker compose stop
docker compose up -d --wait
```
Das benannte Volume `kibu_kibu_postgres` erhält die Daten bei Neustarts. **Nicht** `docker compose down -v` verwenden, wenn Daten erhalten bleiben sollen. Regelmäßige verschlüsselte Backups sind vor realem Einsatz erforderlich.
## Prüfen
```powershell
npm test
npm run test:db
npm run build
```
`test:db` benötigt eine eingerichtete Datenbank. Eigene Kinder-/Audit-Testdatensätze werden innerhalb von Transaktionen geprüft und vollständig zurückgerollt. Der Paralleltest verwendet eine eigene kurzlebige Aufnahmerunde und entfernt diese samt Anmeldungen im Anschluss. Bestehende Demodaten bleiben erhalten. Geprüft werden unter anderem Korrekturen, Versionskonflikte, Vorher-/Nachher-Protokollierung, unveränderliches Audit-Log, Berechtigungen, Slots, Anmeldungen, konkurrierende Auslosungen und einmalige Übernahme. Unit-Tests prüfen exakte Fenstergrenzen und die gleichberechtigten Auswahlpfade kleiner Ziehungen. `npm run typecheck` prüft TypeScript ohne Build.
## Betriebsgrenze
Diese Version ist für den lokalen Testbetrieb gedacht, nicht zur unveränderten Veröffentlichung im Internet. Entwicklungs- und Produktionsserver binden standardmäßig nur an `127.0.0.1`. Für einen echten Einsatz mit Kinderdaten sind unter anderem HTTPS, datenschutzgerechte Betriebs-/Löschkonzepte einschließlich Audit-Daten, Backup/Restore und individuelle Betreuungszugänge erforderlich. Bei HTTPS `SESSION_SECURE=true` setzen. Der erste Zugang ist kein öffentliches Standardpasswort.
Ein lokaler Produktionsbuild lässt sich mit `npm run build` und `npm start` starten. Ein laufender Entwicklungsserver muss dafür vorher beendet werden oder ein anderer Port gewählt werden.