Files
FEDEO/docs/zeiterfassung-2.0.md

9.7 KiB

Zeiterfassung 2.0

Unter 2.0 → Zeiterfassung werden Anwesenheiten direkt als Zeitspannen gespeichert. Eine Anwesenheit enthält Beginn, Ende, Pausen und optionale Projektzuordnungen. Arbeitszeit ist die Anwesenheitsdauer abzüglich der Pausen. Die bisherige Erfassung bleibt für noch nicht umgestellte Mitarbeiter verfügbar.

Erfassung und Freigaben

Kommen öffnet eine Anwesenheit. Pause beginnen und Pause beenden erfassen Pausen innerhalb dieser Anwesenheit. Gehen schließt die Anwesenheit und gegebenenfalls eine laufende Pause. Manuelle Einträge können mehrere Tage umfassen. Überschneidungen, Pausen außerhalb der Anwesenheit und Projektzeiten innerhalb einer Pause werden abgelehnt. Projektzuordnungen sind exklusive Teilzeiträume; mehrere Projekte können nicht dieselbe Arbeitszeit beanspruchen.

Abgeschlossene Einträge können eingereicht werden. Berechtigte Personen können sie genehmigen oder mit Begründung ablehnen. Korrekturen verlangen einen Grund und setzen den Status auf Erfasst zurück. Damit wird die korrigierte Fassung erneut eingereicht und genehmigt. Der Verlauf enthält die vorherige und die neue Fassung, den Akteur, die Aktion und den Grund. Pausen und Projekte werden gemeinsam mit der Anwesenheit freigegeben.

Urlaub, Krankheit, Freizeitausgleich, Feiertag und Sonstiges werden als eigene Spannen geführt. Ganztägige Einträge verwenden in der Oberfläche einen ersten und letzten Tag einschließlich. Die API speichert das Enddatum exklusiv. Anwesenheiten und Abwesenheiten dürfen sich nicht überschneiden; bei teilweiser Abwesenheit sind Uhrzeitspannen zu verwenden.

Auswertung

Die Auswertung verwendet Europe/Berlin für Tagesgrenzen und begrenzt jede Spanne auf den gewählten Zeitraum. Nachtschichten zählen anteilig zu den jeweiligen Tagen oder Monaten. Zeitumstellungen werden anhand der tatsächlich vergangenen Zeit berücksichtigt. In manuellen Eingaben wird die angegebene IANA-Zeitzone verwendet; nicht existierende Ortszeiten werden im Formular abgelehnt. Unveränderte Zeitpunkte behalten ihren ursprünglichen Offset. Bei neu eingegebenen, doppelt vorkommenden Ortszeiten verlangt das Formular die Eingabe in UTC. Die API akzeptiert Zeitpunkte mit explizitem UTC-Offset.

Sollzeit stammt aus den regelmäßigen Wochenarbeitszeiten des Mitarbeiterprofils. Arbeitszeitsummen enthalten nur abgeschlossene Einträge; eingereicht umfasst auch genehmigte Zeiten. Urlaub und Krankheit werden nur genehmigt gutgeschrieben. Ganztägige Abwesenheiten zählen an Arbeitstagen gemäß Sollzeit, zeitweise Abwesenheiten höchstens bis zur Tagessollzeit. Feiertagsausgleich hat Vorrang vor Abwesenheitsgutschriften und zählt pro Datum einmal. Die Summe der Gutschriften überschreitet die Tagessollzeit nicht.

Freizeitausgleich und Sonstiges werden ausgewiesen, erzeugen aber keine zusätzliche Zeitgutschrift. Ein freier Arbeitstag zum Überstundenabbau reduziert deshalb den Saldo um seine Sollzeit. Aktuelle Anwesenheit und Pausen sind unabhängig vom ausgewählten Auswertungsmonat sichtbar.

Berechtigungen

Eigene Zeiten können angemeldete Mitarbeiter mit Profil im aktiven Mandanten erfassen. Folgende Berechtigungen werden im Backend durchgesetzt:

Berechtigung Funktion
staff.time.read_all Zeiten anderer Mitarbeiter lesen
staff.time.write_all Zeiten anderer Mitarbeiter lesen, erfassen, korrigieren und einreichen
staff.time.approve Zeiten lesen und eingereichte Zeiten genehmigen oder ablehnen
staff.time.activate Zeiten lesen, Übernahme prüfen und Mitarbeiter umstellen

Administratoren können diese Aktionen ebenfalls ausführen. Die Rechte werden als Berechtigungen der bestehenden Authentifizierungsrollen vergeben. Ein Lese- oder Genehmigungsrecht erlaubt keine Korrektur fremder Zeiten. Die Menüanzeige folgt dem vorhandenen Mandantenmerkmal staffTime.

Einführung und Datenübernahme

  1. Backend und Frontend gemeinsam bereitstellen. Vor Start des neuen Backends die regulären Datenbankmigrationen ausführen (npm run migrate im Backend). Die additive Migration 0080_staff_time_spans legt die neuen Tabellen und Schutzfunktionen an. Sie aktiviert niemanden automatisch.
  2. Als Administrator einen Mitarbeiter unter 2.0 → Zeiterfassung auswählen und Übernahme prüfen anklicken.
  3. Anzahl, Arbeitsminuten und Einträge in der Vorschau prüfen. Offene Einträge, fehlende Enden, unbekannte Ereignisse, uneinheitliche Freigaben oder überlappende Daten aus den beiden alten Modellen verhindern die Aktivierung. Diese Fälle müssen vorab in den Altdaten geklärt werden. Es werden keine Endzeiten erfunden und keine doppelten Einträge stillschweigend verworfen.
  4. Geprüfte Daten übernehmen und aktivieren übernimmt die vollständige Historie dieses Mitarbeiters in einer Transaktion. Wenn sich die Altdaten seit der Vorschau geändert haben, muss die Vorschau neu geladen werden. Wiederholte Aktivierung erzeugt keine Duplikate.
  5. Nach Aktivierung kommen auch Lesezugriffe auf historische Zeiträume aus dem neuen Modell. Die alten Datensätze bleiben erhalten; Quellverweise verbinden sie mit den übernommenen Spannen. Alte Schreibzugriffe werden durch Datenbanktrigger gesperrt. Eine Rückkehr zum alten Schreibmodell ist kein unterstützter Schalter.

Die erste Aktivierung sollte mit einem Mitarbeiter erfolgen, dessen Zeiten und Salden bekannt sind. Zusätzlich zur Arbeitsminutensumme sollten die Freigaben, Abwesenheitstage und Projektzuordnungen der Vorschau fachlich geprüft werden. Fehler der bisherigen Ereignisrekonstruktion können zu abweichenden, nun korrekt berechneten Ergebnissen führen. Der Import erhält die ursprünglichen Uhrzeitgrenzen; er interpretiert alte Uhrzeitspannen nicht nachträglich als ganztägige Abwesenheit.

Vor einer Bereitstellung ist eine Datenbanksicherung nötig. Nach erfolgter Umstellung ist bei Problemen eine Vorwärtskorrektur vorzuziehen. Ein vollständiges Zurücksetzen auf die Sicherung würde zwischenzeitlich erfasste Zeiten verlieren und ist eine gesonderte Betriebsentscheidung.

Bestehende Anbindungen

Die bisherigen Schnittstellen für Start, Ende, Einreichen, Genehmigen, Ablehnen und Auswertung erkennen aktivierte Mitarbeiter. Sie arbeiten dann auf den neuen Spannen. Die Webansicht unter Mitarbeiter → Zeiten wechselt für aktivierte Mitarbeiter zur neuen Oberfläche. Dashboard, Anwesenheitsanzeige und Plantafel lesen über diese kompatiblen Schnittstellen. Die Anwesenheitsanzeige berücksichtigt laufende Pausen.

Die Mobile-App fasst die kompatiblen Arbeitssegmente zu einer Anwesenheit zusammen und bietet Pausenaktionen für umgestellte Mitarbeiter. RFID-Terminals wechseln zwischen Kommen und Gehen; Gehen beendet eine laufende Pause. Für wiederholte Terminalübertragungen muss derselbe Zeitstempel oder dieselbe request_id mitgesendet werden. Scans ohne Zeitstempel und Anfrage-ID gelten jeweils als neue Betätigung. Rückwirkende Offline-Scans werden bei unpassendem Zustand oder Überschneidung abgelehnt und erfordern eine manuelle Korrektur.

Interne API-Aufrufe bleiben an den authentifizierten Mandanten gebunden. Öffentliche Formulare legen für umgestellte Mitarbeiter eine vollständige Anwesenheit mit Projektzuordnung an. Dokument und Zeit werden gemeinsam in einer Transaktion geschrieben, damit ein Zeitkonflikt keinen halbfertigen Lieferschein hinterlässt. Alte Bearbeitungs- und Projektänderungsaufrufe verweisen auf die vollständige Bearbeitung unter 2.0, damit Pausen oder Freigaben nicht verloren gehen.

Technischer Aufbau

staff_time_spans enthält Anwesenheiten und Abwesenheiten mit diskriminierendem Typ, Status und Versionsnummer. Gemeinsam gespeicherte Intervalle erlauben eine einheitliche Prüfung auf Überschneidungen. Zugehörige Tabellen enthalten Pausen, Projektzeiten, Änderungshistorie, Quellverweise sowie aktivierte Mitarbeiter und wiederholungssichere Anfragen. Der Mandantenexport nimmt auch Pausen, Projektzuordnungen und Änderungshistorie mit. Die Dienstschicht liegt unter backend/src/modules/time-v2.

Die API liegt unter /api/v2/time. GET /context liefert Mitarbeiterauswahl und Rechte, GET /spans die Spannen und den aktuellen Zustand, GET /evaluation die Auswertung und GET /spans/:id/history den Verlauf. POST /commands akzeptiert user_id, request_id und command. Bearbeitungen und Statuswechsel enthalten ID und erwartete Versionsnummer. Gleichzeitige Änderungen werden mit HTTP 409 beantwortet. Ein Wiederholungsversuch muss dieselbe Anfrage-ID und identische Daten verwenden. GET /migration erzeugt die Vorschau; POST /activate verlangt deren Fingerprint.

Prüfungen

Fachliche Tests laufen mit:

node --import ./backend/node_modules/tsx/dist/loader.mjs --test backend/tests/timeV2.test.ts

Die PostgreSQL- und HTTP-Integrationstests benötigen eine ausdrücklich bestimmte, entbehrliche Testdatenbank namens time_v2_test:

TIME_V2_TEST_DATABASE_URL=postgres://USER:PASSWORD@HOST:PORT/time_v2_test \
  node --import ./backend/node_modules/tsx/dist/loader.mjs --test backend/tests/timeV2.test.ts

Jeder Integrationstest erzeugt ein eigenes Schema und entfernt es anschließend. Ohne die Variable werden diese Integrationstests übersprungen. Getestet werden unter anderem Pausenabzug, Monatsgrenzen, Zeitumstellungen, Feiertage, Migration, Wiederholungen, Parallelzugriffe, Versionskonflikte, Statuswechsel und Mandantentrennung. Zusätzlich sind Backend-Typecheck und Frontend-Build auszuführen.

Die Browserprüfung verwendet ausschließlich simulierte API-Antworten und prüft den gebauten Frontend-Stand. Sie benötigt eine lokale Playwright-Installation und einen laufenden Frontend-Previewserver:

PLAYWRIGHT_MODULE=/ABSOLUTER/PFAD/playwright/index.mjs \
TIME_V2_FRONTEND_URL=http://127.0.0.1:3148 \
  node frontend/tests/time-v2.browser.mjs