old entries have not been deleted, before new entries have been added. This has been fixed. Also manual entries by administrators are know protected and can only be deleted by an administrator. |
||
|---|---|---|
| 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.1.0
Letztes Update: November 2025
Entwickelt für: Schulen zur Verwaltung von Flexistunden pädagogischer Mitarbeiter