school-timetracker/README.md

773 lines
18 KiB
Markdown

# 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](#überblick)
- [Funktionen](#funktionen)
- [Technologie-Stack](#technologie-stack)
- [Voraussetzungen](#voraussetzungen)
- [Installation](#installation)
- [Konfiguration](#konfiguration)
- [Verwendung](#verwendung)
- [API-Dokumentation](#api-dokumentation)
- [Architektur](#architektur)
- [Sicherheit](#sicherheit)
- [Backup & Wartung](#backup--wartung)
- [Fehlerbehebung](#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: 1800h)
- 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**
```bash
git clone <repository-url>
cd zeiterfassung
```
2. **Umgebungsvariablen konfigurieren**
```bash
cp .env.example .env
nano .env
```
Wichtige Variablen in `.env`:
```env
PORT=8080
DB_PATH=/data/timetracking.db
JWT_SECRET=ihr-sicheres-geheimnis-hier-ändern
TZ=Europe/Berlin
```
3. **Anwendung starten**
```bash
docker-compose up -d
```
4. **Anwendung aufrufen**
```
http://localhost:8080
```
**Standard-Anmeldedaten:**
- Benutzername: `admin`
- Passwort: `admin123`
⚠️ **WICHTIG**: Ändern Sie das Admin-Passwort sofort nach der ersten Anmeldung!
### Option 2: Lokale Entwicklung
1. **Backend kompilieren**
```bash
go mod download
go build -o timetracking
```
2. **Frontend kompilieren**
```bash
cd static
elm make Main.elm --output=elm.js --optimize
cd ..
```
3. **Umgebungsvariablen setzen**
```bash
export PORT=8080
export DB_PATH=./timetracking.db
export JWT_SECRET=development-secret
```
4. **Anwendung starten**
```bash
./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** |
| `TZ` | Zeitzone | `Europe/Berlin` | Nein |
| `ENVIRONMENT` | `production` für HTTPS-Redirect | - | Nein |
### Docker-Volumes
Das Docker-Setup erstellt ein persistentes Volume für die Datenbank:
```yaml
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/admin123)
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: 1800h)
- 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:**
```json
{
"username": "admin",
"password": "admin123"
}
```
**Response:**
```json
{
"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:**
```json
{
"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`
```sql
id INTEGER PRIMARY KEY
username TEXT UNIQUE NOT NULL
password TEXT NOT NULL (bcrypt-hashed)
is_admin BOOLEAN DEFAULT 0
yearly_hours REAL DEFAULT 1800.0
created_at DATETIME
```
#### Tabelle: `schedules`
```sql
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`
```sql
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`
```sql
id INTEGER PRIMARY KEY
name TEXT UNIQUE
start_date DATE
end_date DATE
is_active BOOLEAN DEFAULT 0
created_at DATETIME
```
#### Tabelle: `audit_logs`
```sql
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)
```bash
openssl rand -base64 64
```
2. **HTTPS verwenden**: In Produktion immer TLS/SSL aktivieren
```env
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
```bash
go get -u ./...
docker-compose pull
```
## 💾 Backup & Wartung
### Datenbank-Backup
**Docker-Setup:**
```bash
# 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:**
```bash
# 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`:
```bash
#!/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:
```yaml
services:
timetracking:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
```
### Updates durchführen
```bash
# 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
```bash
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:**
```bash
# 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:
```bash
# 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:**
```bash
# 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:
```bash
cd static
elm make Main.elm --output=elm.js --optimize
```
### Datenbankfehler nach Update
**Problem**: "Database schema error"
**Lösung:**
```bash
# 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 1800.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.0.0
**Letztes Update**: November 2024
**Entwickelt für**: Schulen zur Verwaltung von Flexistunden pädagogischer Mitarbeiter