- Added import of Schedules - Added export for schedule table - Added import of logo - Added password change to users - improved ui/ux |
||
|---|---|---|
| backend | ||
| frontend | ||
| docker-compose.yml | ||
| Dockerfile | ||
| README.md | ||
Zeiterfassungssystem für pädagogische Mitarbeiter
Eine vollständige Webanwendung zur Erfassung und Verwaltung von Flexistunden für pädagogische Mitarbeiter (PM) an Schulen.
📋 Inhaltsverzeichnis
- Überblick
- Funktionen
- Technologie-Stack
- Voraussetzungen
- Installation
- Konfiguration
- Verwendung
- API-Dokumentation
- Architektur
- Sicherheit
- Backup & Wartung
- Fehlerbehebung
🎯 Überblick
Diese Anwendung wurde entwickelt, um die Erfassung von Flexistunden (zusätzliche Arbeitsstunden) für pädagogische Mitarbeiter an Schulen zu vereinfachen. Sie ermöglicht:
- Mitarbeitern: Wöchentliche Zeiterfassung anhand eines vorkonfigurierten Stundenplans
- Administratoren: Vollständige Verwaltung von Benutzern, Stundenplänen, Schuljahren und Zeiteinträgen
Das System arbeitet mit ISO-Kalenderwochen und unterstützt schuljahrbezogene Auswertungen.
✨ Funktionen
Für Mitarbeiter
- Wochenbasierte Zeiterfassung: Auswahl der gearbeiteten Zeiten aus dem Stundenplan
- Kalenderwochen-Navigation: Einfaches Vor- und Zurückblättern zwischen Wochen
- Jahresübersicht: Anzeige der geleisteten vs. Soll-Arbeitsstunden
- Responsive Design: Optimiert für Desktop, Tablet und Mobile
Für Administratoren
-
Benutzerverwaltung:
- Benutzer anlegen, bearbeiten und löschen
- Jahresarbeitsstunden pro Benutzer festlegen (Standard: 60h)
- Passwörter zurücksetzen
-
Stundenplan-Management:
- Wochenstundenplan mit Unterrichts- und Pausenzeiten erstellen
- Unterrichtsstunden und Pausen unterscheiden
- Zeiten mit Titeln versehen (z.B. "Mathematik", "Pause")
-
Schuljahrverwaltung:
- Schuljahre mit Start- und Enddatum definieren
- Aktives Schuljahr setzen
- Jahresberechnungen basierend auf aktivem Schuljahr
-
Zeiteintrags-Verwaltung:
- Alle Zeiteinträge einsehen und bearbeiten
- Manuelle Stundeneintragungen (positiv = Abzug, negativ = Hinzurechnung)
- Einzelne Einträge korrigieren oder löschen
-
Berichtswesen:
- Jahresübersicht aller Mitarbeiter
- PDF-Export der Jahresübersicht
- Wochenweise Stundenauswertung
🛠 Technologie-Stack
Frontend
- Elm 0.19: Funktionale Programmiersprache für type-safe UI
- Bulma CSS: Modernes CSS-Framework
- Font Awesome: Icons
- LocalStorage: Client-seitige Datenpersistenz für Authentifizierung
Backend
- Go (Golang): Performante Backend-Sprache
- Echo Framework: Web-Framework für Go
- SQLite: Embedded SQL-Datenbank
- JWT: Token-basierte Authentifizierung
- bcrypt: Passwort-Hashing
- gofpdf: PDF-Generierung
Deployment
- Docker: Containerisierung
- Docker Compose: Orchestrierung
📦 Voraussetzungen
Für Docker-Deployment (empfohlen)
- Docker (Version 20.10+)
- Docker Compose (Version 1.29+)
Für lokale Entwicklung
- Go 1.21+
- Elm 0.19
- Node.js 16+ (für Elm-Tooling)
- SQLite3
🚀 Installation
Option 1: Docker Compose (Produktion)
- Repository klonen
git clone <repository-url>
cd zeiterfassung
- Umgebungsvariablen konfigurieren
cp .env.example .env
nano .env
Wichtige Variablen in .env:
PORT=8080
DB_PATH=/data/timetracking.db
JWT_SECRET=ihr-sicheres-geheimnis-hier-ändern
TZ=Europe/Berlin
- Anwendung starten
docker-compose up -d
- Anwendung aufrufen
http://localhost:8080
Standard-Anmeldedaten:
- Benutzername:
admin - Passwort: Das in
docker-compose.ymlunterINITIAL_ADMIN_PASSWORDfestgelegte Passwort.
⚠️ WICHTIG: Ändern Sie das Admin-Passwort sofort nach der ersten Anmeldung!
Option 2: Lokale Entwicklung
- Backend kompilieren
go mod download
go build -o timetracking
- Frontend kompilieren
cd static
elm make Main.elm --output=elm.js --optimize
cd ..
- Umgebungsvariablen setzen
export PORT=8080
export DB_PATH=./timetracking.db
export JWT_SECRET=development-secret
- Anwendung starten
./timetracking
⚙️ Konfiguration
Umgebungsvariablen
| Variable | Beschreibung | Standard | Erforderlich |
|---|---|---|---|
PORT |
HTTP-Server Port | 8080 |
Nein |
DB_PATH |
Pfad zur SQLite-Datenbank | ./timetracking.db |
Nein |
JWT_SECRET |
Geheimnis für JWT-Token | - | Ja |
INITIAL_ADMIN_PASSWORD |
Initiales Passwort für den Admin-Benutzer | changeme |
Ja |
TZ |
Zeitzone | Europe/Berlin |
Nein |
ENVIRONMENT |
production für HTTPS-Redirect und striktes CORS |
development |
Nein |
CORS_ALLOWED_ORIGINS |
Komma-getrennte Liste von erlaubten Origins | * (in dev), http://localhost:8080 (in prod) |
Nein |
Docker-Volumes
Das Docker-Setup erstellt ein persistentes Volume für die Datenbank:
volumes:
timetracking-data:
driver: local
Die Datenbank wird unter /data/timetracking.db im Container gespeichert.
📖 Verwendung
Ersteinrichtung als Administrator
-
Anmelden mit den Standard-Credentials (admin/das initiale Passwort aus der Konfiguration)
-
Admin-Passwort ändern:
- Gehe zu "Benutzer" Tab
- Klicke auf "PW Reset" beim Admin-Benutzer
- Neues sicheres Passwort eingeben
-
Schuljahr erstellen:
- Wechsle zum "Schuljahre" Tab
- Erstelle ein Schuljahr (z.B. "2024/2025")
- Startdatum: 01.08.2024
- Enddatum: 31.07.2025
- Klicke auf "Aktivieren"
-
Stundenplan erstellen:
- Wechsle zum "Stundenplan" Tab
- Füge Unterrichtsstunden hinzu:
- Wochentag auswählen
- Start- und Endzeit eingeben
- Typ: "Unterricht" oder "Pause"
- Titel vergeben (z.B. "Mathematik 1a")
-
Mitarbeiter anlegen:
- Wechsle zum "Benutzer" Tab
- "Benutzer anlegen"
- Benutzername und Passwort eingeben
- Jahresarbeitsstunden festlegen (Standard: 60h)
- Admin-Rechte nur für weitere Administratoren
Zeiterfassung als Mitarbeiter
-
Anmelden mit persönlichen Zugangsdaten
-
Wochenansicht:
- Zeigt aktuelle Kalenderwoche mit Datumsbereich
- Navigation: "Vorherige Woche" / "Nächste Woche"
-
Stunden erfassen:
- Klicke auf die Zeitslots, die du gearbeitet hast
- Ausgewählte Zeiten werden grün markiert
- Klicke "Speichern" zum Übernehmen
-
Woche bearbeiten:
- Falls bereits erfasst, erscheint "Bearbeiten"-Button
- Aktiviert Bearbeitungsmodus
- "Einträge löschen" entfernt alle Einträge der Woche
- Neue Auswahl treffen und "Änderungen speichern"
-
Jahresübersicht prüfen:
- Unten auf der Seite: "Jahresgesamtzeit"
- Zeigt: Soll-Stunden, Geleistete Stunden, Verbleibende Stunden
- Fortschrittsbalken visualisiert den Status
Administrative Aufgaben
Manuelle Stundeneintragung
Für Korrekturen oder Sonderfälle:
- Gehe zu "Zeiteinträge" Tab
- Sektion "Manuelle Stundeneintragung"
- Mitarbeiter auswählen
- Datum eingeben
- Stunden eingeben:
- Positive Werte (z.B.
2.5): Werden abgezogen (z.B. Krankheit, Urlaub) - Negative Werte (z.B.
-3.0): Werden hinzugerechnet (z.B. Nachholung, Sondereinsatz)
- Positive Werte (z.B.
Zeiteinträge bearbeiten
- Gehe zu "Zeiteinträge" Tab
- Liste aller Einträge mit Bearbeitungsmöglichkeit
- "Bearbeiten" klicken:
- Datum ändern
- Start-/Endzeit anpassen
- Typ ändern (Unterricht/Pause/Manuell)
- Speichern oder Löschen
PDF-Export
- Gehe zu "Zeiteinträge" Tab
- Sektion "Jahresübersicht"
- Klicke "PDF exportieren"
- PDF enthält:
- Schuljahrname und Zeitraum
- Alle Mitarbeiter mit Soll/Ist/Differenz
- Generierungsdatum
🔌 API-Dokumentation
Authentifizierung
Alle geschützten Endpunkte erfordern einen JWT-Token im Header:
Authorization: Bearer <token>
Öffentliche Endpunkte
POST /api/login
Benutzer-Anmeldung
Request:
{
"username": "admin",
"password": "<your-initial-admin-password>"
}
Response:
{
"token": "eyJhbGc...",
"username": "admin",
"is_admin": true
}
Geschützte Endpunkte (Benutzer)
GET /api/schedules
Alle Stundenpläne abrufen
GET /api/my-time-entries
Eigene Zeiteinträge abrufen
POST /api/time-entries/batch
Mehrere Zeiteinträge auf einmal erstellen
Request:
{
"entries": [
{
"schedule_id": 1,
"date": "2024-11-04",
"type": "lesson",
"start_time": "08:00",
"end_time": "09:00"
}
]
}
DELETE /api/my-time-entries/week?year=2024&week=45
Alle eigenen Einträge einer Woche löschen
GET /api/week-dates?year=2024&week=45
Datumsbereich einer Kalenderwoche abrufen
GET /api/week-has-entries?year=2024&week=45
Prüfen, ob für eine Woche bereits Einträge existieren
GET /api/yearly-hours-summary
Jahresübersicht für alle Benutzer
GET /api/my-info
Eigene Benutzerinformationen abrufen
GET /api/school-year/active
Aktives Schuljahr abrufen
Admin-Endpunkte
Stundenplan-Verwaltung
POST /api/admin/schedules- Stundenplan erstellenDELETE /api/admin/schedules/delete?id=1- Stundenplan löschen
Benutzerverwaltung
POST /api/admin/users- Benutzer erstellenGET /api/admin/users/list- Alle Benutzer auflistenPUT /api/admin/users/:id- Benutzer bearbeiten (Arbeitsstunden)PUT /api/admin/users/:id/reset-password- Passwort zurücksetzenDELETE /api/admin/users/delete?id=2- Benutzer löschen
Zeiteintrags-Verwaltung
GET /api/admin/time-entries- Alle ZeiteinträgePUT /api/admin/time-entries/:id- Zeiteintrag bearbeitenDELETE /api/admin/time-entries/:id- Zeiteintrag löschenPOST /api/admin/time-entry- Manueller Zeiteintrag
Schuljahrverwaltung
GET /api/admin/school-years- Alle SchuljahrePOST /api/admin/school-years- Schuljahr erstellenPUT /api/admin/school-years/:id/activate- Schuljahr aktivierenDELETE /api/admin/school-years/:id- Schuljahr löschen
Berichte
GET /api/admin/yearly-summary/pdf- Jahresübersicht als PDF
🏗 Architektur
Backend-Struktur
.
├── main.go # Einstiegspunkt, Server-Setup
├── handlers.go # HTTP-Handler für alle Endpunkte
├── middleware.go # JWT-Auth, Admin-Check, Rate-Limiting
├── database.go # Datenbanklogik und Queries
├── models.go # Datenstrukturen
├── pdf.go # PDF-Generierung
├── docker-compose.yml # Docker-Orchestrierung
└── Dockerfile # Container-Image
Frontend-Struktur
static/
├── Main.elm # Elm-Hauptanwendung
│ ├── Model # Anwendungszustand
│ ├── Update # Zustandsänderungen
│ ├── View # UI-Rendering
│ └── Subscriptions # Event-Handling
├── index.html # HTML-Wrapper
└── elm.js # Kompilierte Elm-Anwendung
Datenbank-Schema
Tabelle: users
id INTEGER PRIMARY KEY
username TEXT UNIQUE NOT NULL
password TEXT NOT NULL (bcrypt-hashed)
is_admin BOOLEAN DEFAULT 0
yearly_hours REAL DEFAULT 60.0
created_at DATETIME
Tabelle: schedules
id INTEGER PRIMARY KEY
day_of_week INTEGER (0=Montag, 4=Freitag)
start_time TEXT (HH:MM)
end_time TEXT (HH:MM)
type TEXT (lesson/break)
title TEXT
created_at DATETIME
Tabelle: time_entries
id INTEGER PRIMARY KEY
user_id INTEGER (FK -> users)
schedule_id INTEGER (FK -> schedules)
date TEXT (YYYY-MM-DD)
type TEXT (lesson/break/manual)
start_time TEXT
end_time TEXT
created_at DATETIME
Tabelle: school_years
id INTEGER PRIMARY KEY
name TEXT UNIQUE
start_date DATE
end_date DATE
is_active BOOLEAN DEFAULT 0
created_at DATETIME
Tabelle: audit_logs
id INTEGER PRIMARY KEY
user_id INTEGER
action TEXT
details TEXT
created_at DATETIME
Stundenberechnung
Die Anwendung berechnet Arbeitsstunden nach folgenden Regeln:
- Unterrichtsstunden (
type: "lesson"): 1,0 Stunde (fest) - Pausen (
type: "break"): Differenz zwischen End- und Startzeit - Manuelle Einträge (
type: "manual"):- Positive Werte werden abgezogen
- Negative Werte werden hinzugerechnet
Beispiel:
Unterricht 08:00-09:00 → 1,0h
Pause 09:00-09:15 → 0,25h
Manueller Eintrag: 2.5 → -2,5h (Abzug)
Manueller Eintrag: -1.0 → +1,0h (Zuschlag)
ISO-Kalenderwochen
Die Anwendung verwendet ISO 8601 Kalenderwochen:
- Woche beginnt am Montag
- Erste Woche des Jahres enthält den 4. Januar
- 52 oder 53 Wochen pro Jahr
🔒 Sicherheit
Implementierte Sicherheitsmaßnahmen
- Passwort-Hashing: bcrypt mit Default-Cost (10 Runden)
- JWT-Authentifizierung: HMAC-SHA256 mit 2h Ablaufzeit
- CORS-Protection: Konfigurierbare Origins
- Rate Limiting: 5 Login-Versuche pro Minute pro IP
- SQL-Injection-Schutz: Prepared Statements
- Admin-Schutz: Admin-Benutzer (ID=1) kann nicht gelöscht werden
- Input-Validierung: Server- und clientseitig
Best Practices
-
JWT_SECRET ändern: Verwenden Sie einen starken, zufälligen String (64+ Zeichen)
openssl rand -base64 64 -
HTTPS verwenden: In Produktion immer TLS/SSL aktivieren
ENVIRONMENT=production -
Regelmäßige Backups: Sichern Sie die Datenbank täglich
-
Starke Passwörter: Mindestens 12 Zeichen, Mix aus Groß-/Kleinbuchstaben, Zahlen, Sonderzeichen
-
Updates: Halten Sie Dependencies aktuell
go get -u ./... docker-compose pull
💾 Backup & Wartung
Datenbank-Backup
Docker-Setup:
# Backup erstellen
docker exec school-timetracking sqlite3 /data/timetracking.db ".backup '/data/backup-$(date +%Y%m%d).db'"
docker cp school-timetracking:/data/backup-$(date +%Y%m%d).db ./backups/
# Backup wiederherstellen
docker cp ./backups/backup-20241108.db school-timetracking:/data/timetracking.db
docker-compose restart
Lokales Setup:
# Backup
sqlite3 timetracking.db ".backup 'backup-$(date +%Y%m%d).db'"
# Wiederherstellen
cp backup-20241108.db timetracking.db
Automatisches Backup (Cron)
Erstellen Sie ein Backup-Script backup.sh:
#!/bin/bash
BACKUP_DIR="/path/to/backups"
DATE=$(date +%Y%m%d-%H%M%S)
docker exec school-timetracking sqlite3 /data/timetracking.db ".backup '/data/backup-$DATE.db'"
docker cp school-timetracking:/data/backup-$DATE.db $BACKUP_DIR/
# Alte Backups löschen (älter als 30 Tage)
find $BACKUP_DIR -name "backup-*.db" -mtime +30 -delete
Crontab-Eintrag (täglich um 3 Uhr):
0 3 * * * /path/to/backup.sh
Log-Rotation
Docker Compose Log-Größe begrenzen:
services:
timetracking:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Updates durchführen
# Repository aktualisieren
git pull
# Neue Images bauen
docker-compose build
# Container neu starten
docker-compose down
docker-compose up -d
# Logs prüfen
docker-compose logs -f
🐛 Fehlerbehebung
Anwendung startet nicht
Problem: Container startet nicht
docker-compose logs timetracking
Häufige Ursachen:
JWT_SECRETnicht gesetzt → Setzen Sie die Variable in.env- Port 8080 bereits belegt → Ändern Sie
PORTin.env - Datenbank-Berechtigungen → Prüfen Sie Volume-Permissions
Login funktioniert nicht
Problem: "Invalid credentials" trotz korrekten Passworts
Lösung:
# Admin-Passwort zurücksetzen
docker exec -it school-timetracking /bin/sh
sqlite3 /data/timetracking.db
# In SQLite:
UPDATE users SET password = '$2a$10$...' WHERE username = 'admin';
.exit
Generieren Sie einen neuen bcrypt-Hash:
# Mit Go
echo -n 'neues-passwort' | go run -e 'import "golang.org/x/crypto/bcrypt"; pass, _ := bcrypt.GenerateFromPassword([]byte(os.Args[1]), bcrypt.DefaultCost); fmt.Println(string(pass))'
Zeiteinträge werden nicht gespeichert
Problem: Fehler beim Speichern von Zeiteinträgen
Prüfen:
- Browser-Konsole auf JavaScript-Fehler prüfen
- Backend-Logs prüfen:
docker-compose logs -f - JWT-Token gültig? → Neu anmelden
- Datenbank-Speicherplatz verfügbar?
PDF-Export schlägt fehl
Problem: "Failed to generate PDF"
Lösung:
# Container-Logs prüfen
docker-compose logs timetracking | grep -i pdf
# Häufig: Fehlende Schriftarten
# → Rebuilden Sie das Image
docker-compose build --no-cache
Responsive Layout funktioniert nicht
Problem: Mobile Ansicht nicht korrekt
Lösung:
- Browser-Cache leeren
- Elm neu kompilieren:
cd static elm make Main.elm --output=elm.js --optimize
Datenbankfehler nach Update
Problem: "Database schema error"
Lösung:
# Backup erstellen
docker cp school-timetracking:/data/timetracking.db ./backup-pre-migration.db
# Migration manuell durchführen
docker exec -it school-timetracking sqlite3 /data/timetracking.db
# Fehlende Spalten hinzufügen (Beispiel)
ALTER TABLE users ADD COLUMN yearly_hours REAL DEFAULT 60.0;
.exit
📝 Häufig gestellte Fragen (FAQ)
Q: Wie ändere ich die Standard-Arbeitsstunden? A: Als Admin unter "Benutzer" → Benutzer auswählen → "Arbeitszeit" klicken → Neue Stundenzahl eingeben.
Q: Können Mitarbeiter vergangene Wochen bearbeiten? A: Ja, über die Wochen-Navigation können alle Wochen bearbeitet werden (sofern im aktuellen Schuljahr).
Q: Wie funktioniert die Schuljahr-Berechnung? A: Das System berechnet Stunden nur für Einträge innerhalb des aktiven Schuljahres (Start- bis Enddatum).
Q: Was passiert bei 53-Wochen-Jahren? A: Das System unterstützt ISO-Kalenderwochen inklusive Woche 53 automatisch.
Q: Kann ich mehrere Schuljahre parallel nutzen? A: Es kann immer nur ein Schuljahr aktiv sein. Berechnungen basieren auf diesem Zeitraum.
Q: Wie funktionieren negative Stunden? A: Negative Werte bei manuellen Einträgen werden zum Stundenkonto hinzugerechnet (für Zusatzleistungen).
📄 Lizenz
Todo
👥 Kontakt & Support
Todo
Version: 1.5.0
Letztes Update: November 2025
Entwickelt für: Schulen zur Verwaltung von Flexistunden pädagogischer Mitarbeiter