From 4e74f72c9fdc267bbe7092dd1519bdb1c58bea64 Mon Sep 17 00:00:00 2001 From: olaf Date: Sun, 31 Aug 2025 07:30:53 +0000 Subject: [PATCH] multiple corrections on docker-compose and Dockerfile robust start sequence avoid scrolling of main content --- dashboard/Dockerfile | 53 +++++++++++++++++++++------------- dashboard/Dockerfile.dev | 42 +++++++++++++++++---------- dashboard/package.json | 2 +- dashboard/src/App.css | 37 +++++++++++++++++++----- dashboard/src/App.tsx | 6 ++-- dashboard/src/programminfo.tsx | 44 +++++++++++++++------------- dashboard/vite.config.ts | 11 +++++-- dashboard/wait-for-backend.sh | 24 +++++++++++++++ docker-compose.yml | 32 ++++++++++---------- server/Dockerfile | 34 +++++++++++++++++----- server/Dockerfile.dev | 44 ++++++++++++---------------- 11 files changed, 211 insertions(+), 118 deletions(-) create mode 100755 dashboard/wait-for-backend.sh diff --git a/dashboard/Dockerfile b/dashboard/Dockerfile index 8385cd5..c62a1ce 100644 --- a/dashboard/Dockerfile +++ b/dashboard/Dockerfile @@ -1,39 +1,52 @@ # ========================================== # dashboard/Dockerfile (Production) +# 🔧 OPTIMIERT: Multi-Stage-Build für ein minimales Produktions-Image # ========================================== -FROM node:lts-alpine AS builder + +# Stage 1: Build-Umgebung +FROM node:20-alpine AS build WORKDIR /app -# Copy package files -COPY package*.json ./ -COPY pnpm-lock.yaml* ./ +# Kopiere package.json und pnpm-lock.yaml +COPY package.json pnpm-lock.yaml ./ -# Install pnpm and dependencies -RUN npm install -g pnpm -RUN pnpm install --frozen-lockfile +# Installiere pnpm und dann die Abhängigkeiten +# --prod stellt sicher, dass nur Produktions-Abhängigkeiten installiert werden +RUN npm install -g pnpm && pnpm install --prod --frozen-lockfile -# Copy source code +# Kopiere den restlichen Quellcode COPY . . -# Build arguments -ARG NODE_ENV=production +# Setze Build-Argumente als Umgebungsvariablen ARG VITE_API_URL +ENV VITE_API_URL=${VITE_API_URL} -# Build the application +# Baue die Anwendung für die Produktion RUN pnpm build -# Production stage with nginx -FROM nginx:alpine +# Stage 2: Produktions-Umgebung +FROM nginx:1.25-alpine -# Copy built files to nginx -COPY --from=builder /app/dist /usr/share/nginx/html +# Kopiere die gebauten statischen Dateien aus der Build-Stage +COPY --from=build /app/dist /usr/share/nginx/html -# Copy custom nginx config (optional) -COPY nginx.conf /etc/nginx/nginx.conf +# Optional: Eine Nginx-Konfiguration für Single-Page-Applications (SPA) +# Diese leitet alle Anfragen, die keine Dateien sind, auf die index.html um. +# Erstelle eine Datei `nginx.prod.conf` mit folgendem Inhalt: +# server { +# listen 80; +# root /usr/share/nginx/html; +# index index.html; +# location / { +# try_files $uri $uri/ /index.html; +# } +# } +# COPY nginx.prod.conf /etc/nginx/conf.d/default.conf -# Expose port -EXPOSE 3000 +# Exponiere Port 80 (Standard-HTTP-Port von Nginx) +EXPOSE 80 -# Start nginx +# Starte Nginx CMD ["nginx", "-g", "daemon off;"] + diff --git a/dashboard/Dockerfile.dev b/dashboard/Dockerfile.dev index 0dfab4c..e4450ec 100644 --- a/dashboard/Dockerfile.dev +++ b/dashboard/Dockerfile.dev @@ -1,24 +1,36 @@ # ========================================== # dashboard/Dockerfile.dev (Development) +# 🔧 OPTIMIERT: Für schnelle Entwicklung mit Vite und pnpm # ========================================== -FROM node:lts-alpine +FROM node:20-alpine +# Setze das Arbeitsverzeichnis auf den Workspace-Root, um die Pfade aus +# docker-compose.override.yml korrekt aufzulösen. +WORKDIR /workspace + +# 🔧 HINZUGEFÜGT: Installiere curl, damit das wait-for-backend.sh Skript funktioniert +RUN apk add --no-cache curl + +# Installiere pnpm, da es im Projekt verwendet wird. +RUN npm install -g pnpm + +# Kopiere die package-Dateien in das korrekte Unterverzeichnis. +# Dies nutzt den Docker-Cache: Wenn sich die Dateien nicht ändern, +# wird der `pnpm install`-Schritt übersprungen. +COPY package.json pnpm-lock.yaml* ./ + +# Wechsle in das Dashboard-Verzeichnis, um die Befehle auszuführen. WORKDIR /workspace/dashboard -# Install dependencies manager (pnpm optional, npm reicht für Compose-Setup) -# RUN npm install -g pnpm +# Installiere ALLE Abhängigkeiten (inkl. devDependencies) +RUN pnpm install -# Copy package files -COPY package*.json ./ +# Das Kopieren des restlichen Codes ist nicht nötig, da das gesamte +# Verzeichnis `./:/workspace` in der docker-compose.override.yml gemountet wird. -# Install dependencies (nutze npm, da Compose "npm run dev" nutzt) -RUN npm install +# Exponiere die Ports für Vite und Node-Debugging +EXPOSE 5173 9229 -# Copy source code -COPY . . - -# Expose ports -EXPOSE 3000 9229 - -# Standard-Dev-Command (wird von Compose überschrieben) -CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "3000"] \ No newline at end of file +# Der Startbefehl wird in der docker-compose.override.yml definiert. +# Ein Standard-CMD ist dennoch eine gute Praxis. +CMD ["pnpm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "5173"] diff --git a/dashboard/package.json b/dashboard/package.json index 04e62b2..439b759 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite --host 0.0.0.0 --port 3000", + "dev": "vite", "build": "tsc -b && vite build", "lint": "eslint .", "preview": "vite preview" diff --git a/dashboard/src/App.css b/dashboard/src/App.css index bf101df..4429f16 100644 --- a/dashboard/src/App.css +++ b/dashboard/src/App.css @@ -17,6 +17,7 @@ body { font-family: Inter, 'Segoe UI', Roboto, Arial, sans-serif; + overflow: hidden; /* Verhindert den Scrollbalken auf der obersten Ebene */ } :root { @@ -28,6 +29,7 @@ body { /* Layout-Container für Sidebar und Content */ .layout-container { display: flex; + position: relative; /* Wichtig für die absolute Positionierung des Inhalts */ height: 100vh; /* Feste Höhe auf die des Viewports setzen */ overflow: hidden; /* Verhindert, dass der Scrollbalken den gesamten Container betrifft */ } @@ -40,6 +42,7 @@ body { font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; flex-shrink: 0; overflow: hidden; + z-index: 10; /* Stellt sicher, dass die Sidebar über dem Inhalt ist */ } .sidebar-theme .sidebar-link { @@ -73,16 +76,36 @@ body { color: var(--sidebar-bg); } +/* === START: ROBUSTES ABSOLUTE-POSITIONING-LAYOUT === */ -/* Nur der Page-Content bekommt den horizontalen Scrollbalken */ -.page-content-scroll { - flex: 1 1 auto; - overflow-x: auto; - padding: 16px; /* Optional: Abstand innerhalb des Contents */ - height: 100%; - box-sizing: border-box; /* Padding wird in die Breite/Höhe einbezogen */ +/* Der Inhaltsbereich wird absolut positioniert, um den Rest des Bildschirms auszufüllen */ +.content-area { + position: absolute; + inset: 0 0 0 16rem; /* Shorthand für top, right, bottom, left */ + display: flex; + flex-direction: column; + transition: inset-inline-start 0.3s ease-in-out; /* Animiert die 'left' Eigenschaft */ } +/* Anpassung für die eingeklappte Sidebar */ +.content-area.collapsed { + left: 5rem; /* Breite der eingeklappten Sidebar (w-20) */ +} + +.content-header { + flex-shrink: 0; /* Header soll nicht schrumpfen */ +} + +.page-content { + flex-grow: 1; /* Füllt den verbleibenden Platz */ + overflow-y: auto; /* NUR dieser Bereich scrollt */ + padding: 2rem; + background-color: #f3f4f6; +} + +/* === ENDE: ROBUSTES ABSOLUTE-POSITIONING-LAYOUT === */ + + /* Kanban-Karten im Sidebar-Style */ .e-kanban .e-card, .e-kanban .e-card .e-card-content, diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index 5e26fbc..454d31f 100644 --- a/dashboard/src/App.tsx +++ b/dashboard/src/App.tsx @@ -116,10 +116,10 @@ const Layout: React.FC = () => { {/* Main Content */} -
+
{/* Header */}
{ [Organisationsname]
-
+
diff --git a/dashboard/src/programminfo.tsx b/dashboard/src/programminfo.tsx index 23a96d3..ac4f57c 100644 --- a/dashboard/src/programminfo.tsx +++ b/dashboard/src/programminfo.tsx @@ -139,26 +139,30 @@ const Programminfo: React.FC = () => {

Verwendete Open-Source-Komponenten

-
-

Frontend

-
    - {info.openSourceComponents.frontend.map(item => ( -
  • - {item.name} ({item.license}-Lizenz) -
  • - ))} -
-
-
-

Backend

-
    - {info.openSourceComponents.backend.map(item => ( -
  • - {item.name} ({item.license}-Lizenz) -
  • - ))} -
-
+ {info.openSourceComponents.frontend && ( +
+

Frontend

+
    + {info.openSourceComponents.frontend.map(item => ( +
  • + {item.name} ({item.license}-Lizenz) +
  • + ))} +
+
+ )} + {info.openSourceComponents.backend && ( +
+

Backend

+
    + {info.openSourceComponents.backend.map(item => ( +
  • + {item.name} ({item.license}-Lizenz) +
  • + ))} +
+
+ )}
diff --git a/dashboard/vite.config.ts b/dashboard/vite.config.ts index e04aa16..a0ef3f8 100644 --- a/dashboard/vite.config.ts +++ b/dashboard/vite.config.ts @@ -5,9 +5,16 @@ import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], server: { + host: '0.0.0.0', + watch: { + usePolling: true, + }, + fs: { + strict: false, + }, proxy: { - '/api': 'http://localhost:8000', - '/screenshots': 'http://localhost:8000', + '/api': 'http://server:8000', + '/screenshots': 'http://server:8000', }, }, }); diff --git a/dashboard/wait-for-backend.sh b/dashboard/wait-for-backend.sh new file mode 100755 index 0000000..996f438 --- /dev/null +++ b/dashboard/wait-for-backend.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# wait-for-backend.sh + +# Stellt sicher, dass das Skript bei einem Fehler abbricht +set -e + +# Der erste Parameter ist der Host, der erreicht werden soll +host="$1" +# Alle weiteren Parameter bilden den Befehl, der danach ausgeführt werden soll +shift +cmd="$@" + +# Schleife, die so lange läuft, bis der Host mit einem erfolgreichen HTTP-Status antwortet +# curl -s: silent mode (kein Fortschrittsbalken) +# curl -f: fail silently (gibt einen Fehlercode > 0 zurück, wenn der HTTP-Status nicht 2xx ist) +until curl -s -f "$host" > /dev/null; do + >&2 echo "Backend ist noch nicht erreichbar - schlafe für 2 Sekunden" + sleep 2 +done + +# Wenn die Schleife beendet ist, ist das Backend erreichbar +>&2 echo "Backend ist erreichbar - starte Vite-Server..." +# Führe den eigentlichen Befehl aus (z.B. npm run dev) +exec $cmd diff --git a/docker-compose.yml b/docker-compose.yml index 30a7d22..77a24b5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ - networks: infoscreen-net: driver: bridge @@ -18,19 +17,19 @@ services: condition: service_healthy environment: - DB_URL=mysql+pymysql://${DB_USER}:${DB_PASSWORD}@db/${DB_NAME} - volumes: - - ./listener:/app:rw + # 🔧 ENTFERNT: Volume-Mount ist nur für die Entwicklung networks: - infoscreen-net + proxy: - image: nginx:stable + image: nginx:1.25 # 🔧 GEÄNDERT: Spezifische Version container_name: infoscreen-proxy ports: - "80:80" - "443:443" volumes: - - ${PWD}/nginx.conf:/etc/nginx/nginx.conf:ro - - ${PWD}/certs:/etc/nginx/certs:ro + - ./nginx.conf:/etc/nginx/nginx.conf:ro # 🔧 GEÄNDERT: Relativer Pfad + - ./certs:/etc/nginx/certs:ro # 🔧 GEÄNDERT: Relativer Pfad depends_on: - server - dashboard @@ -38,7 +37,7 @@ services: - infoscreen-net db: - image: mariadb:lts + image: mariadb:11.2 # 🔧 GEÄNDERT: Spezifische Version container_name: infoscreen-db restart: unless-stopped environment: @@ -60,7 +59,7 @@ services: start_period: 30s mqtt: - image: eclipse-mosquitto:2.0.21 + image: eclipse-mosquitto:2.0.21 # ✅ GUT: Version ist bereits spezifisch container_name: infoscreen-mqtt restart: unless-stopped volumes: @@ -114,9 +113,8 @@ services: build: context: ./dashboard dockerfile: Dockerfile - # ✅ HINZUGEFÜGT: Build-Args für React Production Build + # 🔧 VEREINFACHT: Build-Args werden durch Umgebungsvariablen gesetzt args: - - NODE_ENV=production - VITE_API_URL=${API_URL} image: infoscreen-dashboard:latest container_name: infoscreen-dashboard @@ -125,20 +123,20 @@ services: server: condition: service_healthy environment: - # ✅ GEÄNDERT: React-spezifische Umgebungsvariablen - - VITE_API_URL=${API_URL} - NODE_ENV=production - ports: - - "3000:3000" # ✅ GEÄNDERT: Standard React/Vite Port + - VITE_API_URL=${API_URL} + # 🔧 ENTFERNT: Port wird in Produktion nicht direkt freigegeben, Zugriff via Proxy networks: - infoscreen-net - # ✅ GEÄNDERT: Healthcheck für React App healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3000/"] + # 🔧 GEÄNDERT: Healthcheck prüft den Nginx-Server im Container + test: ["CMD", "curl", "-f", "http://localhost/"] interval: 30s timeout: 5s retries: 3 - start_period: 30s + # 🔧 ERHÖHT: Gibt dem Backend mehr Zeit zum Starten, bevor dieser + # Container als "gesund" markiert wird. + start_period: 60s scheduler: build: diff --git a/server/Dockerfile b/server/Dockerfile index d649576..fa0945d 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,16 +1,33 @@ # server/Dockerfile -# Produktions-Dockerfile für die Flask-API mit Gunicorn +# 🔧 OPTIMIERT: Multi-Stage-Build für ein minimales und sicheres Produktions-Image -# --- Basisimage --- +# Stage 1: Builder - Installiert Abhängigkeiten +FROM python:3.13-slim AS builder + +WORKDIR /app + +# Installiert nur die für den Build notwendigen Systemabhängigkeiten +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + libmariadb-dev-compat libmariadb-dev gcc \ + && rm -rf /var/lib/apt/lists/* + +# Kopiert nur die requirements.txt, um den Docker-Cache optimal zu nutzen +COPY requirements.txt . + +# Installiert die Python-Pakete in ein separates Verzeichnis +RUN pip install --no-cache-dir --prefix="/install" -r requirements.txt + +# Stage 2: Final - Das eigentliche Produktions-Image FROM python:3.13-slim # --- Arbeitsverzeichnis --- WORKDIR /app -# --- Systemabhängigkeiten für MariaDB-Client & Locale --- +# Installiert nur die für die Laufzeit notwendigen Systemabhängigkeiten RUN apt-get update \ && apt-get install -y --no-install-recommends \ - libmariadb-dev-compat libmariadb-dev locales git\ + libmariadb-dev-compat locales \ && rm -rf /var/lib/apt/lists/* # --- Locale konfigurieren --- @@ -19,12 +36,12 @@ RUN sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \ ENV LANG=de_DE.UTF-8 \ LC_ALL=de_DE.UTF-8 -# --- Python-Abhängigkeiten --- -COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt +# Kopiert die installierten Pakete aus der Builder-Stage +COPY --from=builder /install /usr/local # --- Applikationscode --- -COPY server/ /app +# Kopiert den Server-Code in das Arbeitsverzeichnis +COPY server/ . # --- Non-Root User anlegen und Rechte setzen --- ARG USER_ID=1000 @@ -40,3 +57,4 @@ EXPOSE 8000 # --- Startbefehl für Gunicorn --- CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "wsgi:app"] + diff --git a/server/Dockerfile.dev b/server/Dockerfile.dev index fa4492d..87b1780 100644 --- a/server/Dockerfile.dev +++ b/server/Dockerfile.dev @@ -1,15 +1,15 @@ # Datei: server/Dockerfile.dev -# Entwicklungs-Dockerfile für die API (Flask + SQLAlchemy) +# 🔧 OPTIMIERT: Für die Entwicklung im Dev-Container +# ========================================== FROM python:3.13-slim -# Build args für UID/GID +# Die Erstellung des non-root Users und die Locale-Konfiguration +# sind für den Dev-Container nicht zwingend nötig, da VS Code sich als 'root' +# verbindet (gemäß devcontainer.json). Sie schaden aber nicht. ARG USER_ID=1000 ARG GROUP_ID=1000 - -# Erstelle non-root User -RUN apt-get update \ - && apt-get install -y --no-install-recommends locales curl \ +RUN apt-get update && apt-get install -y --no-install-recommends locales curl git \ && groupadd -g ${GROUP_ID} infoscreen_taa \ && useradd -u ${USER_ID} -g ${GROUP_ID} --shell /bin/bash --create-home infoscreen_taa \ && sed -i 's/# de_DE.UTF-8 UTF-8/de_DE.UTF-8 UTF-8/' /etc/locale.gen \ @@ -17,32 +17,26 @@ RUN apt-get update \ && rm -rf /var/lib/apt/lists/* ENV LANG=de_DE.UTF-8 \ - LANGUAGE=de_DE:de \ LC_ALL=de_DE.UTF-8 -# Arbeitsverzeichnis -WORKDIR /app +# Setze das Arbeitsverzeichnis auf den Workspace-Root, passend zu den Mounts. +WORKDIR /workspace -# Kopiere nur Requirements für schnellen Rebuild -COPY requirements.txt ./ -COPY requirements-dev.txt ./ +# Kopiere die Anforderungsdateien in das korrekte Unterverzeichnis. +# ✅ KORRIGIERT: Pfade sind jetzt relativ zum Build-Kontext (dem 'server'-Verzeichnis) +COPY requirements.txt requirements-dev.txt ./ -# Installiere Python-Abhängigkeiten (Prod + Dev) +# Installiere die Python-Abhängigkeiten RUN pip install --upgrade pip \ && pip install --no-cache-dir -r requirements.txt \ - && pip install --no-cache-dir -r requirements-dev.txt + && pip install --no-cache-dir -r requirements-dev.txt -# Expose Ports für Flask API -EXPOSE 8000 -EXPOSE 5678 +# Das Kopieren des Codes ist nicht nötig, da das Verzeichnis gemountet wird. -# Setze Env für Dev -ENV FLASK_ENV=development -ENV ENV_FILE=.env +# Exponiere die Ports für die Flask API und den Debugger +EXPOSE 8000 5678 -# Wechsle zum non-root User -USER infoscreen_taa +# Der Startbefehl wird in der docker-compose.override.yml definiert. +# Ein Standard-CMD dient als Fallback. +CMD ["python", "-m", "debugpy", "--listen", "0.0.0.0:5678", "-m", "flask", "run", "--host=0.0.0.0", "--port=8000"] -# Default Command: Flask Development Server -CMD ["python", "-m", "debugpy", "--listen", "0.0.0.0:5678", "wsgi.py"] -# CMD ["sleep", "infinity"]