Zeiterfassung
Eine Full-Stack-Zeiterfassungsanwendung, entwickelt mit Node.js, Express, SQLite und containerisiert mit Docker.
📸 Screenshots
Hauptansicht mit Timer und Monatsübersicht
Funktionen
⏱️ Zeiterfassung
- Live-Timer mit automatischen Pausen: Start/Stop-Timer erfasst die tägliche Arbeitszeit
- Automatische Pausen nach 6h (30 Min) oder 9h (45 Min) gemäß deutschem Arbeitszeitgesetz
- Rundung auf 15-Minuten-Intervalle
- Timer persistiert über Seiten-Reloads
- Manuelle Startzeit-Eingabe möglich
- Visueller Indikator (blinkendes Uhr-Icon) bei laufendem Timer
- Flexible Eingabemodi:
- Manuelle Eingabe (Datum, Start, Ende, Pause)
- Inline-Bearbeitung direkt in der Tabelle
- Schnelles Hinzufügen von Einträgen über Monatsansicht
- Arbeitsort-Tracking: Büro oder Home-Office pro Eintrag
- Sondereinträge:
- Urlaubstage (werden nicht vom Saldo abgezogen)
- Gleittage (ziehen 8h vom Saldo ab)
📊 Intelligente Berechnungen
- Automatische Pausenberechnung (deutsches Arbeitszeitgesetz)
- 10-Stunden-Cap für maximale Nettoarbeitszeit pro Tag
- Live-Statistiken mit laufendem Timer:
- Soll-Stunden (basierend auf Arbeitstagen)
- Ist-Stunden (inkl. aktuell laufender Timer)
- Monatssaldo + Gesamtsaldo mit Vormonatsübertrag
- Arbeitstage-Zählung
- Urlaubsverwaltung:
- Konfigurierbares Jahres-Kontingent
- Tracking: Genommen, Geplant, Verfügbar
- Automatische Jahresberechnung
🗓️ Bundesland-spezifische Feiertage
- 16 Bundesländer mit korrekten regionalen Feiertagen
- Persistente Einstellung (gespeichert in Datenbank)
- Kollisionserkennung: Warnung bei Feiertagen mit bestehenden Einträgen
- Alle Feiertage: Bundeseinheitlich + regional (z.B. Fronleichnam, Reformationstag)
📅 Monatsansicht & Navigation
- Vollständiger Monatskalender mit allen Tagen
- Intuitive Farbcodierung:
- 🟢 Grün: Home-Office
- 🟡 Gelb: Urlaub
- 🔵 Cyan: Gleittage
- 🔴 Rot: Fehlende Arbeitstage
- ⚫ Grau: Wochenenden
- 🔵 Blau: Feiertage (mit Namen)
- Navigation: Vor/Zurück-Buttons zum Monatswechsel
- Auto-Fill: Automatisches Befüllen des Monats mit Standard-Arbeitszeiten (9:00-17:30)
- Quick-Actions: Plus-Buttons für schnelles Hinzufügen von Einträgen
⚡ Bulk-Operationen
- Mehrfachauswahl-Modus mit Checkboxen
- Bulk-Aktionen:
- Standort setzen (Büro/Home)
- Urlaub eintragen
- Gleitzeit eintragen
- Löschen
- Funktioniert in beiden Ansichten (Monatsansicht + Filteransicht)
🔍 Filter & Export
- Zeitraum-Filter: Von/Bis-Datum (bleibt bei Bulk-Aktionen erhalten)
- Getrennte Ansichten: Monatsnavigation wird bei Filter-Ansicht ausgeblendet
- CSV-Export (Alle): Alle Einträge im gewählten Zeitraum
- Spalten: Datum, Start, Ende, Pause (Min), Netto (h), Arbeitsort, Abweichung (h)
- CSV-Export (Abweichungen): Nur Tage ≠ 8,0h
- Ideal für Gleitzeit-Nachweise
- PDF-Export:
- Monats-Export: Exportiert aktuellen Monat als formatierten PDF
- Bulk-Export: Exportiert ausgewählte Einträge (im Bulk-Modus)
- Professionelles Layout mit Mitarbeiter-Info und Statistiken
- Automatische Tabelle mit allen Einträgen
- Deutsche Formatierung (Datum, Währung, Dezimalstellen)
- Deutsches Format: Semikolon-getrennt (CSV), Komma-Dezimal
💾 Datenbank-Management
- Datenbank-Export: Vollständiger Export aller Daten als JSON
- Enthält alle Einträge und Einstellungen
- Versioniert für Kompatibilität
- Zeitstempel im Dateinamen
- Datenbank-Import: Wiederherstellen aus JSON-Backup
- Validierung der Datenstruktur
- Bestätigungs-Dialog vor Überschreiben
- Löscht alte Daten vor Import
- Importiert Einträge und Einstellungen
- Instanz-Migration: Einfaches Wechseln zwischen Servern/Instanzen
🎨 Modernes UI/UX
- Premium Design: Glass-Morphism, Gradients, Schatten, Animationen
- Responsive: Desktop, Tablet, Mobile
- Dark Mode: Augenschonendes dunkles Design
- Toast-Benachrichtigungen: Visuelles Feedback
- Icons: Lucide Icons für klare Symbolik
- Flatpickr: Touch-optimierte Datums-/Zeit-Picker
🏗️ Technologie-Stack
Backend:
- Node.js 18+ mit Express.js
- SQLite (better-sqlite3) für dateibasierte Persistenz
- Modulare Architektur (config, utils, routes)
Frontend:
- Vanilla JavaScript (ES6+)
- Tailwind CSS (CDN)
- Lucide Icons
- Flatpickr (Datums-/Zeit-Picker)
- jsPDF mit autoTable Plugin (PDF-Generierung)
Infrastructure:
- Docker & Docker Compose
- Multi-Stage Build für optimierte Images
- Gitea Actions CI/CD für automatische Builds
- Gitea Container Registry für Image-Hosting
📁 Projektstruktur
timetracker/
├── server.js # Express Entry Point
├── db/
│ ├── schema.sql # Datenbankschema
│ └── timetracker.db # SQLite Datenbank (generiert)
├── public/
│ ├── index.html # Single-Page Application
│ ├── favicon.svg # App Icon
│ └── js/
│ ├── state.js # Globaler State
│ ├── utils.js # Hilfsfunktionen
│ ├── holidays.js # Feiertagsberechnung
│ ├── api.js # Backend-Kommunikation
│ └── main.js # Hauptlogik (~3700 Zeilen)
├── .gitea/workflows/ # CI/CD Workflows
│ └── docker-build.yml # Docker Build & Push
├── media/screenshots/ # App-Screenshots
├── Dockerfile # Container-Image
├── docker-compose.yml # Orchestrierung
└── package.json
⚙️ Deutsche Arbeitszeitregelungen
Die App implementiert deutsches Arbeitszeitgesetz (ArbZG):
- > 6h Arbeit → 30 Min Pause (automatisch)
- > 9h Arbeit → 45 Min Pause (automatisch)
- Maximale Nettoarbeitszeit: 10,0h pro Tag
- Rundung: Alle Zeiten auf 15-Minuten-Intervalle
🚀 Installation & Ausführung
<EFBFBD> Option 1: Vorgefertigtes Docker Image (Empfohlen)
Voraussetzungen: Docker (& Docker Compose optional)
# Image pullen (public registry, kein Login nötig)
docker pull gitea.fx-se.de/maggot/timetracker:latest
# Container starten
docker run -d \
-p 3000:3000 \
-v $(pwd)/db:/app/db \
--name timetracker \
gitea.fx-se.de/maggot/timetracker:latest
Oder mit docker-compose.yml:
version: '3.8'
services:
app:
image: gitea.fx-se.de/maggot/timetracker:latest
ports:
- "3000:3000"
volumes:
- ./db:/app/db
restart: unless-stopped
# Starten
docker-compose up -d
# Logs
docker-compose logs -f
# Stoppen
docker-compose down
# Stoppen + Daten löschen
docker-compose down -v
App läuft auf: http://localhost:3000
🔨 Option 2: Docker (manuell bauen)
# Repository klonen
git clone https://gitea.fx-se.de/maggot/timetracker.git
cd timetracker
# Image bauen
docker build -t zeiterfassung .
# Container starten (mit Daten-Persistenz)
docker run -p 3000:3000 -v $(pwd)/db:/app/db zeiterfassung
💻 Option 3: Lokal (ohne Docker)
Voraussetzungen: Node.js 18+
# Repository klonen
git clone https://gitea.fx-se.de/maggot/timetracker.git
cd timetracker
npm install
npm start
App läuft auf: http://localhost:3000
📤 Export-Funktionen
Die App bietet mehrere Export-Modi für verschiedene Anwendungsfälle:
PDF-Export 📄
Monats-Export:
- Klicke auf "PDF Export" in der Monatsansicht
- Exportiert alle Einträge des aktuellen Monats
- Professionelles Layout mit:
- Mitarbeiter-Informationen (Name, Personal-Nr.)
- Monatsstatistiken (Soll/Ist/Saldo)
- Vollständige Tabelle aller Einträge
- Deutsche Formatierung
Bulk-Export:
- Aktiviere Bulk-Modus und wähle Einträge aus
- Klicke auf "PDF exportieren"
- Exportiert nur ausgewählte Einträge
- Gleiche Formatierung wie Monats-Export
CSV-Export 📊
Die App bietet zwei CSV-Export-Modi über die Filter-Ansicht:
Export Alle (📥) Exportiert alle Einträge im gewählten Zeitraum.
Spalten:
Datum;Start;Ende;Pause (min);Netto (h);Arbeitsort;Abweichung (h)
Beispiel:
2025-10-21;08:00;17:00;30;8,50;Büro;+0,50
2025-10-22;09:00;18:00;45;8,25;Home;+0,25
2025-10-23;08:30;16:30;30;7,50;Büro;-0,50
Export Abweichungen (⚠️) Exportiert nur Tage mit ≠ 8,0 Stunden.
Zweck: Gleitzeit-Nachweise für HR (nur relevante Über-/Unterschreitungen)
Beispiel:
2025-10-21;08:00;18:30;45;9,75;Büro;+1,75
2025-10-23;09:00;15:30;30;6,00;Home;-2,00
(Tage mit exakt 8,0h fehlen)
Format: Semikolon-getrennt, Komma-Dezimal, YYYY-MM-DD Datum
Datenbank-Backup 💾
Export:
- Gehe zu Einstellungen
- Klicke auf "Datenbank exportieren"
- JSON-Datei mit Zeitstempel wird heruntergeladen
- Enthält: Alle Einträge + Einstellungen + Version
Import:
- Gehe zu Einstellungen
- Klicke auf "Datenbank importieren"
- Wähle JSON-Backup-Datei
- Bestätige Überschreiben der Daten
- Alte Daten werden gelöscht, neue importiert
Verwendung:
- Regelmäßige Backups vor Updates
- Migration zwischen Instanzen/Servern
- Datensicherung
📡 API-Endpunkte
Einträge
GET /api/entries?from=YYYY-MM-DD&to=YYYY-MM-DD- Einträge abrufenPOST /api/entries- Eintrag erstellenPUT /api/entries/:id- Eintrag aktualisierenDELETE /api/entries/:id- Eintrag löschen
Einstellungen
GET /api/settings/:key- Setting abrufenPOST /api/settings- Setting speichern{key, value}GET /api/settings- Alle Settings
Datenbank-Management
GET /api/database/export- Vollständigen DB-Export als JSONPOST /api/database/import- DB-Import aus JSONDELETE /api/entries/all- Alle Einträge löschen (für Import)
🔄 CI/CD & Deployment
Die App verwendet Gitea Actions für automatische Builds und Deployments:
Automatische Docker Builds:
- Bei Push zu
main/masterBranch - Nur bei relevanten Änderungen (Server, Frontend, Dependencies)
- Ignoriert README, Workflow-Änderungen
- Erstellt Images mit Tags:
latest+ Commit-SHA
Container Registry:
- Gehostet auf Gitea:
gitea.fx-se.de/maggot/timetracker - Authentifizierung via Personal Access Token
- Automatischer Push nach erfolgreichem Build
Workflow-Konfiguration:
# Triggert nur bei:
- server.js, package.json, Dockerfile
- db/**, public/**
- Ignoriert: *.md, .gitea/workflows/**, .gitignore
Siehe: .gitea/workflows/docker-build.yml für Details
🛠️ Entwicklung
Architektur: Single-Page Application (SPA) mit REST-API Backend
Tech-Details:
- Modulare Frontend-Architektur (5 separate JS-Dateien)
- Flatpickr für Touch-optimierte Picker (auch in Tabellen-Inline-Edit)
- Lucide Icons für Symbolik
- jsPDF + autoTable für PDF-Generierung
- SQLite für dateibasierte Persistenz
- Server-seitige Berechnungen für Datenintegrität
- Responsive Design (Tailwind CSS via CDN)
Datenpersistenz:
- SQLite-Datenbank:
db/timetracker.db - Automatische Migrations beim Start
- Volume-Mounting in Docker für Persistenz
- JSON-basierte Backups für Migration
Code-Organisation:
state.js: Globaler Application Stateutils.js: Hilfsfunktionen (Datum, Zeit, Format)holidays.js: Feiertagsberechnung (16 Bundesländer)api.js: Backend-Kommunikationmain.js: Hauptlogik, UI, Event-Handler
📄 Lizenz
MIT License - siehe LICENSE Datei
Entwickelt mit ❤️ für deutsches Arbeitszeitrecht