- Introduced additional terms under Section 7 of the GNU AGPL v3 for KIBU, including attribution, marking of modified versions, and trademark usage. - Added MIT License file for clarity on licensing options. - Updated README.md to reflect the new licensing terms, including detailed usage rights and obligations. - Created REUSE.toml for SPDX compliance and license annotations. - Added THIRD_PARTY_NOTICES.md to clarify third-party dependencies and their licenses. - Updated various source files and scripts to include SPDX headers for copyright and licensing. - Enhanced footer in layout to display licensing information and project link. - Implemented a new license page to present the AGPL and additional terms clearly.
KIBU – Kinder-Betreuung Online
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.
Lizenz
Copyright (C) 2026 Paul Schoeneck. Originaler KIBU-Code steht unter
AGPL-3.0-only mit Zusatzbedingungen nach §7:
Lizenzhinweis, vollständige AGPL
und Zusatzbedingungen.
SPDX: AGPL-3.0-only AND LicenseRef-KIBU-Additional-Terms.
AND bildet die zusätzlich geltenden Bedingungen ab, keine Wahl einer anderen Lizenz.
- Private, interne und kommerzielle Nutzung, Änderungen, Hosting und Verkauf sind erlaubt, wenn die jeweils einschlägigen Lizenzbedingungen eingehalten werden.
- Bei Weitergabe müssen Lizenz-/Urheberhinweise erhalten bleiben und die Anforderungen an korrespondierenden Quellcode erfüllt werden. Veränderte Fassungen müssen als solche mit relevantem Änderungsdatum gekennzeichnet sein.
- Veränderte, über ein Netzwerk genutzte Versionen müssen den interagierenden
Nutzern einen gut sichtbaren kostenlosen Zugang zu ihrem vollständigen
korrespondierenden Quellcode anbieten (§13). Dazu gehören auch erforderliche
Build-/Installationsskripte, nicht aber Kinderdaten, Zugangsdaten oder
.env. Das bedeutet nicht, dass private Änderungen ohne Weitergabe oder Netzwerkangebot generell veröffentlicht werden müssen. - Die Oberfläche muss den festgelegten Herkunftshinweis bewahren. Es werden keine Markenrechte eingeräumt; daraus folgt keine pauschale Pflicht zur Umbenennung jeder Änderung. Gesetzlich erlaubte Herkunftsnennungen bleiben möglich.
- Es gibt keine Gewährleistung. Die Zusatzbedingungen gelten nur für Material, für das entsprechende Rechte vorliegen, nicht automatisch für Abhängigkeiten. Diese behalten ihre eigenen Lizenztexte und Hinweispflichten; siehe auch Drittanbieterhinweise.
Der globale Footer und die öffentliche Seite /license zeigen Herkunft, Lizenz,
Gewährleistungsausschluss und Projektlink. Vor Veröffentlichung muss der
Quellcode-Link tatsächlich den vollständigen Quellcode der bereitgestellten
Version verfügbar machen. Betreiber veränderter Versionen müssen ihren eigenen
passenden Quellcodezugang verlinken; der Herkunftslink zum Original bleibt bestehen.
Bei gebündelten Deployments müssen die von der Lizenzseite gelesenen Dateien aus
LICENSES mit ausgeliefert werden.
REUSE-Kennzeichnung: editierbare Quelldateien haben SPDX-Header.
JSON-Dateien und das generierte next-env.d.ts sind in REUSE.toml erfasst;
KIBU.md besitzt eine .license-Begleitdatei, damit der Inhalt unverändert bleibt.
next-env.d.ts ist eine generierte Next.js-Datei und behält die MIT-Kennzeichnung.
Prüfung (Python-Werkzeug, keine App-Abhängigkeit):
python -m pip install reuse
python -m reuse lint
Diese Erläuterung ist keine Rechtsberatung. Vor Veröffentlichung sind Rechte an allen Beiträgen/Assets, Drittanbieterhinweise, die konkrete Zulässigkeit der Zusatzbedingungen und gegebenenfalls Markenfragen zu prüfen. Datenschutz und Pflichten beim Betrieb mit echten Kinderdaten sind von der Softwarelizenz unabhängig.
Starten
Voraussetzungen: Node.js 20.9 oder neuer, npm und Docker Desktop mit lokalem Linux-Container-Kontext.
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(StandardEurope/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.
- 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. - 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.
- 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.
- Einmalig X Plätze auslosen: X muss zwischen 1 und Anzahl der Anmeldungen liegen (maximal 10.000). Jede Anmeldung hat die gleiche Chance;
crypto.randomIntmit 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. - 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
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.
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.
Testinstanz leeren oder neu befuellen
Achtung: unwiderruflich, nur fuer lokale Testdatenbanken! Vorher die App
beenden. Beide Befehle loeschen alle Kinder, Wochen-/Tagesplaene, Anwesenheit,
Abholberechtigungen, Alleingehregeln, den gesamten Audit-Verlauf,
Aufnahmerunden, Anmeldungen, Limits, Betreuungskonten und Sitzungen.
Eigene Slots werden durch die vier aktiven Standardslots ersetzt.
Schema, angewendete Migrationen und die lokale .env bleiben erhalten.
Der Audit-Loeschschutz wird nur innerhalb der Reset-Transaktion kurz aufgehoben;
bei einem Fehler wird die gesamte Leerung zurueckgerollt.
# Nur leeren, noch ohne neuen Zugang oder Demokinder:
npm run db:clear -- --confirm-reset
# Leeren, neuen Zugang erstellen und 12 fiktive Kinder mit Verlauf anlegen:
npm run db:reset -- --confirm-reset
Ohne --confirm-reset wird nichts geloescht. Remote-Datenbankadressen und
PostgreSQL-Verwaltungsdatenbanken werden abgelehnt. Die Adresse allein ersetzt
keine Pruefung des Ziels: auch eine lokale Portweiterleitung darf nicht auf
Produktivdaten zeigen.
db:reset fuehrt nach dem Leeren die vorhandenen Befehle db:setup und
db:seed aus. Ein neues zufaelliges Passwort erscheint im Terminal; wenn in
.env BOOTSTRAP_EMAIL/BOOTSTRAP_PASSWORD gesetzt sind, werden diese benutzt.
Alte Passwoerter und Sitzungen funktionieren danach nicht mehr. Die Demodaten
umfassen Kinder, Wochenplaene, Tagesabweichungen, Kontakte, Alleingehregeln und
zwei Wochen Anwesenheitsverlauf; Aufnahmerunden bleiben leer.
Nach db:clear bei Bedarf npm run db:setup und npm run db:seed einzeln
ausfuehren. db:seed allein ist weiterhin nicht destruktiv und ueberschreibt
keine vorhandenen Kinder. Schlaegt die Neueinrichtung nach erfolgreichem Leeren
fehl, bleibt die Instanz leer bzw. teilweise eingerichtet; Ursache beheben und
db:setup/db:seed erneut ausfuehren. Anschliessend die App wieder starten.
Prüfen
npm test
npm run test:db
npm run test:reset
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.
test:reset erstellt eine eigene zufaellig benannte lokale Testdatenbank und
entfernt ausschliesslich diese wieder. Der Datenbankzugang benoetigt dafuer
CREATEDB (beim lokalen Compose-Zugang vorhanden). Der Test prueft Schutzabfragen,
vollstaendige Leerung, Standardslots, erneute Demo-Befuellung, neue Zugangsdaten
und den nach dem Reset wieder aktiven Audit-Loeschschutz.
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.