# Personalbereich: Arbeitszeit, Urlaub und Zeitkonto Stand: 08.10.2026 · Branch `codex/personalbereich` ## Einstieg und Zuständigkeiten Der Bereich liegt unter `/dashboard/personal`. Kita-Admins (einschließlich Vorstand mit Rolle `ADMIN`) verwalten alle Personalprofile ihrer Kita. ErzieherInnen bearbeiten eigene Zeiten und Anträge. Eltern und Koordination haben keinen Zugriff. Der interne Teamkalender ist nur für Admins und ErzieherInnen zugänglich. Bestehende ErzieherInnen-Stammdaten bleiben erhalten. Ein Admin öffnet beim Personalstamm das **Personalprofil** und hinterlegt: 1. Beschäftigungsbeginn, optionales Ende, Beginn der Zeiterfassung und Anfangssaldo. 2. Ein datiertes Wochenmodell mit Netto-Sollstunden für Montag bis Sonntag; 0 bedeutet frei. 3. Jahresurlaub und ausdrücklich festgelegten Übertrag, individuell für die Arbeitstage dieser Person. 4. Einen passenden ErzieherInnen-Account. Bestehende verifizierte Accounts derselben Kita können verknüpft werden. Für neue Accounts wird ein persönlicher, einmal verwendbarer Aktivierungslink mit sieben Tagen Gültigkeit erzeugt. Ein neuer Link ersetzt den alten. 5. Die örtlichen Feiertage unter **Teamkalender**. Feiertage gelten separat von den Schließtagen des allgemeinen Kalenders. Der Aktivierungsablauf verwendet die bestehende Passwort- und Consent-Einrichtung unter `/invite/[token]`. Neue Accounts erhalten den Aktivierungslink per E-Mail; der berechtigte Admin erhält ihn zusätzlich zum Kopieren. Ein vorhandener verifizierter Account wird verknüpft, ohne eine Aktivierungsmail zu verschicken. ## Arbeitszeit und Überstunden Pro Tag sind mehrere Arbeitsblöcke mit Beginn, Ende und Pause möglich. Zeitblöcke dürfen nicht überlappen. Die Pause wird in Minuten vom Block abgezogen. Zeiten werden für heutige oder vergangene Tage innerhalb der Beschäftigung und ab Erfassungsbeginn erfasst. Blöcke über Mitternacht werden auf zwei Tage aufgeteilt. Die Tagesbilanz ist **Istzeit + Urlaub/Krankheit − Sollzeit**. Arbeit an einem freien Tag oder Feiertag zählt als zusätzliche Istzeit. Die Wochenansicht zeigt alle sieben Tage; in einer laufenden Woche fehlen zukünftige Arbeitszeiten noch, deshalb ist ihre Differenz vorläufig. Die Fachkraft reicht ihre Woche nach dem letzten vorgesehenen Arbeitstag ein. Offene Abwesenheiten im Zeitraum müssen zuerst geklärt sein. Der Admin prüft die einzelnen Zeiten, genehmigt die Woche oder gibt sie mit Rückmeldung zurück. Eingereichte und genehmigte Wochen sperren Zeitänderungen. Eigene Wochen und eigene Anträge können nicht selbst freigegeben werden. Beim Genehmigen wird die Tagesberechnung gespeichert. Nur genehmigte Wochen, der Anfangssaldo und wirksame manuelle Korrekturen zählen zum bestätigten Zeitkonto. Offene oder eingereichte Wochen wirken noch nicht auf dieses Konto. Eine Rückgabe entfernt die Wochenbuchung bis zur erneuten Freigabe. Fehler in manuellen Korrekturen werden durch eine begründete Gegenbuchung behoben. ## Feste Wochentage und seltene Wechsel Wochenmodelle gelten ab ihrem Datum. Eine spätere Änderung überschreibt kein früheres Modell. Seltene Tausche werden über zwei Tagesausnahmen erfasst: der bisherige Arbeitstag erhält 0 Sollstunden, der Ersatztermin die vorgesehenen Stunden. Genehmigte Abwesenheiten sowie eingereichte oder genehmigte Wochen schützen ihren Zeitraum auch vor Änderungen an Modellen, Ausnahmen und Feiertagen. Betroffene Freigaben müssen vor einer solchen Änderung zurückgegeben bzw. storniert werden. Grunddaten und Anfangssaldo werden nach der ersten Erfassung geschützt; das Beschäftigungsende bleibt über einen eigenen Ablauf verwaltbar, sofern bestehende Zeiten und Anträge nicht verletzt werden. ## Urlaub Urlaub ist ganztägig oder für einen einzelnen halben Tag möglich. Nur vorgesehene Arbeitstage verbrauchen Urlaub. Wochenenden sind nicht pauschal frei: Entscheidend sind Wochenmodell und Tagesausnahmen. Feiertage verbrauchen keinen Urlaub und erzeugen keine Sollzeit. Ein halber Urlaubstag schreibt die Hälfte der Tages-Sollzeit gut; bei ungerader Minutenzahl wird auf eine ganze Minute gerundet. Ein Jahreskonto führt Anspruch plus Übertrag, genommenen Urlaub, genehmigten geplanten Urlaub, offene Anträge und verfügbaren Rest. Offene Anträge werden bei weiteren Anträgen berücksichtigt. Abgelehnte und stornierte Anträge verbrauchen nichts. Zeiträume über den Jahreswechsel werden auf die jeweiligen Jahreskonten verteilt. Anspruch und Übertrag werden nicht automatisch anteilig berechnet oder zum Jahreswechsel übertragen. Offene Anträge können geändert oder zurückgezogen werden. Bei genehmigten Anträgen wird eine Stornierung beantragt. Bis zur Entscheidung bleibt die Abwesenheit gebucht. Krankheit hinterlegt der Admin; sie entlastet die Sollzeit, ohne Urlaub zu verbrauchen. KollegInnen sehen Krankheit im Teamkalender nur als **Abwesend**, ohne persönliche Notizen oder Kontodaten. ## Freizeitausgleich Freizeitausgleich wird für einen einzelnen vorgesehenen Arbeitstag in Stunden beantragt. Das bestätigte verfügbare Guthaben muss ausreichen; weitere offene Anträge werden dabei berücksichtigt. Nach Genehmigung wird die Zeit reserviert. Freizeitausgleich erzeugt keine zusätzliche Istzeit oder Urlaubsgutschrift. Beispiel: 6 Stunden Soll, 5 Stunden Arbeit und 1 Stunde Freizeitausgleich ergeben eine Tagesbilanz von −1 Stunde. Mit der Wochenfreigabe wird diese Stunde im Zeitkonto gebucht und die Reservierung entfällt. Dadurch wird die Stunde genau einmal abgezogen. Bei offenen Stornierungen bleibt die Reservierung erhalten. ## Hinweise und Nachvollziehbarkeit Neue Anträge und eingereichte Wochen erzeugen interne Hinweise für Kita-Admins. Entscheidungen und Rückgaben erzeugen Hinweise für die betroffene Fachkraft. Hinweise lassen sich als gelesen markieren; jede Person kann ausschließlich eigene Hinweise quittieren. Das Personalprofil zeigt die letzten 30 Änderungen. Im Datenmodell werden sämtliche Änderungen mit Zeitpunkt und handelnder User-ID gespeichert. Parallele Änderungen laufen in serialisierbaren Datenbanktransaktionen mit Wiederholung bei Schreibkonflikten. Rollen, Accountstatus, Eigentümer und Kita-Zugehörigkeit werden serverseitig geprüft. Das Löschen von Fachkräften mit Personalprofil wird verhindert; sie können auf inaktiv gesetzt werden. Bei Accountlöschung bleiben Personalaufzeichnungen ohne Accountverknüpfung erhalten. Die Löschung einer Kita entfernt auch ihren Personalbereich. ## Einführung und Schema Das Projekt verwendet weiterhin seinen vorhandenen Ablauf mit `prisma db push`. Es gibt keine vollständige versionierte Prisma-Migrationshistorie. Die neuen Tabellen sind additiv; vorhandene Personen erhalten noch kein automatisch befülltes Beschäftigungsprofil. - Lokal: Abhängigkeiten installieren, Prisma-Client generieren, Schema gegen eine dafür vorgesehene Datenbank anwenden, App starten und Profile einrichten. - Im vorhandenen Docker-Ablauf erzeugt `npm run build:prod` den Client; `scripts/start-production.sh` wendet das Schema vor App-Start an. - [Prüfbares SQL](../deploy/sql/personalbereich.sql) beschreibt dieselbe additive Änderung gegen den dokumentierten Ausgangsstand. Es ist einmalig und nicht idempotent. Entweder den vorhandenen Schemaabgleich **oder** dieses SQL verwenden; das SQL nicht nach bereits erfolgtem Schemaabgleich erneut ausführen. - Ist der Personalbereich bereits auf Stand `043fed2` eingeführt, beschreibt [Personalbereich-E-Mail-SQL](../deploy/sql/personalbereich-email.sql) ausschließlich die zusätzlichen Mail-Tabellen und die Profileinstellung. Auch dieses Skript ist eine einmalige Alternative zum Schemaabgleich. Die reale Projekt- und Produktionsdatenbank wurde bei dieser Umsetzung nicht verändert. Alle DB- und Browserprüfungen liefen mit synthetischen Daten in einer separaten lokalen PostgreSQL-Datenbank. ## Prüfungen - `npm run test:staff`: Berechnungstests für Teilzeit, halbe Tage, Feiertage, Jahreswechsel, Statuswechsel, Pausen, Snapshots und Freizeitausgleich. - `npm run test:staff:integration`: echte Datenbankabläufe für Mandantentrennung, Rollen und Eigentümer, Anträge, Freigaben, parallele Änderungen, Sperren, Rückgaben, Aktivierungslinks und Beschäftigungsende. - Integrationstests akzeptieren ausschließlich `127.0.0.1:55439/kita_staff_test`. Beispiel: `DATABASE_URL=postgresql://USER@127.0.0.1:55439/kita_staff_test npm run test:staff:integration`. Die leere Testdatenbank vorher mit dem aktuellen Schema einrichten. Tests bereinigen nur ihre eigens erzeugten Testkitas. - Browserprüfung: Admin richtet Profil, 18-Stunden-Woche und 18 Urlaubstage ein; Erzieherin erfasst drei Blöcke mit Pausen, reicht eine 19-Stunden-Woche ein und beantragt einen Urlaubstag. Nach Adminfreigabe zeigt das Zeitkonto 11 Stunden (10 Stunden Anfangssaldo + 1 Stunde Wochenplus) und das Urlaubskonto 17 Tage. Der Urlaub erscheint im Teamkalender. Ergebnisse der abschließenden Prüfung: | Prüfung | Ergebnis | | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Berechnungstests | 9 bestanden. | | Integrationstests | 17 bestanden; einschließlich Empfänger, Opt-out, Versandfehler, Token-Erneuerung und paralleler Versandversuche. Testkitas danach bereinigt. | | TypeScript | Erfolgreich. | | ESLint für sämtliche geänderten Anwendungsteile und neue Tests | Erfolgreich, ohne Warnungen. | | Projektweites ESLint | Die bereits vorhandenen zwei `as any`-Fehler in `src/lib/auth-utils.ts` und neun Warnungen bestehen weiterhin. | | Endgültiger Produktionsbuild | Erfolgreich, einschließlich `/dashboard/personal`. | | Vollständiges und inkrementelles SQL-Skript | Erfolgreich in isolierten Prüfschemata; anschließend jeweils kein Unterschied zum Prisma-Schema. | | Browser | Admin- und ErzieherInnen-Ablauf einschließlich Freigaben erfolgreich. Mobile Ansicht und Arbeitszeitdialog ohne Seitenüberlauf geprüft. Abschalten der E-Mail-Hinweise im Demo-Profil gespeichert und nach Neuladen verifiziert; anschließend wieder eingeschaltet. | Die vom bestehenden Build gemeldete Warnung zu mehreren Lockfiles bzw. dem Turbopack-Arbeitsverzeichnis und die bestehende Prisma-Konfigurationswarnung sind unabhängig vom Personalbereich. Eine produktive Bereitstellung oder Mailzustellung wurde nicht durchgeführt. ## E-Mail-Hinweise Die E-Mail-Erweiterung wurde am 08.10.2026 ausdrücklich beauftragt. Sie verwendet die vorhandene Resend-Anbindung: | Nachricht | Empfänger | Inhalt | | ------------------------------------------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------- | | Accountaktivierung | Vom Kita-Admin eingetragene E-Mail-Adresse der Fachkraft | Kita, Name, persönlicher Aktivierungslink mit sieben Tagen Gültigkeit. | | Antrag / Änderung / Stornierung oder Arbeitswoche eingereicht | Alle Kita-Admins derselben Kita, einzeln angeschrieben | Name, Zeitraum und Hinweis auf Prüfung im geschützten Personalbereich. | | Entscheidung / Rückgabe | Account-Adresse der betroffenen Fachkraft | Art, Zeitraum und Status mit Link in den geschützten Personalbereich. | Fachkräfte können Entscheidungsmails unter **Mein Profil → E-Mail-Hinweise** abschalten. Aktivierungslinks und interne App-Hinweise bleiben davon unabhängig. Krankheitsbuchungen erzeugen keine E-Mail. Private Notizen, Entscheidungsbegründungen und Zeit- oder Urlaubskontostände werden nicht per E-Mail übertragen. Versandaufträge werden innerhalb derselben Datenbanktransaktion wie die Personalaktion gespeichert. Der Versand erfolgt anschließend; ein Fehler macht den gespeicherten Antrag nicht rückgängig. Ausstehende Mails erscheinen im Personalbereich mit **Versand erneut versuchen**. Admins dürfen die Aufträge ihrer Kita wiederholen, Fachkräfte nur eigene. Pro Aktion werden bis zu 50 ausstehende Aufträge verarbeitet. Es gibt keinen zusätzlichen Hintergrundjob. Vor jedem Versand werden Kita-Zugehörigkeit, aktuelle Rolle, Accountverknüpfung und gegebenenfalls die Abschalteinstellung geprüft. Ersetzte, abgelaufene oder bereits verwendete Aktivierungslinks werden übersprungen. Eine fünfminütige Versandsperre verhindert parallele Versuche für denselben Auftrag; ein stabiler Resend-Idempotenzschlüssel vermindert doppelte Zustellungen bei Wiederholungen. Eine Zustellbestätigung des Empfängerpostfachs wird nicht erfasst. Benötigt werden `RESEND_API_KEY`, `EMAIL_FROM` und eine öffentliche App-Adresse über `NEXT_PUBLIC_SITE_URL`, alternativ `AUTH_URL` oder `NEXTAUTH_URL`. Ohne Konfiguration bleibt ein Produktionsversand ausstehend und wird als Warnung angezeigt. Im Entwicklungsmodus ohne Resend-Schlüssel wird der bestehende lokale Mailtransport simuliert. Die Tests verwenden ausschließlich einen eingesetzten Testtransport; es wurden keine echten E-Mails verschickt.