Zum Hauptinhalt springen

Zeiterfassung

Zweck

Zeiterfassung dokumentiert geleistete Arbeitszeit pro Mitarbeiter — entweder global (Anwesenheit) oder im Kontext eines Auftrags (Leistungs-Zeit). Pro Eintrag pflegen Sie Start, Ende, optionalen Service (Was wurde erbracht?), Billable-Flag (Verrechenbar?) und Kommentar.

Voraussetzungen

- Mindestens ein Mitarbeiter mit aktivem Vertrag. - Bei Workorder-Trackings: Auftrag darf nicht gesperrt sein (`Workorder.locked = false`). - Berechtigung `create:FullEmployeeTimeTracking`.

Berechtigungen (CASL)

ActionSubjectWirkungKeycloak-Rolle
viewFE_EmployeeTimeTracking, EmployeeTimeTrackingListe/Details aufrufbar
createFullEmployeeTimeTrackingNeue Zeit erfassenAPP_SPEAMCORE_CREATE_FULL_EMPLOYEE_TIME_TRACKING
update/deleteEmployeeTimeTrackingEigene oder fremde Zeiten ändernAPP_SPEAMCORE_UPDATE/DELETE_EMPLOYEE_TIME_TRACKING

Schritt-für-Schritt-Anleitung

Zeit erfassen

  1. Zeiterfassung (/employee-time-trackings) → + Neu.
  2. Im Modal FullTimeTrackingForm:
    • Mitarbeiter wählen.
    • Parent-Kontext wählen: Employee (Anwesenheits-Zeit) oder Workorder (Leistungs-Zeit). Bei Workorder-Auswahl Auftrag mit auswählen.
    • Start-Zeit (Pflicht).
    • End-Zeit (optional — leer lassen für „laufende" Zeitmessung).
    • Service (optional, für Leistungs-Klassifikation).
    • Verrechenbar (Switch).
    • Kommentar (optional).
  3. Speichern. System prueft Doppelbuchungen (offene Records) und Workorder-Lock.

Zeit bearbeiten

Eintrag in der Liste öffnen → Modal mit denselben Feldern.

Wenn die zugehörige Workorder gesperrt ist, blockiert der Backend-Hook das Update. Die UI ist aktuell **nicht** ausgegraut — die Sperre wird erst beim Speichern angezeigt.

Listenansicht — employee-time-trackings

Überlauf-Schutz „Noch da?" (über 10 Stunden)

Läuft eine Zeiterfassung ohne Ende sehr lange, greift seit Juni 2026 ein Überlauf-Schutz — er verhindert vergessene laufende Zeiten und unterstützt die Arbeitszeit-Dokumentation (ArbZG).

  1. Ein globaler Watcher im Frontend ruft alle 60 Sekunden die laufende Zeit ab (GET /employees/:id/active-time-tracking).
  2. Überschreitet die offene Zeit 10 Stunden und wurde sie nicht innerhalb der letzten Stunde bestätigt, erscheint ein „Noch da?"-Hinweis mit 5-Minuten-Countdown und (einmalig je Sitzung) eine Browser-Benachrichtigung.
  3. Zwei Aktionen:
    • Ja, noch daPOST …/confirm-overrun — setzt overrunConfirmedAt; danach 1 Stunde Ruhe.
    • StoppenPOST …/stop-overrun — beendet die Zeit.
  4. Failsafe im Backend: Ein Minuten-Cron erkennt überlange offene Zeiten unabhängig vom Browser und sendet eine Push-Benachrichtigung an die Geräte des Mitarbeiters.
Der Überlauf-Schutz ist eine **Erinnerung**, kein hartes Limit: Er stoppt die Zeit nicht automatisch beim 10-Stunden-Wert, sondern fragt nach. Erst wenn niemand reagiert, greift der Backend-Failsafe. Die gesetzliche Tageshöchstgrenze behandelt zusätzlich das Konzept [§3 ArbZG-Cap](/konzepte/arbzg-paragraph-3-cap).

Toolbar (Detail-Seite)

Schlanke Toolbar oben rechts:

IconAktion (aria-label)CASLWirkung
ZurückgehenZurück zur Liste.
🏠Zur Startseite gehenSpringt auf das Dashboard / /.
⏮/◀/▶/⏭PaginationNavigation durch die gefilterte Liste — Massen-Bearbeitung ohne Liste-Sprung.

Wie auf jeder Detail-Seite verfuegbar — siehe Floating-Quickbar:

  • KAL. (Mini-Kalender)
  • ZEIT (Persoenliche Wochen-Arbeitszeit)
  • ARBEIT (Eigene bevorstehende Aufträge)

Felder und Eingaben

FeldnamePflichtDatentypBeschreibungWirkung beim AusfuellenVoraussetzung
employeeIdjaUUID (Lookup)Mitarbeiter, dem die Zeit zugeordnet wird.Wird auf Anwesenheits- und Auftrags-Reports angerechnet.view:Employee
parentTypejaEnumEmployee (Anwesenheit) oder Workorder (Leistung).Steuert, gegen welchen Datensatz die Zeit verbucht wird.
parentIdjaUUIDID des Parent-Datensatzes.Wenn Workorder: view:Workorder und Auftrag nicht gesperrt.
startTimejaDateTimeBeginn der Zeit.Anker für Sortierung und Tages-/Monats-Aggregation.
endTimeneinDateTimeEnde der Zeit. Leer = laufende Zeit.Wenn leer, gilt der Eintrag als „offen" — Doppelbuchungen pro Mitarbeiter werden geblockt.
serviceIdneinUUID (Lookup)Service-Zuordnung für Leistungs-Auswertung.Beeinflusst Reports und Auswertungen pro Service.view:Service
billableneinBoolean (Switch)Verrechenbar gegenueber Kunde.Wenn true: kann auf einen Verkaufsbeleg übernommen werden.
commentneinTEXTOptionaler manueller Kommentar.Erscheint in Reports und auf der Workorder-Detail-Seite.
autoCommentString (read-only)Automatisch befüllter Kommentar (Mai 2026), getrennt vom manuellen comment. Quelle: In-App-Aktivität (nur bei Einwilligung) bzw. Speam-intern GitLab-Commits.Überschreibt comment nie; reine Lese-Hilfe.Employee.activityTrackingConsent für den Activity-Provider.
employeeTimeTrackingTypeIdneinUUIDKlassifizierungs-Stammdatum (z. B. „Reise", „Pause").Wird in Reports gruppiert.
overrunPromptedAtDateTime (read-only)Zeitpunkt der letzten „Noch da?"-Aufforderung.gesetzt vom Überlauf-Schutz
overrunConfirmedAtDateTime (read-only)Zeitpunkt der letzten Bestätigung durch den Mitarbeiter (danach 1 h Ruhe).gesetzt bei „Ja, noch da"

Wiederverwendbare Konzepte

Verknuepfungen zu anderen Modulen

  • Mitarbeiter — Tab Zeiterfassung zeigt eigene Zeiten.
  • Aufträge — Tab Arbeitszeit zeigt alle Trackings dieses Auftrags.
  • WorkorderEmployee — wird automatisch erzeugt/reaktiviert, wenn eine Zeit zu einem Auftrag erfasst wird.
  • Verkaufsbelegebillable-Trackings koennen in Belegpositionen übernommen werden.

Häufige Fehler und Lösungen

FehlerLösung
„Doppelbuchung" beim SpeichernBestehender offener Eintrag (endTime = null) — vorherige Zeit erst beenden.
Workorder-Tracking blockiertAuftrag ist gesperrt (locked = true) — Auftrag entsperren oder andere Workorder wählen.
endTime vor startTimeValidierung lehnt das ab. Werte korrigieren.

API/Schnittstellen

MethodeEndpointZweckCASL
GET/api/employees/time-trackingsListeview EmployeeTimeTracking
POST/api/employees/time-tracking/:parentType/:parentId/:employeeIdAnlegen mit Auto-Ensure WorkorderEmployeecreate FullEmployeeTimeTracking
PATCH/api/employees/time-tracking/:idÄndern (mit Lock-Check)update EmployeeTimeTracking
DELETE/api/employees/time-tracking/:idSoft-Deletedelete EmployeeTimeTracking
GET/api/employees/:employeeId/active-time-trackinglaufende Zeit für den „Noch da?"-Watcherview EmployeeTimeTracking
POST/api/employees/:employeeId/time-tracking/:id/confirm-overrunÜberlauf bestätigenupdate EmployeeTimeTracking
POST/api/employees/:employeeId/time-tracking/:id/stop-overrunÜberlauf-Zeit stoppenupdate EmployeeTimeTracking

Jede Zeile der Liste hat in der Actions-Spalte ein Sprung-zum-Kontext-Icon (FiExternalLink):

  • parentType = Workorder → Klick öffnet /workorders/:id im Detail (CASL-Voraussetzung view:Workorder)
  • parentType = Employee → Klick öffnet /employees/:id (view:Employee)

Label entsprechend „Gehe zu Workorder" oder „Gehe zu Mitarbeiter" (i18n). Die Spalte ist 140 px breit und steht vor den Edit/Delete-Actions. Backend-Query nutzt include=workorder.NumberCircleAssignment, damit die Workorder-Nummer in der Tabelle korrekt rendert.

Versionshinweise

  • 2026-06-22: Überlauf-Schutz „Noch da?" dokumentiert — globaler Watcher (60 s), 10-Stunden-Schwelle, 5-Minuten-Countdown + Browser-Benachrichtigung, Backend-Failsafe-Cron; neue read-only-Felder overrunPromptedAt/overrunConfirmedAt und Endpoints active-time-tracking, confirm-overrun, stop-overrun. Verifiziert an TimeTrackingOverrunWatcher.tsx, timeTrackingOverrun.service.ts, employeeTimeTracking.router.ts, employeeTimeTracking.model.ts.

  • 2026-05-31: Read-only-Feld autoComment ergänzt — automatisch befüllter Kommentar (Provider-basiert: Activity bei Einwilligung / GitLab Speam-intern), getrennt vom manuellen comment. Quelle: BE autoComment.service.ts, Migration add-auto-comment-to-employee-time-trackings.

  • 2026-05-20 (Welle 132): Neue Actions-Spalte mit RefLink-Icon zum verknüpften Parent (Workorder oder Employee), basierend auf parentType. Quelle: FE-Commit 3da01a80.

  • 2026-04-29: Initiale Veroeffentlichung mit FE-Tiefen-Standard.