diff --git a/backend/app/app.py b/backend/app/app.py
index d18ba7d2..d52d71f7 100644
--- a/backend/app/app.py
+++ b/backend/app/app.py
@@ -4245,7 +4245,7 @@ if __name__ == "__main__":
# Scheduler stoppen falls aktiviert
if SCHEDULER_ENABLED and scheduler:
try:
- scheduler.shutdown(wait=False)
+ scheduler.stop()
app_logger.info("Job-Scheduler gestoppt")
except Exception as e:
app_logger.error(f"Fehler beim Stoppen des Schedulers: {str(e)}")
diff --git a/backend/app/install_raspberry_pi.sh b/backend/app/install_raspberry_pi.sh
index f47212a0..a77998ea 100644
--- a/backend/app/install_raspberry_pi.sh
+++ b/backend/app/install_raspberry_pi.sh
@@ -3,6 +3,7 @@
# ===================================================================
# Raspberry Pi Vollautomatische Installation - MYP Druckerverwaltung
# Für Debian 12 (Bookworm) auf Raspberry Pi
+# Nach offizieller Raspberry Pi Kiosk-Anleitung optimiert
# ===================================================================
set -e # Beende bei Fehlern
@@ -38,25 +39,31 @@ if [ "$EUID" -ne 0 ]; then
fi
log "=== MYP Druckerverwaltung - Raspberry Pi Installation ==="
-log "Debian 12 (Bookworm) Vollautomatische Einrichtung"
+log "Debian 12 (Bookworm) Kiosk-Modus nach offizieller Anleitung"
echo
# Konfigurationsvariablen
APP_USER="myp"
+KIOSK_USER="kiosk"
APP_DIR="/opt/myp-druckerverwaltung"
SERVICE_NAME="myp-druckerverwaltung"
KIOSK_SERVICE_NAME="myp-kiosk"
-GITHUB_REPO="https://github.com/your-repo/myp-druckerverwaltung.git" # Anpassen!
-DISPLAY_PORT=":0"
+KIOSK_URL="http://localhost"
+
+# Bereinige unbenötigte Pakete (entsprechend offizieller Anleitung)
+log "Entferne unbenötigte Pakete zur Speicheroptimierung..."
+export DEBIAN_FRONTEND=noninteractive
+apt-get purge -y wolfram-engine scratch scratch2 nuscratch sonic-pi idle3 smartsim java-common minecraft-pi libreoffice* || true
+apt-get autoremove -y
+apt-get clean
# Systemupdate
log "Aktualisiere Paketlisten und System..."
-export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get upgrade -y --allow-downgrades --allow-remove-essential --allow-change-held-packages
-# Installiere erforderliche Pakete
-log "Installiere Systempakete..."
+# Installiere erforderliche Pakete (nach offizieller Anleitung)
+log "Installiere Systempakete für Kiosk-Modus..."
apt-get install -y \
python3 \
python3-pip \
@@ -74,7 +81,9 @@ apt-get install -y \
openbox \
lightdm \
x11-xserver-utils \
+ xdotool \
unclutter \
+ sed \
build-essential \
libssl-dev \
libffi-dev \
@@ -82,7 +91,7 @@ apt-get install -y \
zlib1g-dev \
nodejs \
npm \
- --break-system-packages || true
+ --no-install-recommends || true
# Erstelle Anwendungsbenutzer
log "Erstelle Anwendungsbenutzer '$APP_USER'..."
@@ -94,15 +103,24 @@ else
log "Benutzer '$APP_USER' existiert bereits"
fi
+# Erstelle Kiosk-Benutzer (nach offizieller Anleitung)
+log "Erstelle Kiosk-Benutzer '$KIOSK_USER'..."
+if ! id "$KIOSK_USER" &>/dev/null; then
+ useradd -m -s /bin/bash "$KIOSK_USER"
+ usermod -aG audio,video "$KIOSK_USER"
+ log "Benutzer '$KIOSK_USER' erstellt"
+else
+ log "Benutzer '$KIOSK_USER' existiert bereits"
+fi
+
# Erstelle Anwendungsverzeichnis
log "Erstelle Anwendungsverzeichnis..."
mkdir -p "$APP_DIR"
chown "$APP_USER:$APP_USER" "$APP_DIR"
-# Klone Repository (falls nicht lokal vorhanden)
+# Kopiere Anwendung
if [ ! -d "$APP_DIR/.git" ]; then
- log "Klone Anwendung von Repository..."
- # Für lokale Installation: kopiere aktuelles Verzeichnis
+ log "Kopiere Anwendung..."
if [ -f "app.py" ]; then
log "Kopiere lokale Anwendung..."
cp -r . "$APP_DIR/"
@@ -111,7 +129,7 @@ if [ ! -d "$APP_DIR/.git" ]; then
error "Anwendungsdateien nicht gefunden. Führe das Skript im Anwendungsverzeichnis aus."
fi
else
- log "Repository bereits vorhanden, aktualisiere..."
+ log "Anwendung bereits vorhanden, aktualisiere..."
cd "$APP_DIR"
sudo -u "$APP_USER" git pull
fi
@@ -126,7 +144,7 @@ sudo -u "$APP_USER" ./venv/bin/pip install --upgrade pip
# Installiere Python-Abhängigkeiten
log "Installiere Python-Abhängigkeiten..."
if [ -f "requirements.txt" ]; then
- sudo -u "$APP_USER" ./venv/bin/pip install -r requirements.txt --break-system-packages || true
+ sudo -u "$APP_USER" ./venv/bin/pip install -r requirements.txt
else
# Fallback: Installiere grundlegende Pakete
sudo -u "$APP_USER" ./venv/bin/pip install \
@@ -136,14 +154,13 @@ else
werkzeug \
requests \
python-dotenv \
- gunicorn \
- --break-system-packages || true
+ gunicorn
fi
-# Node.js Abhängigkeiten installieren (falls package.json vorhanden)
+# Node.js Abhängigkeiten installieren
if [ -f "package.json" ]; then
log "Installiere Node.js Abhängigkeiten..."
- sudo -u "$APP_USER" npm install --unsafe-perm=true --allow-root
+ sudo -u "$APP_USER" npm install
# Baue Frontend-Assets
if [ -f "tailwind.config.js" ]; then
@@ -157,7 +174,6 @@ log "Initialisiere Datenbank..."
if [ -f "init_db.py" ]; then
sudo -u "$APP_USER" ./venv/bin/python init_db.py
else
- # Erstelle einfache SQLite-Datenbank
sudo -u "$APP_USER" touch database.db
fi
@@ -179,8 +195,96 @@ EOF
chown "$APP_USER:$APP_USER" "$APP_DIR/.env"
+# Erstelle Kiosk-Skript (nach offizieller Anleitung)
+log "Erstelle Kiosk-Skript..."
+cat > "/home/$KIOSK_USER/kiosk.sh" << EOF
+#!/bin/bash
+
+# Warte auf System-Bereitschaft
+sleep 5
+
+# Setze Display-Umgebung
+export DISPLAY=:0
+
+# Deaktiviere Bildschirmschoner (nach offizieller Anleitung)
+xset s noblank
+xset s off
+xset -dpms
+
+# Verstecke Mauszeiger
+unclutter -idle 0.5 -root &
+
+# Bereinige Chromium-Präferenzen (verhindert Crash-Warnungen)
+sed -i 's/"exited_cleanly":false/"exited_cleanly":true/' /home/$KIOSK_USER/.config/chromium/Default/Preferences 2>/dev/null || true
+sed -i 's/"exit_type":"Crashed"/"exit_type":"Normal"/' /home/$KIOSK_USER/.config/chromium/Default/Preferences 2>/dev/null || true
+
+# Warte auf Netzwerk und Anwendung
+while ! curl -s http://localhost > /dev/null; do
+ echo "Warte auf Anwendung..."
+ sleep 2
+done
+
+# Starte Chromium im Kiosk-Modus (nach offizieller Anleitung)
+/usr/bin/chromium-browser \\
+ --noerrdialogs \\
+ --disable-infobars \\
+ --kiosk \\
+ --no-sandbox \\
+ --disable-web-security \\
+ --disable-features=TranslateUI \\
+ --disable-ipc-flooding-protection \\
+ --disable-renderer-backgrounding \\
+ --disable-backgrounding-occluded-windows \\
+ --disable-background-timer-throttling \\
+ --disable-background-networking \\
+ --disable-breakpad \\
+ --disable-component-extensions-with-background-pages \\
+ --disable-dev-shm-usage \\
+ --disable-extensions \\
+ --disable-features=TranslateUI,BlinkGenPropertyTrees \\
+ --disable-hang-monitor \\
+ --disable-popup-blocking \\
+ --disable-prompt-on-repost \\
+ --disable-sync \\
+ --disable-translate \\
+ --force-color-profile=srgb \\
+ --no-first-run \\
+ --autoplay-policy=no-user-gesture-required \\
+ --start-fullscreen \\
+ $KIOSK_URL &
+
+# Optional: Automatische Tab-Rotation (auskommentiert)
+# while true; do
+# sleep 30
+# xdotool keydown ctrl+r; xdotool keyup ctrl+r; # Seite neu laden
+# done
+EOF
+
+chmod +x "/home/$KIOSK_USER/kiosk.sh"
+chown "$KIOSK_USER:$KIOSK_USER" "/home/$KIOSK_USER/kiosk.sh"
+
+# Konfiguriere LightDM für automatischen Login (nach offizieller Anleitung)
+log "Konfiguriere automatischen Login..."
+cat > "/etc/lightdm/lightdm.conf" << EOF
+[Seat:*]
+autologin-user=$KIOSK_USER
+autologin-user-timeout=0
+user-session=openbox
+xserver-command=X -s 0 -dpms
+EOF
+
+# Erstelle Openbox-Konfiguration für Kiosk-Benutzer
+log "Konfiguriere Openbox für Kiosk-Modus..."
+mkdir -p "/home/$KIOSK_USER/.config/openbox"
+cat > "/home/$KIOSK_USER/.config/openbox/autostart" << EOF
+# Starte Kiosk-Anwendung automatisch
+/home/$KIOSK_USER/kiosk.sh &
+EOF
+
+chown -R "$KIOSK_USER:$KIOSK_USER" "/home/$KIOSK_USER/.config"
+
# Erstelle Systemd-Service für die Anwendung
-log "Erstelle Systemd-Service..."
+log "Erstelle Systemd-Service für Anwendung..."
cat > "/etc/systemd/system/$SERVICE_NAME.service" << EOF
[Unit]
Description=MYP Druckerverwaltung Flask Application
@@ -202,6 +306,27 @@ StandardError=journal
WantedBy=multi-user.target
EOF
+# Erstelle Systemd-Service für Kiosk (nach offizieller Anleitung)
+log "Erstelle Systemd-Service für Kiosk..."
+cat > "/etc/systemd/system/$KIOSK_SERVICE_NAME.service" << EOF
+[Unit]
+Description=MYP Chromium Kiosk
+Wants=graphical.target
+After=graphical.target $SERVICE_NAME.service
+
+[Service]
+Environment=DISPLAY=:0.0
+Environment=XAUTHORITY=/home/$KIOSK_USER/.Xauthority
+Type=simple
+ExecStart=/bin/bash /home/$KIOSK_USER/kiosk.sh
+Restart=on-abort
+User=$KIOSK_USER
+Group=$KIOSK_USER
+
+[Install]
+WantedBy=graphical.target
+EOF
+
# Nginx-Konfiguration
log "Konfiguriere Nginx..."
cat > "/etc/nginx/sites-available/myp-druckerverwaltung" << EOF
@@ -237,112 +362,6 @@ EOF
rm -f /etc/nginx/sites-enabled/default
ln -sf /etc/nginx/sites-available/myp-druckerverwaltung /etc/nginx/sites-enabled/
-# Kiosk-Modus konfigurieren
-log "Konfiguriere Kiosk-Modus..."
-
-# Erstelle Kiosk-Benutzer
-if ! id "kiosk" &>/dev/null; then
- useradd -m -s /bin/bash kiosk
- usermod -aG audio,video kiosk
-fi
-
-# Erstelle Kiosk-Startskript
-cat > "/home/kiosk/start-kiosk.sh" << 'EOF'
-#!/bin/bash
-
-# Warte auf Netzwerk
-sleep 10
-
-# Setze Display
-export DISPLAY=:0
-
-# Deaktiviere Bildschirmschoner und Energiesparmodus
-xset s off
-xset -dpms
-xset s noblank
-
-# Verstecke Mauszeiger
-unclutter -idle 0.5 -root &
-
-# Starte Chromium im Kiosk-Modus
-chromium-browser \
- --kiosk \
- --no-sandbox \
- --disable-web-security \
- --disable-features=TranslateUI \
- --disable-ipc-flooding-protection \
- --disable-renderer-backgrounding \
- --disable-backgrounding-occluded-windows \
- --disable-background-timer-throttling \
- --disable-background-networking \
- --disable-breakpad \
- --disable-component-extensions-with-background-pages \
- --disable-dev-shm-usage \
- --disable-extensions \
- --disable-features=TranslateUI,BlinkGenPropertyTrees \
- --disable-hang-monitor \
- --disable-ipc-flooding-protection \
- --disable-popup-blocking \
- --disable-prompt-on-repost \
- --disable-renderer-backgrounding \
- --disable-sync \
- --disable-translate \
- --disable-windows10-custom-titlebar \
- --force-color-profile=srgb \
- --metrics-recording-only \
- --no-first-run \
- --safebrowsing-disable-auto-update \
- --enable-automation \
- --password-store=basic \
- --use-mock-keychain \
- --autoplay-policy=no-user-gesture-required \
- --start-fullscreen \
- --window-position=0,0 \
- --window-size=1920,1080 \
- http://localhost/
-EOF
-
-chmod +x /home/kiosk/start-kiosk.sh
-chown kiosk:kiosk /home/kiosk/start-kiosk.sh
-
-# Erstelle Systemd-Service für Kiosk
-cat > "/etc/systemd/system/$KIOSK_SERVICE_NAME.service" << EOF
-[Unit]
-Description=MYP Kiosk Mode
-After=graphical-session.target network.target $SERVICE_NAME.service
-Wants=graphical-session.target
-
-[Service]
-Type=simple
-User=kiosk
-Group=kiosk
-Environment=DISPLAY=:0
-ExecStart=/home/kiosk/start-kiosk.sh
-Restart=always
-RestartSec=10
-
-[Install]
-WantedBy=graphical.target
-EOF
-
-# Konfiguriere LightDM für automatischen Login
-log "Konfiguriere automatischen Login..."
-cat > "/etc/lightdm/lightdm.conf" << EOF
-[Seat:*]
-autologin-user=kiosk
-autologin-user-timeout=0
-user-session=openbox
-EOF
-
-# Erstelle Openbox-Konfiguration für Kiosk-Benutzer
-mkdir -p /home/kiosk/.config/openbox
-cat > "/home/kiosk/.config/openbox/autostart" << EOF
-# Starte Kiosk-Anwendung
-/home/kiosk/start-kiosk.sh &
-EOF
-
-chown -R kiosk:kiosk /home/kiosk/.config
-
# Erstelle Wartungsskript
log "Erstelle Wartungsskript..."
cat > "/usr/local/bin/myp-maintenance" << 'EOF'
@@ -383,15 +402,23 @@ case "$1" in
echo "=== Anwendungslogs ==="
journalctl -u myp-druckerverwaltung -f
;;
+ kiosk-logs)
+ echo "=== Kiosk-Logs ==="
+ journalctl -u myp-kiosk -f
+ ;;
update)
echo "Aktualisiere MYP Druckerverwaltung..."
cd /opt/myp-druckerverwaltung
sudo -u myp git pull
- sudo -u myp ./venv/bin/pip install -r requirements.txt --break-system-packages
+ sudo -u myp ./venv/bin/pip install -r requirements.txt
systemctl restart myp-druckerverwaltung
;;
+ kiosk-restart)
+ echo "Starte nur Kiosk neu..."
+ systemctl restart myp-kiosk
+ ;;
*)
- echo "Verwendung: $0 {start|stop|restart|status|logs|update}"
+ echo "Verwendung: $0 {start|stop|restart|status|logs|kiosk-logs|update|kiosk-restart}"
exit 1
;;
esac
@@ -399,57 +426,8 @@ EOF
chmod +x /usr/local/bin/myp-maintenance
-# Aktiviere und starte Services
-log "Aktiviere und starte Services..."
-systemctl daemon-reload
-systemctl enable "$SERVICE_NAME"
-systemctl enable nginx
-systemctl enable "$KIOSK_SERVICE_NAME"
-
-# Starte Services
-systemctl start "$SERVICE_NAME"
-systemctl start nginx
-
-# Warte kurz und prüfe Status
-sleep 5
-
-if systemctl is-active --quiet "$SERVICE_NAME"; then
- log "✅ MYP Druckerverwaltung Service läuft"
-else
- warning "⚠️ MYP Druckerverwaltung Service nicht aktiv"
-fi
-
-if systemctl is-active --quiet nginx; then
- log "✅ Nginx läuft"
-else
- warning "⚠️ Nginx nicht aktiv"
-fi
-
-# Konfiguriere Firewall (falls ufw installiert)
-if command -v ufw &> /dev/null; then
- log "Konfiguriere Firewall..."
- ufw --force enable
- ufw allow 80/tcp
- ufw allow 22/tcp
-fi
-
-# Erstelle Desktop-Verknüpfung für Wartung
-cat > "/home/$APP_USER/Desktop/MYP-Wartung.desktop" << EOF
-[Desktop Entry]
-Version=1.0
-Type=Application
-Name=MYP Wartung
-Comment=MYP Druckerverwaltung Wartung
-Exec=gnome-terminal -- sudo myp-maintenance status
-Icon=applications-system
-Terminal=true
-Categories=System;
-EOF
-
-chown "$APP_USER:$APP_USER" "/home/$APP_USER/Desktop/MYP-Wartung.desktop"
-chmod +x "/home/$APP_USER/Desktop/MYP-Wartung.desktop"
-
# Erstelle Backup-Skript
+log "Erstelle Backup-Skript..."
cat > "/usr/local/bin/myp-backup" << 'EOF'
#!/bin/bash
@@ -486,6 +464,40 @@ chmod +x /usr/local/bin/myp-backup
# Erstelle Cron-Job für automatische Backups
echo "0 2 * * * root /usr/local/bin/myp-backup" > /etc/cron.d/myp-backup
+# Aktiviere und starte Services
+log "Aktiviere und starte Services..."
+systemctl daemon-reload
+systemctl enable "$SERVICE_NAME"
+systemctl enable nginx
+systemctl enable "$KIOSK_SERVICE_NAME"
+
+# Starte Services
+systemctl start "$SERVICE_NAME"
+systemctl start nginx
+
+# Warte kurz und prüfe Status
+sleep 5
+
+if systemctl is-active --quiet "$SERVICE_NAME"; then
+ log "✅ MYP Druckerverwaltung Service läuft"
+else
+ warning "⚠️ MYP Druckerverwaltung Service nicht aktiv"
+fi
+
+if systemctl is-active --quiet nginx; then
+ log "✅ Nginx läuft"
+else
+ warning "⚠️ Nginx nicht aktiv"
+fi
+
+# Konfiguriere Firewall (falls ufw installiert)
+if command -v ufw &> /dev/null; then
+ log "Konfiguriere Firewall..."
+ ufw --force enable
+ ufw allow 80/tcp
+ ufw allow 22/tcp
+fi
+
# Abschlussmeldung
log "=== Installation abgeschlossen! ==="
echo
@@ -495,6 +507,7 @@ info "📋 Wichtige Informationen:"
info " • Anwendung läuft auf: http://$(hostname -I | awk '{print $1}')"
info " • Anwendungsverzeichnis: $APP_DIR"
info " • Anwendungsbenutzer: $APP_USER"
+info " • Kiosk-Benutzer: $KIOSK_USER"
info " • Service-Name: $SERVICE_NAME"
info " • Kiosk-Service: $KIOSK_SERVICE_NAME"
echo
@@ -502,13 +515,22 @@ info "🔧 Wartungskommandos:"
info " • Status prüfen: myp-maintenance status"
info " • Neustart: myp-maintenance restart"
info " • Logs anzeigen: myp-maintenance logs"
+info " • Kiosk-Logs: myp-maintenance kiosk-logs"
+info " • Nur Kiosk neustarten: myp-maintenance kiosk-restart"
info " • Update: myp-maintenance update"
info " • Backup erstellen: myp-backup"
echo
-info "🖥️ Kiosk-Modus:"
-info " • Wird beim nächsten Neustart automatisch gestartet"
-info " • Vollbild-Browser auf http://localhost"
-info " • Automatischer Login als 'kiosk' Benutzer"
+info "🖥️ Kiosk-Modus (nach offizieller Raspberry Pi Anleitung):"
+info " • Automatischer Login als '$KIOSK_USER' Benutzer"
+info " • Chromium-Browser im Vollbild-Kiosk-Modus"
+info " • Automatische Anzeige von $KIOSK_URL"
+info " • Versteckter Mauszeiger"
+info " • Deaktivierte Bildschirmschoner"
+echo
+info "🔍 Zusätzliche Konfiguration:"
+info " • Kiosk-Skript: /home/$KIOSK_USER/kiosk.sh"
+info " • LightDM-Konfiguration: /etc/lightdm/lightdm.conf"
+info " • Openbox-Autostart: /home/$KIOSK_USER/.config/openbox/autostart"
echo
warning "⚠️ Wichtiger Hinweis:"
warning " Starte das System neu, um den Kiosk-Modus zu aktivieren:"
diff --git a/backend/app/static/css/responsive-improvements.css b/backend/app/static/css/responsive-improvements.css
new file mode 100644
index 00000000..9c634bbb
--- /dev/null
+++ b/backend/app/static/css/responsive-improvements.css
@@ -0,0 +1,526 @@
+/**
+ * Mercedes-Benz MYP Platform - Responsive Verbesserungen & Problembehebung
+ * Entfernt eckige Hintergründe und verbessert Responsivität
+ */
+
+/* Globale Überschreibungen für problematische Hintergründe */
+* {
+ background-color: transparent !important;
+}
+
+/* Erlaubte Hintergründe explizit definieren */
+body,
+html {
+ background: #f8fafc !important;
+}
+
+.dark body,
+.dark html {
+ background: #000000 !important;
+}
+
+/* Mercedes Professional Overrides */
+.bg-professional,
+.professional-hero,
+.professional-container,
+.mb-glass,
+.card-professional,
+.stat-card {
+ background: #f8fafc !important;
+ border-radius: 2rem !important;
+}
+
+.dark .bg-professional,
+.dark .professional-hero,
+.dark .professional-container,
+.dark .mb-glass,
+.dark .card-professional,
+.dark .stat-card {
+ background: #111111 !important;
+ border-color: #333333 !important;
+}
+
+/* Entferne alle eckigen Hintergründe mit problematischen Farben */
+[style*="#182031"],
+[style*="#d5d7d8"],
+[style*="rgb(24, 32, 49)"],
+[style*="rgb(213, 215, 216)"] {
+ background: transparent !important;
+ background-color: transparent !important;
+}
+
+/* Navbar und Navigation - Responsive */
+.navbar {
+ background: rgba(255, 255, 255, 0.95) !important;
+ backdrop-filter: blur(20px) !important;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1) !important;
+}
+
+.dark .navbar {
+ background: rgba(0, 0, 0, 0.95) !important;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important;
+}
+
+/* Responsive Typography */
+@media (max-width: 640px) {
+ .title-professional {
+ font-size: 2.5rem !important;
+ line-height: 1.1 !important;
+ }
+
+ .subtitle-professional {
+ font-size: 1.125rem !important;
+ line-height: 1.5 !important;
+ }
+
+ .btn-professional {
+ padding: 0.75rem 1.5rem !important;
+ font-size: 0.875rem !important;
+ }
+
+ .professional-container,
+ .mb-glass,
+ .card-professional {
+ padding: 1.5rem !important;
+ margin: 1rem !important;
+ border-radius: 1rem !important;
+ }
+}
+
+@media (min-width: 641px) and (max-width: 768px) {
+ .title-professional {
+ font-size: 3.5rem !important;
+ line-height: 1.1 !important;
+ }
+
+ .subtitle-professional {
+ font-size: 1.25rem !important;
+ line-height: 1.6 !important;
+ }
+
+ .btn-professional {
+ padding: 1rem 2rem !important;
+ font-size: 1rem !important;
+ }
+
+ .professional-container,
+ .mb-glass,
+ .card-professional {
+ padding: 2rem !important;
+ margin: 1.5rem !important;
+ border-radius: 1.5rem !important;
+ }
+}
+
+@media (min-width: 769px) and (max-width: 1024px) {
+ .title-professional {
+ font-size: 4.5rem !important;
+ line-height: 1.1 !important;
+ }
+
+ .subtitle-professional {
+ font-size: 1.5rem !important;
+ line-height: 1.6 !important;
+ }
+
+ .btn-professional {
+ padding: 1.25rem 2.5rem !important;
+ font-size: 1.125rem !important;
+ }
+
+ .professional-container,
+ .mb-glass,
+ .card-professional {
+ padding: 2.5rem !important;
+ margin: 2rem !important;
+ border-radius: 2rem !important;
+ }
+}
+
+@media (min-width: 1025px) {
+ .title-professional {
+ font-size: 6rem !important;
+ line-height: 1.1 !important;
+ }
+
+ .subtitle-professional {
+ font-size: 2rem !important;
+ line-height: 1.6 !important;
+ }
+
+ .btn-professional {
+ padding: 1.5rem 3rem !important;
+ font-size: 1.25rem !important;
+ }
+
+ .professional-container,
+ .mb-glass,
+ .card-professional {
+ padding: 3rem !important;
+ margin: 2rem !important;
+ border-radius: 2rem !important;
+ }
+}
+
+/* Responsive Grid Improvements */
+@media (max-width: 640px) {
+ .grid {
+ grid-template-columns: 1fr !important;
+ gap: 1rem !important;
+ }
+
+ .grid-cols-2 {
+ grid-template-columns: 1fr !important;
+ }
+
+ .grid-cols-3 {
+ grid-template-columns: 1fr !important;
+ }
+
+ .grid-cols-4 {
+ grid-template-columns: 1fr !important;
+ }
+}
+
+@media (min-width: 641px) and (max-width: 768px) {
+ .grid-cols-3 {
+ grid-template-columns: repeat(2, 1fr) !important;
+ }
+
+ .grid-cols-4 {
+ grid-template-columns: repeat(2, 1fr) !important;
+ }
+}
+
+/* Responsive Flex Improvements */
+.flex-col-mobile {
+ flex-direction: column !important;
+}
+
+@media (min-width: 768px) {
+ .flex-col-mobile {
+ flex-direction: row !important;
+ }
+}
+
+/* Responsive Spacing */
+@media (max-width: 640px) {
+ .space-y-6 > * + * {
+ margin-top: 1rem !important;
+ }
+
+ .space-y-8 > * + * {
+ margin-top: 1.5rem !important;
+ }
+
+ .space-y-12 > * + * {
+ margin-top: 2rem !important;
+ }
+
+ .space-x-6 > * + * {
+ margin-left: 1rem !important;
+ }
+
+ .space-x-8 > * + * {
+ margin-left: 1.5rem !important;
+ }
+}
+
+/* Input Field Responsivität */
+.input-professional {
+ background: #ffffff !important;
+ border: 2px solid #e2e8f0 !important;
+ border-radius: 1rem !important;
+ padding: 1rem !important;
+ font-size: 1rem !important;
+ width: 100% !important;
+}
+
+.dark .input-professional {
+ background: #1a1a1a !important;
+ border-color: #333333 !important;
+ color: #ffffff !important;
+}
+
+.input-professional:focus {
+ border-color: #3b82f6 !important;
+ box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1) !important;
+ background: #ffffff !important;
+}
+
+.dark .input-professional:focus {
+ background: #222222 !important;
+}
+
+@media (max-width: 640px) {
+ .input-professional {
+ padding: 0.875rem !important;
+ font-size: 0.875rem !important;
+ border-radius: 0.75rem !important;
+ }
+}
+
+/* Alert und Modal Responsivität */
+.alert-professional {
+ border-radius: 1.5rem !important;
+ padding: 2rem !important;
+ margin-bottom: 2rem !important;
+}
+
+@media (max-width: 640px) {
+ .alert-professional {
+ padding: 1.5rem !important;
+ margin-bottom: 1.5rem !important;
+ border-radius: 1rem !important;
+ }
+}
+
+/* Status Card Responsivität */
+.status-professional {
+ display: inline-flex !important;
+ align-items: center !important;
+ gap: 0.5rem !important;
+ padding: 0.75rem 1rem !important;
+ border-radius: 2rem !important;
+ font-size: 0.875rem !important;
+ font-weight: 700 !important;
+ border: 1px solid transparent !important;
+}
+
+@media (max-width: 640px) {
+ .status-professional {
+ padding: 0.5rem 0.75rem !important;
+ font-size: 0.75rem !important;
+ border-radius: 1rem !important;
+ }
+}
+
+/* Button Responsivität */
+.btn-professional {
+ display: inline-flex !important;
+ align-items: center !important;
+ justify-content: center !important;
+ background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%) !important;
+ color: white !important;
+ border: none !important;
+ border-radius: 1rem !important;
+ font-weight: 700 !important;
+ text-decoration: none !important;
+ transition: all 0.3s ease !important;
+ box-shadow: 0 4px 15px rgba(59, 130, 246, 0.3) !important;
+}
+
+.btn-professional:hover {
+ background: linear-gradient(135deg, #1d4ed8 0%, #1e40af 100%) !important;
+ transform: translateY(-2px) !important;
+ box-shadow: 0 8px 25px rgba(59, 130, 246, 0.4) !important;
+ color: white !important;
+}
+
+@media (max-width: 640px) {
+ .btn-professional {
+ width: 100% !important;
+ justify-content: center !important;
+ padding: 1rem 2rem !important;
+ font-size: 1rem !important;
+ }
+}
+
+/* Hero Header Responsivität */
+.professional-hero {
+ position: relative !important;
+ overflow: hidden !important;
+ background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%) !important;
+ border: 1px solid #e2e8f0 !important;
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1) !important;
+}
+
+.dark .professional-hero {
+ background: linear-gradient(135deg, #000000 0%, #1a1a1a 100%) !important;
+ border-color: #333333 !important;
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5) !important;
+}
+
+/* Mobile Navigation Verbesserungen */
+@media (max-width: 1024px) {
+ .navbar-menu-new {
+ display: none !important;
+ }
+
+ .mobile-menu-new {
+ background: rgba(255, 255, 255, 0.95) !important;
+ backdrop-filter: blur(20px) !important;
+ border-top: 1px solid rgba(0, 0, 0, 0.1) !important;
+ }
+
+ .dark .mobile-menu-new {
+ background: rgba(0, 0, 0, 0.95) !important;
+ border-top: 1px solid rgba(255, 255, 255, 0.1) !important;
+ }
+
+ .mobile-nav-item {
+ display: flex !important;
+ align-items: center !important;
+ padding: 1rem !important;
+ border-radius: 0.75rem !important;
+ color: #64748b !important;
+ text-decoration: none !important;
+ transition: all 0.3s ease !important;
+ }
+
+ .dark .mobile-nav-item {
+ color: #94a3b8 !important;
+ }
+
+ .mobile-nav-item:hover,
+ .mobile-nav-item.active {
+ background: rgba(59, 130, 246, 0.1) !important;
+ color: #3b82f6 !important;
+ }
+}
+
+/* Container Max-Width Responsivität */
+.max-w-7xl {
+ max-width: 100% !important;
+ padding-left: 1rem !important;
+ padding-right: 1rem !important;
+}
+
+@media (min-width: 640px) {
+ .max-w-7xl {
+ padding-left: 1.5rem !important;
+ padding-right: 1.5rem !important;
+ }
+}
+
+@media (min-width: 768px) {
+ .max-w-7xl {
+ padding-left: 2rem !important;
+ padding-right: 2rem !important;
+ }
+}
+
+@media (min-width: 1024px) {
+ .max-w-7xl {
+ max-width: 80rem !important;
+ padding-left: 2rem !important;
+ padding-right: 2rem !important;
+ }
+}
+
+/* Entferne alle potentiellen eckigen Standard-Hintergründe */
+div, section, article, aside, header, footer, main, nav {
+ background-color: transparent !important;
+}
+
+/* Glasmorphism Verbesserungen */
+.mb-glass {
+ background: rgba(255, 255, 255, 0.9) !important;
+ backdrop-filter: blur(20px) !important;
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1) !important;
+}
+
+.dark .mb-glass {
+ background: rgba(17, 17, 17, 0.95) !important;
+ border: 1px solid rgba(255, 255, 255, 0.1) !important;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important;
+}
+
+/* Entfernt alle Standardhintergründe von Browsern */
+input, textarea, select, button {
+ background-color: transparent !important;
+}
+
+/* Erlaubte Input-Hintergründe */
+.input-professional,
+input[type="text"],
+input[type="email"],
+input[type="password"],
+input[type="number"],
+input[type="datetime-local"],
+textarea,
+select {
+ background: #ffffff !important;
+ border: 2px solid #e2e8f0 !important;
+}
+
+.dark .input-professional,
+.dark input[type="text"],
+.dark input[type="email"],
+.dark input[type="password"],
+.dark input[type="number"],
+.dark input[type="datetime-local"],
+.dark textarea,
+.dark select {
+ background: #1a1a1a !important;
+ border-color: #333333 !important;
+ color: #ffffff !important;
+}
+
+/* Animation Verbesserungen */
+@keyframes fadeInResponsive {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.animate-fade-in {
+ animation: fadeInResponsive 0.6s ease-out !important;
+}
+
+.animate-slide-up {
+ animation: fadeInResponsive 0.8s ease-out !important;
+}
+
+.animate-scale-in {
+ animation: fadeInResponsive 0.5s ease-out !important;
+}
+
+/* Smooth Scrolling */
+html {
+ scroll-behavior: smooth !important;
+}
+
+/* Performance Optimierungen */
+* {
+ box-sizing: border-box !important;
+}
+
+img {
+ max-width: 100% !important;
+ height: auto !important;
+}
+
+/* Accessibility Verbesserungen */
+@media (prefers-reduced-motion: reduce) {
+ * {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ }
+}
+
+/* Focus Indicators */
+button:focus,
+input:focus,
+textarea:focus,
+select:focus,
+a:focus {
+ outline: 2px solid #3b82f6 !important;
+ outline-offset: 2px !important;
+}
+
+/* Entfernt problematische Farben aus allen Elementen */
+[style*="background-color: #182031"],
+[style*="background: #182031"],
+[style*="background-color: #d5d7d8"],
+[style*="background: #d5d7d8"] {
+ background: transparent !important;
+ background-color: transparent !important;
+}
\ No newline at end of file
diff --git a/backend/app/static/js/background-fix.js b/backend/app/static/js/background-fix.js
new file mode 100644
index 00000000..40541df0
--- /dev/null
+++ b/backend/app/static/js/background-fix.js
@@ -0,0 +1,241 @@
+/**
+ * Mercedes-Benz MYP Platform - Background Fix
+ * Entfernt problematische eckige Hintergründe zur Laufzeit
+ */
+
+(function() {
+ 'use strict';
+
+ // Problematische Farben die entfernt werden sollen
+ const problematicColors = [
+ '#182031',
+ '#d5d7d8',
+ 'rgb(24, 32, 49)',
+ 'rgb(213, 215, 216)',
+ 'rgba(24, 32, 49, 1)',
+ 'rgba(213, 215, 216, 1)'
+ ];
+
+ // Funktion zum Entfernen problematischer Hintergründe
+ function removeProblematicBackgrounds() {
+ const allElements = document.querySelectorAll('*');
+
+ allElements.forEach(element => {
+ const computedStyle = window.getComputedStyle(element);
+ const backgroundColor = computedStyle.backgroundColor;
+ const backgroundImage = computedStyle.backgroundImage;
+
+ // Prüfe auf problematische Hintergrundfarben
+ problematicColors.forEach(color => {
+ if (backgroundColor.includes(color.replace('#', '')) ||
+ backgroundColor === color ||
+ backgroundImage.includes(color)) {
+
+ console.log('Entferne problematischen Hintergrund:', color, 'von Element:', element);
+ element.style.background = 'transparent';
+ element.style.backgroundColor = 'transparent';
+ element.style.backgroundImage = 'none';
+ }
+ });
+
+ // Spezielle Checks für inline styles
+ const inlineStyle = element.getAttribute('style');
+ if (inlineStyle) {
+ problematicColors.forEach(color => {
+ if (inlineStyle.includes(color)) {
+ console.log('Entferne problematischen Inline-Style:', color, 'von Element:', element);
+
+ // Entferne problematische Farbe aus inline style
+ let newStyle = inlineStyle
+ .replace(new RegExp(`background-color:\\s*${color.replace('#', '\\#')}[^;]*;?`, 'gi'), '')
+ .replace(new RegExp(`background:\\s*${color.replace('#', '\\#')}[^;]*;?`, 'gi'), '')
+ .replace(/background-color:\s*transparent\s*!important\s*;?\s*/gi, '')
+ .trim();
+
+ if (newStyle !== inlineStyle) {
+ element.setAttribute('style', newStyle);
+ }
+ }
+ });
+ }
+ });
+ }
+
+ // Funktion zum Erzwingen des Mercedes-Designs
+ function enforceDesign() {
+ const isDark = document.documentElement.classList.contains('dark');
+
+ // Haupthintergrund erzwingen
+ document.body.style.background = isDark ? '#000000' : '#f8fafc';
+ document.documentElement.style.background = isDark ? '#000000' : '#f8fafc';
+
+ // Professionelle Container sicherstellen
+ const containers = document.querySelectorAll(
+ '.professional-container, .mb-glass, .card-professional, .bg-professional, .professional-hero'
+ );
+
+ containers.forEach(container => {
+ if (isDark) {
+ container.style.background = '#111111';
+ container.style.borderColor = '#333333';
+ } else {
+ container.style.background = '#f8fafc';
+ container.style.borderColor = '#e2e8f0';
+ }
+ container.style.borderRadius = '2rem';
+ });
+
+ // Input-Felder sicherstellen
+ const inputs = document.querySelectorAll(
+ '.input-professional, input[type="text"], input[type="email"], input[type="password"], input[type="number"], textarea, select'
+ );
+
+ inputs.forEach(input => {
+ if (isDark) {
+ input.style.background = '#1a1a1a';
+ input.style.borderColor = '#333333';
+ input.style.color = '#ffffff';
+ } else {
+ input.style.background = '#ffffff';
+ input.style.borderColor = '#e2e8f0';
+ input.style.color = '#0f172a';
+ }
+ input.style.borderWidth = '2px';
+ input.style.borderRadius = '1rem';
+ });
+ }
+
+ // Funktion zum Überwachen von DOM-Änderungen
+ function observeChanges() {
+ const observer = new MutationObserver(function(mutations) {
+ let shouldCheck = false;
+
+ mutations.forEach(function(mutation) {
+ if (mutation.type === 'childList' || mutation.type === 'attributes') {
+ shouldCheck = true;
+ }
+ });
+
+ if (shouldCheck) {
+ // Kleine Verzögerung um Layout-Thrashing zu vermeiden
+ setTimeout(() => {
+ removeProblematicBackgrounds();
+ enforceDesign();
+ }, 10);
+ }
+ });
+
+ observer.observe(document.body, {
+ childList: true,
+ subtree: true,
+ attributes: true,
+ attributeFilter: ['style', 'class']
+ });
+ }
+
+ // Dark Mode Toggle überwachen
+ function setupDarkModeObserver() {
+ const darkModeObserver = new MutationObserver(function(mutations) {
+ mutations.forEach(function(mutation) {
+ if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
+ const target = mutation.target;
+ if (target === document.documentElement &&
+ (target.classList.contains('dark') || !target.classList.contains('dark'))) {
+
+ // Warte kurz und wende dann das Design neu an
+ setTimeout(() => {
+ enforceDesign();
+ }, 50);
+ }
+ }
+ });
+ });
+
+ darkModeObserver.observe(document.documentElement, {
+ attributes: true,
+ attributeFilter: ['class']
+ });
+ }
+
+ // Entferne CSS-Klassen die problematische Hintergründe verursachen könnten
+ function removeProblematicClasses() {
+ const elements = document.querySelectorAll('*');
+ const problematicClassPatterns = [
+ /bg-slate-\d+/,
+ /bg-gray-\d+/,
+ /bg-zinc-\d+/
+ ];
+
+ elements.forEach(element => {
+ const classList = Array.from(element.classList);
+ let classesRemoved = false;
+
+ classList.forEach(className => {
+ problematicClassPatterns.forEach(pattern => {
+ if (pattern.test(className)) {
+ console.log('Entferne problematische CSS-Klasse:', className, 'von Element:', element);
+ element.classList.remove(className);
+ classesRemoved = true;
+ }
+ });
+ });
+
+ if (classesRemoved) {
+ // Füge professional classes hinzu
+ if (!element.classList.contains('bg-professional') &&
+ !element.classList.contains('professional-container') &&
+ !element.classList.contains('mb-glass')) {
+ // Nur bei bestimmten Elementen
+ if (element.tagName === 'DIV' || element.tagName === 'SECTION') {
+ element.classList.add('bg-professional');
+ }
+ }
+ }
+ });
+ }
+
+ // Initialisierung
+ function init() {
+ console.log('Mercedes-Benz Background Fix - Initialisierung');
+
+ // Sofort ausführen
+ removeProblematicBackgrounds();
+ removeProblematicClasses();
+ enforceDesign();
+
+ // Observer einrichten
+ observeChanges();
+ setupDarkModeObserver();
+
+ // Regelmäßige Überprüfung alle 5 Sekunden
+ setInterval(() => {
+ removeProblematicBackgrounds();
+ enforceDesign();
+ }, 5000);
+
+ console.log('Mercedes-Benz Background Fix - Aktiv');
+ }
+
+ // Starten wenn DOM bereit ist
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', init);
+ } else {
+ init();
+ }
+
+ // Auch beim Laden von Ressourcen
+ window.addEventListener('load', () => {
+ setTimeout(() => {
+ removeProblematicBackgrounds();
+ enforceDesign();
+ }, 100);
+ });
+
+ // Expose für Debug-Zwecke
+ window.mercedesBackgroundFix = {
+ removeProblematicBackgrounds,
+ enforceDesign,
+ removeProblematicClasses
+ };
+
+})();
\ No newline at end of file
diff --git a/backend/app/templates/base.html b/backend/app/templates/base.html
index f4a7ac6f..5263ec8d 100644
--- a/backend/app/templates/base.html
+++ b/backend/app/templates/base.html
@@ -29,6 +29,7 @@
+
@@ -488,6 +489,7 @@
+
{% if current_user.is_authenticated %}