No description
Find a file
Patryk Hegenberg 55b36e5e62 fix: fix while deleting timeentries for whole week
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.
2025-11-09 23:22:49 +01:00
backend fix: fix while deleting timeentries for whole week 2025-11-09 23:22:49 +01:00
frontend feat: improve app security and error handling 2025-11-09 12:13:47 +01:00
docker-compose.yml feat: added all features for seconde release candidate 2025-11-05 23:39:51 +01:00
Dockerfile feat: update all and add all features for version 1.0 2025-11-05 14:15:38 +01:00
README.md feat: improve app security and error handling 2025-11-09 12:13:47 +01:00

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

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)

  1. Repository klonen
git clone <repository-url>
cd zeiterfassung
  1. 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
  1. Anwendung starten
docker-compose up -d
  1. Anwendung aufrufen
http://localhost:8080

Standard-Anmeldedaten:

  • Benutzername: admin
  • Passwort: Das in docker-compose.yml unter INITIAL_ADMIN_PASSWORD festgelegte Passwort.

⚠️ WICHTIG: Ändern Sie das Admin-Passwort sofort nach der ersten Anmeldung!

Option 2: Lokale Entwicklung

  1. Backend kompilieren
go mod download
go build -o timetracking
  1. Frontend kompilieren
cd static
elm make Main.elm --output=elm.js --optimize
cd ..
  1. Umgebungsvariablen setzen
export PORT=8080
export DB_PATH=./timetracking.db
export JWT_SECRET=development-secret
  1. 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

  1. Anmelden mit den Standard-Credentials (admin/das initiale Passwort aus der Konfiguration)

  2. Admin-Passwort ändern:

    • Gehe zu "Benutzer" Tab
    • Klicke auf "PW Reset" beim Admin-Benutzer
    • Neues sicheres Passwort eingeben
  3. Schuljahr erstellen:

    • Wechsle zum "Schuljahre" Tab
    • Erstelle ein Schuljahr (z.B. "2024/2025")
    • Startdatum: 01.08.2024
    • Enddatum: 31.07.2025
    • Klicke auf "Aktivieren"
  4. 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")
  5. 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

  1. Anmelden mit persönlichen Zugangsdaten

  2. Wochenansicht:

    • Zeigt aktuelle Kalenderwoche mit Datumsbereich
    • Navigation: "Vorherige Woche" / "Nächste Woche"
  3. Stunden erfassen:

    • Klicke auf die Zeitslots, die du gearbeitet hast
    • Ausgewählte Zeiten werden grün markiert
    • Klicke "Speichern" zum Übernehmen
  4. 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"
  5. 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:

  1. Gehe zu "Zeiteinträge" Tab
  2. Sektion "Manuelle Stundeneintragung"
  3. Mitarbeiter auswählen
  4. Datum eingeben
  5. 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)

Zeiteinträge bearbeiten

  1. Gehe zu "Zeiteinträge" Tab
  2. Liste aller Einträge mit Bearbeitungsmöglichkeit
  3. "Bearbeiten" klicken:
    • Datum ändern
    • Start-/Endzeit anpassen
    • Typ ändern (Unterricht/Pause/Manuell)
  4. Speichern oder Löschen

PDF-Export

  1. Gehe zu "Zeiteinträge" Tab
  2. Sektion "Jahresübersicht"
  3. Klicke "PDF exportieren"
  4. 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 erstellen
  • DELETE /api/admin/schedules/delete?id=1 - Stundenplan löschen

Benutzerverwaltung

  • POST /api/admin/users - Benutzer erstellen
  • GET /api/admin/users/list - Alle Benutzer auflisten
  • PUT /api/admin/users/:id - Benutzer bearbeiten (Arbeitsstunden)
  • PUT /api/admin/users/:id/reset-password - Passwort zurücksetzen
  • DELETE /api/admin/users/delete?id=2 - Benutzer löschen

Zeiteintrags-Verwaltung

  • GET /api/admin/time-entries - Alle Zeiteinträge
  • PUT /api/admin/time-entries/:id - Zeiteintrag bearbeiten
  • DELETE /api/admin/time-entries/:id - Zeiteintrag löschen
  • POST /api/admin/time-entry - Manueller Zeiteintrag

Schuljahrverwaltung

  • GET /api/admin/school-years - Alle Schuljahre
  • POST /api/admin/school-years - Schuljahr erstellen
  • PUT /api/admin/school-years/:id/activate - Schuljahr aktivieren
  • DELETE /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:

  1. Unterrichtsstunden (type: "lesson"): 1,0 Stunde (fest)
  2. Pausen (type: "break"): Differenz zwischen End- und Startzeit
  3. 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

  1. Passwort-Hashing: bcrypt mit Default-Cost (10 Runden)
  2. JWT-Authentifizierung: HMAC-SHA256 mit 2h Ablaufzeit
  3. CORS-Protection: Konfigurierbare Origins
  4. Rate Limiting: 5 Login-Versuche pro Minute pro IP
  5. SQL-Injection-Schutz: Prepared Statements
  6. Admin-Schutz: Admin-Benutzer (ID=1) kann nicht gelöscht werden
  7. Input-Validierung: Server- und clientseitig

Best Practices

  1. JWT_SECRET ändern: Verwenden Sie einen starken, zufälligen String (64+ Zeichen)

    openssl rand -base64 64
    
  2. HTTPS verwenden: In Produktion immer TLS/SSL aktivieren

    ENVIRONMENT=production
    
  3. Regelmäßige Backups: Sichern Sie die Datenbank täglich

  4. Starke Passwörter: Mindestens 12 Zeichen, Mix aus Groß-/Kleinbuchstaben, Zahlen, Sonderzeichen

  5. 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_SECRET nicht gesetzt → Setzen Sie die Variable in .env
  • Port 8080 bereits belegt → Ändern Sie PORT in .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:

  1. Browser-Konsole auf JavaScript-Fehler prüfen
  2. Backend-Logs prüfen: docker-compose logs -f
  3. JWT-Token gültig? → Neu anmelden
  4. 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