Add production build optimizations to Vite configuration; set target, output directory, and minification options for improved performance

This commit is contained in:
Torsten Schulz (local)
2025-10-18 21:19:07 +02:00
parent bda61c0ed4
commit 06a65e9130
16 changed files with 4210 additions and 1 deletions

345
scripts/README.md Normal file
View File

@@ -0,0 +1,345 @@
# TimeClock v3 - Server-Management Scripts
Dieses Verzeichnis enthält hilfreiche Wartungs- und Management-Scripts für den Produktions-Server.
## Übersicht
| Script | Beschreibung | Verwendung |
|--------|--------------|------------|
| `backup-timeclock.sh` | Erstellt automatische Datenbank-Backups | Täglich per Cronjob |
| `health-check.sh` | Überwacht API-Verfügbarkeit | Alle 5 Min per Cronjob |
| `restore-backup.sh` | Stellt Datenbank-Backup wieder her | Manuell bei Bedarf |
---
## 1. backup-timeclock.sh
Erstellt automatische komprimierte Backups der MySQL-Datenbank.
### Installation
```bash
# Auf den Server kopieren
sudo cp scripts/backup-timeclock.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/backup-timeclock.sh
# Cronjob einrichten (täglich um 2 Uhr)
sudo crontab -e
```
Füge folgende Zeile hinzu:
```cron
0 2 * * * /usr/local/bin/backup-timeclock.sh >> /var/log/timeclock/backup.log 2>&1
```
### Manuell ausführen
```bash
/usr/local/bin/backup-timeclock.sh
```
### Features
- ✅ Automatische Datenbank-Backups mit Kompression
- ✅ Konfigurierbare Retention (Standard: 30 Tage)
- ✅ Optional: Code-Backups
- ✅ Optional: Remote-Backup per rsync
- ✅ Optional: E-Mail-Benachrichtigungen
- ✅ Backup-Statistiken
### Konfiguration
Bearbeite die Variablen am Anfang des Scripts:
```bash
BACKUP_DIR="/var/backups/timeclock"
RETENTION_DAYS=30
BACKUP_CODE=false # true für Code-Backups
REMOTE_BACKUP=false # true für Remote-Backup
SEND_EMAIL=false # true für E-Mail-Benachrichtigung
```
### Backup-Dateien
Backups werden gespeichert unter:
- Datenbank: `/var/backups/timeclock/timeclock_db_YYYYMMDD_HHMMSS.sql.gz`
- Code: `/var/backups/timeclock/timeclock_code_YYYYMMDD_HHMMSS.tar.gz`
---
## 2. health-check.sh
Überwacht die Verfügbarkeit des Backend-API und startet den Service bei Bedarf automatisch neu.
### Installation
```bash
# Auf den Server kopieren
sudo cp scripts/health-check.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/health-check.sh
# Cronjob einrichten (alle 5 Minuten)
crontab -e
```
Füge folgende Zeile hinzu:
```cron
*/5 * * * * /usr/local/bin/health-check.sh >> /var/log/timeclock/health-check.log 2>&1
```
### Manuell ausführen
```bash
/usr/local/bin/health-check.sh
```
### Features
- ✅ Prüft `/api/health` Endpunkt
- ✅ Automatischer Neustart bei Ausfall
- ✅ Mehrere Retry-Versuche (Standard: 3)
- ✅ Unterstützt PM2 und systemd
- ✅ Optional: E-Mail/Webhook-Benachrichtigungen
- ✅ Ressourcen-Monitoring (CPU/RAM/Disk)
### Konfiguration
```bash
API_URL="http://localhost:3010/api/health"
USE_PM2=true # false für systemd
MAX_RETRIES=3
RETRY_DELAY=5
SEND_EMAIL=false # true für E-Mail-Benachrichtigung
```
### Benachrichtigungen
Das Script kann bei Ausfällen Benachrichtigungen senden via:
- E-Mail (benötigt `mail` command)
- Webhook (Discord, Slack, etc.)
Konfiguriere die entsprechenden Variablen im Script:
```bash
SEND_EMAIL=true
EMAIL_TO="admin@tsschulz.de"
WEBHOOK_URL="https://discord.com/api/webhooks/..."
```
---
## 3. restore-backup.sh
Interaktives Script zum Wiederherstellen von Datenbank-Backups.
### Verwendung
```bash
# Interaktive Auswahl
sudo /var/www/timeclock/scripts/restore-backup.sh
# Spezifisches Backup wiederherstellen
sudo /var/www/timeclock/scripts/restore-backup.sh timeclock_db_20251018_020000.sql.gz
# Mit vollständigem Pfad
sudo /var/www/timeclock/scripts/restore-backup.sh /var/backups/timeclock/timeclock_db_20251018_020000.sql.gz
```
### Features
- ✅ Interaktive Backup-Auswahl
- ✅ Sicherheitskopie vor Restore
- ✅ Konfirmations-Prompts
- ✅ Automatisches Service-Neustart (optional)
- ✅ Datenbank-Statistiken nach Restore
### Ablauf
1. Zeigt Liste verfügbarer Backups
2. Erstellt Sicherheitskopie der aktuellen DB
3. Bestätigung erforderlich
4. Restore durchführen
5. Optional: Service neu starten
### ⚠️ WARNUNG
Das Restore überschreibt die aktuelle Datenbank! Eine Sicherheitskopie wird automatisch erstellt, aber sei vorsichtig!
---
## Logs
Alle Scripts loggen nach:
- `/var/log/timeclock/backup.log` - Backup-Logs
- `/var/log/timeclock/health-check.log` - Health-Check-Logs
### Logs ansehen
```bash
# Backup-Logs
tail -f /var/log/timeclock/backup.log
# Health-Check-Logs
tail -f /var/log/timeclock/health-check.log
# Alle Logs
tail -f /var/log/timeclock/*.log
```
---
## Cronjob-Übersicht
Empfohlene Cronjob-Konfiguration:
```cron
# TimeClock Maintenance Jobs
# Backup: Täglich um 2 Uhr morgens
0 2 * * * /usr/local/bin/backup-timeclock.sh >> /var/log/timeclock/backup.log 2>&1
# Health-Check: Alle 5 Minuten
*/5 * * * * /usr/local/bin/health-check.sh >> /var/log/timeclock/health-check.log 2>&1
# Optional: Log-Rotation - Alte Logs löschen (älter als 90 Tage)
0 3 * * 0 find /var/log/timeclock -name "*.log" -mtime +90 -delete
```
---
## Weitere nützliche Commands
### Backup-Verwaltung
```bash
# Liste aller Backups
ls -lh /var/backups/timeclock/
# Anzahl der Backups
ls -1 /var/backups/timeclock/timeclock_db_*.sql.gz | wc -l
# Gesamtgröße der Backups
du -sh /var/backups/timeclock/
# Ältestes Backup
ls -t /var/backups/timeclock/timeclock_db_*.sql.gz | tail -1
# Neuestes Backup
ls -t /var/backups/timeclock/timeclock_db_*.sql.gz | head -1
# Manuell alte Backups löschen (älter als 30 Tage)
find /var/backups/timeclock -name "timeclock_db_*.sql.gz" -mtime +30 -delete
```
### Service-Management
```bash
# Mit PM2
pm2 status
pm2 logs timeclock-backend
pm2 restart timeclock-backend
pm2 monit
# Mit systemd
sudo systemctl status timeclock
sudo journalctl -u timeclock -f
sudo systemctl restart timeclock
```
### API-Tests
```bash
# Health-Check
curl http://localhost:3010/api/health
# Mit Details
curl -s http://localhost:3010/api/health | jq
# Response-Zeit messen
time curl -s http://localhost:3010/api/health > /dev/null
```
---
## Troubleshooting
### Script läuft nicht
```bash
# Berechtigungen prüfen
ls -l /usr/local/bin/backup-timeclock.sh
# Ausführbar machen
sudo chmod +x /usr/local/bin/backup-timeclock.sh
# Script-Fehler debuggen
bash -x /usr/local/bin/backup-timeclock.sh
```
### Cronjob läuft nicht
```bash
# Cronjobs anzeigen
crontab -l
# Cron-Logs prüfen
sudo grep CRON /var/log/syslog
# Cronjob manuell testen
/usr/local/bin/backup-timeclock.sh
```
### Backup schlägt fehl
```bash
# DB-Verbindung testen
mysql -u timeclock -p -e "SHOW DATABASES;"
# .env Datei prüfen
cat /var/www/timeclock/backend/.env
# Backup-Verzeichnis prüfen
ls -ld /var/backups/timeclock
# Schreibrechte prüfen
touch /var/backups/timeclock/test.txt
```
---
## Best Practices
1. **Regelmäßige Backups testen**
- Teste mindestens monatlich ein Restore
- Verifiziere Backup-Integrität
2. **Monitoring einrichten**
- Health-Checks aktivieren
- E-Mail-Benachrichtigungen konfigurieren
3. **Logs überwachen**
- Prüfe regelmäßig die Log-Dateien
- Implementiere Log-Rotation
4. **Off-Site Backups**
- Aktiviere Remote-Backup in `backup-timeclock.sh`
- Speichere Backups an einem anderen Ort
5. **Sicherheit**
- Schütze Backup-Dateien (enthalten sensible Daten!)
- Setze restriktive Berechtigungen
---
## Support
Bei Problemen:
1. Prüfe die Log-Dateien
2. Teste Scripts manuell
3. Siehe Haupt-Dokumentation: `../DEPLOYMENT.md`
---
**Automatisierte Wartung für sorgenfreien Betrieb! 🚀**

223
scripts/backup-timeclock.sh Executable file
View File

@@ -0,0 +1,223 @@
#!/bin/bash
# =============================================================================
# TimeClock v3 - Automatisches Backup-Script
# =============================================================================
# Erstellt tägliche Backups der Datenbank und optional des Codes
#
# Installation:
# sudo cp backup-timeclock.sh /usr/local/bin/
# sudo chmod +x /usr/local/bin/backup-timeclock.sh
#
# Cronjob einrichten (täglich um 2 Uhr):
# sudo crontab -e
# 0 2 * * * /usr/local/bin/backup-timeclock.sh >> /var/log/timeclock/backup.log 2>&1
#
# Manuell ausführen:
# /usr/local/bin/backup-timeclock.sh
# =============================================================================
set -e
# Konfiguration
BACKUP_DIR="/var/backups/timeclock"
PROJECT_DIR="/var/www/timeclock"
ENV_FILE="$PROJECT_DIR/backend/.env"
RETENTION_DAYS=30 # Backups älter als X Tage werden gelöscht
# Datum
DATE=$(date +%Y%m%d_%H%M%S)
DATE_READABLE=$(date '+%Y-%m-%d %H:%M:%S')
# Logging
log() {
echo "[${DATE_READABLE}] $1"
}
log_error() {
echo "[${DATE_READABLE}] ERROR: $1" >&2
}
# =============================================================================
# Voraussetzungen prüfen
# =============================================================================
if [ ! -f "$ENV_FILE" ]; then
log_error ".env Datei nicht gefunden: $ENV_FILE"
exit 1
fi
# Backup-Verzeichnis erstellen
mkdir -p "$BACKUP_DIR"
# =============================================================================
# Datenbank-Credentials aus .env lesen
# =============================================================================
log "Lese Datenbank-Konfiguration..."
# Funktion zum Auslesen von .env Werten
get_env_value() {
grep "^$1=" "$ENV_FILE" | cut -d '=' -f2- | tr -d '"' | tr -d "'"
}
DB_HOST=$(get_env_value "DB_HOST")
DB_PORT=$(get_env_value "DB_PORT")
DB_NAME=$(get_env_value "DB_NAME")
DB_USER=$(get_env_value "DB_USER")
DB_PASSWORD=$(get_env_value "DB_PASSWORD")
# Defaults setzen
DB_HOST=${DB_HOST:-localhost}
DB_PORT=${DB_PORT:-3306}
if [ -z "$DB_NAME" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ]; then
log_error "Datenbank-Credentials unvollständig in .env"
exit 1
fi
log "Datenbank: $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME"
# =============================================================================
# Datenbank-Backup erstellen
# =============================================================================
log "Erstelle Datenbank-Backup..."
BACKUP_FILE="$BACKUP_DIR/timeclock_db_$DATE.sql.gz"
# mysqldump mit Kompression
if mysqldump \
--host="$DB_HOST" \
--port="$DB_PORT" \
--user="$DB_USER" \
--password="$DB_PASSWORD" \
--single-transaction \
--routines \
--triggers \
--events \
--add-drop-database \
--databases "$DB_NAME" \
| gzip > "$BACKUP_FILE"; then
# Dateigröße ermitteln
SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
log "✅ Datenbank-Backup erfolgreich erstellt: $BACKUP_FILE ($SIZE)"
else
log_error "Datenbank-Backup fehlgeschlagen!"
exit 1
fi
# =============================================================================
# Code-Backup erstellen (optional)
# =============================================================================
BACKUP_CODE=false # Auf true setzen für Code-Backups
if [ "$BACKUP_CODE" = true ]; then
log "Erstelle Code-Backup..."
CODE_BACKUP_FILE="$BACKUP_DIR/timeclock_code_$DATE.tar.gz"
if tar -czf "$CODE_BACKUP_FILE" \
-C "$(dirname $PROJECT_DIR)" \
--exclude="node_modules" \
--exclude="dist" \
--exclude=".git" \
--exclude="*.log" \
"$(basename $PROJECT_DIR)"; then
SIZE=$(du -h "$CODE_BACKUP_FILE" | cut -f1)
log "✅ Code-Backup erfolgreich erstellt: $CODE_BACKUP_FILE ($SIZE)"
else
log_error "Code-Backup fehlgeschlagen!"
fi
fi
# =============================================================================
# Alte Backups löschen
# =============================================================================
log "Lösche alte Backups (älter als $RETENTION_DAYS Tage)..."
# Datenbank-Backups
DELETED_DB=$(find "$BACKUP_DIR" -name "timeclock_db_*.sql.gz" -mtime +$RETENTION_DAYS -type f -delete -print | wc -l)
if [ "$DELETED_DB" -gt 0 ]; then
log "🗑️ $DELETED_DB alte Datenbank-Backups gelöscht"
fi
# Code-Backups
if [ "$BACKUP_CODE" = true ]; then
DELETED_CODE=$(find "$BACKUP_DIR" -name "timeclock_code_*.tar.gz" -mtime +$RETENTION_DAYS -type f -delete -print | wc -l)
if [ "$DELETED_CODE" -gt 0 ]; then
log "🗑️ $DELETED_CODE alte Code-Backups gelöscht"
fi
fi
# =============================================================================
# Backup-Statistik
# =============================================================================
log "Backup-Statistik:"
log " 📊 Gesamt-Backups: $(ls -1 $BACKUP_DIR/timeclock_db_*.sql.gz 2>/dev/null | wc -l)"
log " 💾 Gesamtgröße: $(du -sh $BACKUP_DIR | cut -f1)"
log " 📅 Ältestes Backup: $(ls -t $BACKUP_DIR/timeclock_db_*.sql.gz 2>/dev/null | tail -1 | xargs basename)"
log " 📅 Neuestes Backup: $(ls -t $BACKUP_DIR/timeclock_db_*.sql.gz 2>/dev/null | head -1 | xargs basename)"
# =============================================================================
# Optional: Backup an Remote-Server senden
# =============================================================================
REMOTE_BACKUP=false # Auf true setzen für Remote-Backup
REMOTE_USER="backup"
REMOTE_HOST="backup.example.com"
REMOTE_PATH="/backups/timeclock"
if [ "$REMOTE_BACKUP" = true ]; then
log "Sende Backup an Remote-Server..."
if rsync -az --progress "$BACKUP_FILE" "$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH/"; then
log "✅ Remote-Backup erfolgreich"
else
log_error "Remote-Backup fehlgeschlagen!"
fi
fi
# =============================================================================
# Optional: Backup-Benachrichtigung per E-Mail
# =============================================================================
SEND_EMAIL=false # Auf true setzen für E-Mail-Benachrichtigung
EMAIL_TO="admin@tsschulz.de"
if [ "$SEND_EMAIL" = true ] && command -v mail &> /dev/null; then
log "Sende E-Mail-Benachrichtigung..."
SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
echo "TimeClock Backup erfolgreich erstellt
Datum: $DATE_READABLE
Datei: $BACKUP_FILE
Größe: $SIZE
Datenbank: $DB_NAME
Backup-Verzeichnis: $BACKUP_DIR
Anzahl Backups: $(ls -1 $BACKUP_DIR/timeclock_db_*.sql.gz 2>/dev/null | wc -l)
Gesamtgröße: $(du -sh $BACKUP_DIR | cut -f1)
--
TimeClock v3 Backup System
" | mail -s "✅ TimeClock Backup erfolgreich ($DATE)" "$EMAIL_TO"
log "📧 E-Mail gesendet an $EMAIL_TO"
fi
# =============================================================================
# Fertig
# =============================================================================
log "✅ Backup-Prozess abgeschlossen!"
exit 0

210
scripts/health-check.sh Executable file
View File

@@ -0,0 +1,210 @@
#!/bin/bash
# =============================================================================
# TimeClock v3 - Health-Check Script
# =============================================================================
# Überwacht die Verfügbarkeit des Backend-API und startet bei Bedarf neu
#
# Installation:
# sudo cp health-check.sh /usr/local/bin/
# sudo chmod +x /usr/local/bin/health-check.sh
#
# Cronjob einrichten (alle 5 Minuten):
# crontab -e
# */5 * * * * /usr/local/bin/health-check.sh >> /var/log/timeclock/health-check.log 2>&1
#
# Manuell ausführen:
# /usr/local/bin/health-check.sh
# =============================================================================
set -e
# Konfiguration
API_URL="http://localhost:3010/api/health"
SERVICE_NAME="timeclock-backend"
USE_PM2=true # true für PM2, false für systemd
LOG_FILE="/var/log/timeclock/health-check.log"
MAX_RETRIES=3
RETRY_DELAY=5 # Sekunden zwischen Versuchen
# Datum
DATE=$(date '+%Y-%m-%d %H:%M:%S')
# Logging
log() {
echo "[$DATE] $1" | tee -a "$LOG_FILE"
}
log_error() {
echo "[$DATE] ERROR: $1" | tee -a "$LOG_FILE" >&2
}
# =============================================================================
# Health-Check durchführen
# =============================================================================
check_health() {
# Versuche Health-Endpunkt zu erreichen
if curl -sf "$API_URL" > /dev/null 2>&1; then
return 0 # Erfolg
else
return 1 # Fehler
fi
}
# =============================================================================
# Service neu starten
# =============================================================================
restart_service() {
log "⚠️ Versuche Service neu zu starten..."
if [ "$USE_PM2" = true ]; then
# PM2
if command -v pm2 &> /dev/null; then
if pm2 restart "$SERVICE_NAME" > /dev/null 2>&1; then
log "✅ Service mit PM2 neu gestartet"
return 0
else
log_error "PM2-Neustart fehlgeschlagen!"
return 1
fi
else
log_error "PM2 nicht gefunden!"
return 1
fi
else
# systemd
if sudo systemctl restart "$SERVICE_NAME"; then
log "✅ Service mit systemd neu gestartet"
return 0
else
log_error "systemd-Neustart fehlgeschlagen!"
return 1
fi
fi
}
# =============================================================================
# Benachrichtigung senden
# =============================================================================
send_notification() {
local status=$1
local message=$2
# Optional: E-Mail-Benachrichtigung
SEND_EMAIL=false
EMAIL_TO="admin@tsschulz.de"
if [ "$SEND_EMAIL" = true ] && command -v mail &> /dev/null; then
echo "$message
Zeitpunkt: $DATE
API-URL: $API_URL
Service: $SERVICE_NAME
--
TimeClock v3 Health-Check System
" | mail -s "$status TimeClock Backend" "$EMAIL_TO"
fi
# Optional: Webhook-Benachrichtigung (z.B. Discord, Slack)
WEBHOOK_URL=""
if [ -n "$WEBHOOK_URL" ]; then
curl -X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-d "{\"content\": \"$status $message\"}" \
> /dev/null 2>&1
fi
}
# =============================================================================
# Hauptlogik
# =============================================================================
# Erstelle Log-Verzeichnis falls nicht vorhanden
mkdir -p "$(dirname $LOG_FILE)"
# Prüfe ob Service läuft
if [ "$USE_PM2" = true ]; then
if ! pm2 list | grep -q "$SERVICE_NAME.*online"; then
log_error "⚠️ Service läuft nicht (PM2)!"
restart_service
sleep 10
fi
else
if ! systemctl is-active --quiet "$SERVICE_NAME"; then
log_error "⚠️ Service läuft nicht (systemd)!"
restart_service
sleep 10
fi
fi
# Health-Check mit Retries
SUCCESS=false
for i in $(seq 1 $MAX_RETRIES); do
if check_health; then
# Nur beim ersten Check des Tages loggen (um Log-Spam zu vermeiden)
CURRENT_HOUR=$(date +%H)
CURRENT_MINUTE=$(date +%M)
if [ "$CURRENT_HOUR" = "00" ] && [ "$CURRENT_MINUTE" -lt 6 ]; then
log "✅ Health-Check erfolgreich"
fi
SUCCESS=true
break
else
if [ $i -lt $MAX_RETRIES ]; then
log "⚠️ Health-Check fehlgeschlagen (Versuch $i/$MAX_RETRIES), warte $RETRY_DELAY Sekunden..."
sleep $RETRY_DELAY
fi
fi
done
# Wenn alle Versuche fehlschlagen
if [ "$SUCCESS" = false ]; then
log_error "❌ Health-Check fehlgeschlagen nach $MAX_RETRIES Versuchen!"
# Service neu starten
if restart_service; then
# Nach Neustart erneut prüfen
sleep 10
if check_health; then
log "✅ Service nach Neustart wieder erreichbar"
send_notification "⚠️ RECOVERED:" "TimeClock Backend wurde neu gestartet und ist wieder erreichbar."
else
log_error "❌ Service auch nach Neustart nicht erreichbar!"
send_notification "🚨 CRITICAL:" "TimeClock Backend ist auch nach Neustart nicht erreichbar! Manuelle Intervention erforderlich."
fi
else
log_error "❌ Service-Neustart fehlgeschlagen!"
send_notification "🚨 CRITICAL:" "TimeClock Backend-Neustart fehlgeschlagen! Manuelle Intervention erforderlich."
fi
fi
# =============================================================================
# Zusätzliche Checks (optional)
# =============================================================================
# CPU & Memory Usage prüfen
if [ "$USE_PM2" = true ] && command -v pm2 &> /dev/null; then
PM2_STATUS=$(pm2 jlist | jq -r ".[] | select(.name==\"$SERVICE_NAME\") | \"CPU: \(.monit.cpu)%, Memory: \(.monit.memory / 1024 / 1024 | floor)MB\"" 2>/dev/null || echo "N/A")
# Nur bei hohem Ressourcenverbrauch loggen
# (Optional: weitere Logik implementieren)
fi
# Disk Space prüfen
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$DISK_USAGE" -gt 90 ]; then
log_error "⚠️ Festplattenspeicher kritisch: ${DISK_USAGE}%"
send_notification "⚠️ WARNING:" "Festplattenspeicher auf TimeClock-Server kritisch: ${DISK_USAGE}%"
fi
exit 0

275
scripts/restore-backup.sh Executable file
View File

@@ -0,0 +1,275 @@
#!/bin/bash
# =============================================================================
# TimeClock v3 - Backup-Restore Script
# =============================================================================
# Stellt ein Datenbank-Backup wieder her
#
# Verwendung:
# ./restore-backup.sh [BACKUP_FILE]
# ./restore-backup.sh # Zeigt Liste der verfügbaren Backups
# ./restore-backup.sh timeclock_db_20251018_020000.sql.gz
#
# WARNUNG: Dies überschreibt die aktuelle Datenbank!
# =============================================================================
set -e
# Farben
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Konfiguration
BACKUP_DIR="/var/backups/timeclock"
PROJECT_DIR="/var/www/timeclock"
ENV_FILE="$PROJECT_DIR/backend/.env"
# Logging
log() {
echo -e "${BLUE} $1${NC}"
}
log_success() {
echo -e "${GREEN}$1${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
log_error() {
echo -e "${RED}$1${NC}"
}
# =============================================================================
# Voraussetzungen prüfen
# =============================================================================
if [ ! -f "$ENV_FILE" ]; then
log_error ".env Datei nicht gefunden: $ENV_FILE"
exit 1
fi
if [ ! -d "$BACKUP_DIR" ]; then
log_error "Backup-Verzeichnis nicht gefunden: $BACKUP_DIR"
exit 1
fi
# =============================================================================
# Datenbank-Credentials aus .env lesen
# =============================================================================
get_env_value() {
grep "^$1=" "$ENV_FILE" | cut -d '=' -f2- | tr -d '"' | tr -d "'"
}
DB_HOST=$(get_env_value "DB_HOST")
DB_PORT=$(get_env_value "DB_PORT")
DB_NAME=$(get_env_value "DB_NAME")
DB_USER=$(get_env_value "DB_USER")
DB_PASSWORD=$(get_env_value "DB_PASSWORD")
# Defaults
DB_HOST=${DB_HOST:-localhost}
DB_PORT=${DB_PORT:-3306}
if [ -z "$DB_NAME" ] || [ -z "$DB_USER" ] || [ -z "$DB_PASSWORD" ]; then
log_error "Datenbank-Credentials unvollständig in .env"
exit 1
fi
# =============================================================================
# Verfügbare Backups auflisten
# =============================================================================
list_backups() {
echo ""
log "Verfügbare Backups in $BACKUP_DIR:"
echo ""
BACKUPS=($(ls -t "$BACKUP_DIR"/timeclock_db_*.sql.gz 2>/dev/null))
if [ ${#BACKUPS[@]} -eq 0 ]; then
log_warning "Keine Backups gefunden!"
exit 1
fi
for i in "${!BACKUPS[@]}"; do
BACKUP="${BACKUPS[$i]}"
FILENAME=$(basename "$BACKUP")
SIZE=$(du -h "$BACKUP" | cut -f1)
DATE=$(stat -c %y "$BACKUP" | cut -d'.' -f1)
printf "%2d) %-50s %6s %s\n" $((i+1)) "$FILENAME" "$SIZE" "$DATE"
done
echo ""
}
# =============================================================================
# Backup-Datei auswählen
# =============================================================================
select_backup() {
list_backups
read -p "Wähle ein Backup (Nummer) oder 'q' zum Beenden: " selection
if [ "$selection" = "q" ] || [ "$selection" = "Q" ]; then
log "Abgebrochen."
exit 0
fi
if ! [[ "$selection" =~ ^[0-9]+$ ]]; then
log_error "Ungültige Eingabe!"
exit 1
fi
BACKUPS=($(ls -t "$BACKUP_DIR"/timeclock_db_*.sql.gz 2>/dev/null))
INDEX=$((selection - 1))
if [ $INDEX -lt 0 ] || [ $INDEX -ge ${#BACKUPS[@]} ]; then
log_error "Ungültige Auswahl!"
exit 1
fi
BACKUP_FILE="${BACKUPS[$INDEX]}"
}
# =============================================================================
# Restore durchführen
# =============================================================================
restore_backup() {
local backup_file=$1
if [ ! -f "$backup_file" ]; then
log_error "Backup-Datei nicht gefunden: $backup_file"
exit 1
fi
echo ""
log_warning "WARNUNG: Dies wird die aktuelle Datenbank '$DB_NAME' überschreiben!"
log "Backup-Datei: $(basename $backup_file)"
log "Größe: $(du -h $backup_file | cut -f1)"
log "Datenbank: $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME"
echo ""
read -p "Fortfahren? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
log "Abgebrochen."
exit 0
fi
# Erstelle Backup der aktuellen Datenbank (Sicherheitskopie)
log "Erstelle Sicherheitskopie der aktuellen Datenbank..."
SAFETY_BACKUP="$BACKUP_DIR/timeclock_db_pre_restore_$(date +%Y%m%d_%H%M%S).sql.gz"
if mysqldump \
--host="$DB_HOST" \
--port="$DB_PORT" \
--user="$DB_USER" \
--password="$DB_PASSWORD" \
--single-transaction \
--databases "$DB_NAME" \
| gzip > "$SAFETY_BACKUP"; then
log_success "Sicherheitskopie erstellt: $(basename $SAFETY_BACKUP)"
else
log_error "Sicherheitskopie fehlgeschlagen!"
read -p "Trotzdem fortfahren? (yes/no): " force
if [ "$force" != "yes" ]; then
exit 1
fi
fi
# Restore durchführen
log "Stelle Backup wieder her..."
# Datenbank leeren (optional, aber empfohlen)
log "Leere Datenbank..."
mysql \
--host="$DB_HOST" \
--port="$DB_PORT" \
--user="$DB_USER" \
--password="$DB_PASSWORD" \
-e "DROP DATABASE IF EXISTS $DB_NAME; CREATE DATABASE $DB_NAME;"
# Backup einspielen
if gunzip < "$backup_file" | mysql \
--host="$DB_HOST" \
--port="$DB_PORT" \
--user="$DB_USER" \
--password="$DB_PASSWORD"; then
log_success "Backup erfolgreich wiederhergestellt!"
# Datenbank-Statistiken
TABLE_COUNT=$(mysql \
--host="$DB_HOST" \
--port="$DB_PORT" \
--user="$DB_USER" \
--password="$DB_PASSWORD" \
-e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '$DB_NAME';" -s -N)
log "Datenbank-Statistik:"
log " 📊 Tabellen: $TABLE_COUNT"
# Optional: Service neu starten
log_warning "Möchtest du den Backend-Service neu starten?"
read -p "Service neu starten? (y/n): " restart
if [ "$restart" = "y" ] || [ "$restart" = "Y" ]; then
if command -v pm2 &> /dev/null && pm2 list | grep -q "timeclock-backend"; then
pm2 restart timeclock-backend
log_success "PM2-Service neu gestartet"
elif systemctl is-active --quiet timeclock; then
sudo systemctl restart timeclock
log_success "systemd-Service neu gestartet"
else
log_warning "Service-Verwaltung nicht gefunden - bitte manuell neu starten"
fi
fi
echo ""
log_success "Restore abgeschlossen!"
log "Sicherheitskopie der alten Datenbank: $(basename $SAFETY_BACKUP)"
else
log_error "Restore fehlgeschlagen!"
log "Die Sicherheitskopie befindet sich unter: $(basename $SAFETY_BACKUP)"
exit 1
fi
}
# =============================================================================
# Hauptprogramm
# =============================================================================
echo ""
echo -e "${BLUE}════════════════════════════════════════════════════════════${NC}"
echo -e "${BLUE} TimeClock v3 - Backup Restore${NC}"
echo -e "${BLUE}════════════════════════════════════════════════════════════${NC}"
echo ""
# Wenn Backup-Datei als Argument übergeben wurde
if [ $# -eq 1 ]; then
BACKUP_FILE="$1"
# Wenn nur Dateiname (ohne Pfad) übergeben wurde
if [ ! -f "$BACKUP_FILE" ]; then
BACKUP_FILE="$BACKUP_DIR/$1"
fi
restore_backup "$BACKUP_FILE"
else
# Interaktive Auswahl
select_backup
restore_backup "$BACKUP_FILE"
fi
exit 0