Files
wdm/README.md
T
bryan.hoffmann 36180448e1
Build und Push Docker Image / build-and-push (push) Failing after 49s
Initial commit
2026-08-20 12:24:38 +02:00

209 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# WDM Performance Produktionserfassung für ~40 Maschinen
Flask-Backend mit **serverseitigem Rendering** (Jinja2-Templates, normale
HTML-Formulare, Post-Redirect-Get) **kein Client-JavaScript**, genau wie
beim Essensportal-Projekt. Postgres-Datenbank.
## Start
```bash
cp .env.example .env
# .env anpassen (Passwort etc.)
docker compose up -d --build
```
Die Anwendung ist danach unter `http://<server>:8090/` erreichbar (Port über
`APP_PORT` in `.env` änderbar).
**Wichtig zur DB-Initialisierung:** `build/db/init.sql` (= dein hochgeladenes Schema,
ergänzt um ein paar Beispiel-Abweichungsgründe) wird **nur beim allerersten
Start** ausgeführt, wenn das Datenvolume noch leer ist. Hast du bereits eine
bestehende Postgres-Datenbank mit Daten, dann:
- entweder das `db`-Volume vor dem ersten Start leer lassen und `init.sql`
anpassen/ersetzen, **oder**
- den `db`-Service in `docker-compose.yml` entfernen und stattdessen über
`DB_HOST` / `DB_PORT` / `DB_NAME` / `DB_USER` / `DB_PASSWORD` in der `.env`
auf deine bestehende Datenbank zeigen.
## Aufruf der einzelnen Seiten
- Maschine N (140): `http://<server>:8090/m<N>`
z.B. `http://<server>:8090/m1`
- Produktionsleiter: `http://<server>:8090/start`
**Alte/lange URL-Form:** `http://<server>:8090/m<N>_m_view_main` (z.B.
`.../m1_m_view_main`) funktioniert unverändert weiter und zeigt auf
dieselbe Seite. Sie bleibt bewusst zusätzlich zur kurzen Form erhalten,
damit bereits auf Tablets als Kiosk-Startseite/Lesezeichen hinterlegte
URLs nicht angepasst werden müssen. Für neu eingerichtete Geräte reicht
die kurze Form `/m<N>`.
**Hinweis zum ursprünglich gewünschten `#/...`-Format:** Ein Hash-Fragment
(`#/...`) wird nie an den Server geschickt und funktioniert nur mit
Client-JavaScript, das per Definition entfällt (kein JS). Deshalb sind die
Seiten stattdessen unter echten Server-Pfaden mit denselben Bezeichnern
erreichbar (ohne `#`).
Die Maschinennummer `<N>` entspricht der `id` in der Tabelle `Maschinen`.
Für Tablets an den Maschinen einfach jeweils die passende URL als
Startseite/Kiosk-Link einrichten.
**Reverse Proxy:** Falls du die App hinter einem Unterpfad (z.B.
`/app/wdm-performance/`) betreiben willst, muss der Proxy diesen Präfix vor
Weiterleitung an den Container **entfernen** (strip prefix), da das
Backend mit wurzelrelativen Pfaden arbeitet. Beispiel nginx:
```nginx
location /app/wdm-performance/ {
proxy_pass http://wdm-app:5000/;
}
```
## Funktionsumfang
### Maschinenseite (`/m<N>`, alte Form `/m<N>_m_view_main` weiterhin gültig)
- Überschrift = Maschinenname aus der DB
- Kein aktiver Auftrag → **Start**-Button → Auftragsauswahl (offene/pausierte
Aufträge dieser Maschine, sortiert nach Priorität/`sid`) → Auswahl markiert
Auftrag als aktiv, schreibt `start`-Eintrag in `MDE`
- Aktiver Auftrag → Start-Button ausgeblendet, stattdessen:
- **Prod. erfassen**: Menge (numerisch, ≥0, ≥ bisherige Menge, ≤110% Soll)
+ Pflicht-Dropdown Abweichungsgrund, Server validiert verbindlich vor
dem Schreiben in `MDE`
- **Auftrag pausieren**: gleiche Eingabemaske, setzt Auftrag auf
`status=pause`, `aktiv=false`
- **Auftrag beenden**: bei Menge < Soll erscheint eine große
Bestätigungsabfrage; nach Bestätigung wird die Sollmenge als produziert
in `MDE` (`status=beendet`) vermerkt, Auftrag auf `abgeschlossen` /
`aktiv=false` gesetzt
### Produktionsleiter (`#/start`)
- **Auftrag anlegen**: Maschine (Dropdown), Auftragsnummer, optional Artikel,
Produktionsmenge, Stück/Stunde sowie optional eine **Priorität** (Position
in der Warteschlange dieser Maschine, 1 = als nächstes dran) alles
serverseitig validiert. Wird eine Priorität angegeben, wird der Auftrag an
genau dieser Position eingereiht und alle bestehenden offenen/pausierten
Aufträge dieser Maschine rücken automatisch nach (dichte Nummerierung
1..N, kein bloßes Setzen eines rohen Zahlenwerts). Ohne Angabe wird der
Auftrag ans Ende der Warteschlange gehängt.
- **Aufträge importieren** (`/start_import`): Aufträge aus einer Excel-
(.xlsx) oder CSV-Datei per Drag & Drop oder Dateiauswahl bulk-anlegen,
siehe eigener Abschnitt unten
- **Auftragsübersicht**: alle Aufträge (inkl. Artikel, Maschinenname),
standardmäßig nur offen/pausiert (umschaltbar auf "Alle"), optional nach
Maschine gefiltert, löschbar und (mit Einschränkungen) bearbeitbar:
- **Status und Priorität sind hier nicht editierbar** (nur informativ
angezeigt) Status ändert sich ausschließlich über die eigentlichen
Maschinen-Aktionen (Start/Pause/Beenden), Priorität ausschließlich über
die Drag & Drop-Seite "Auftragspriorität".
- **Aktive Aufträge werden angezeigt, können aber nicht bearbeitet
werden** ein Bearbeitungsversuch (auch ein direkter POST) wird mit
einer Fehlermeldung abgelehnt, solange der Auftrag gerade an der
Maschine läuft.
- Editierbar bleiben Maschine (inkl. automatischem Umhängen der kompletten
MDE-Buchungshistorie auf die neue Maschine), Auftragsnummer, Artikel,
Produktionsmenge und Stück/Stunde.
- **Mengen-Schutz**: Wurde an einem Auftrag bereits eine Menge gemeldet
(MDE-Historie vorhanden), darf die Produktionsmenge nicht mehr so weit
reduziert werden, dass die bereits gemeldete Menge außerhalb der
110%-Toleranz läge (dieselbe Toleranzregel, die auch an der Maschine
beim Erfassen gilt) die App zeigt dabei den konkret noch zulässigen
Mindestwert an.
- **Buchungskorrektur**: direkter Eingriff in die `MDE`-Tabelle (editieren/
löschen), optional nach Maschine gefiltert
- **Auftragspriorität**: Reihenfolge der offenen/pausierten Aufträge je
Maschine per **Drag & Drop** ändern (Auftrag anfassen und an neue Position
ziehen) wird automatisch gespeichert. Funktioniert am PC/Laptop mit
Maus; auf reinen Touch-Geräten ohne Maus ggf. eingeschränkt (Hinweis dazu
steht auf der Seite selbst).
- **Zu Maschine springen**: Direktlinks zu jeder Maschinenseite (zeigt an,
ob die Maschine gerade läuft)
- **Maschinenverwaltung** (`/start_maschinen_verwaltung`, passwortgeschützt):
Maschinen anlegen, umbenennen/Standort ändern, löschen (nur möglich wenn
keine Aufträge mehr an der Maschine hängen). Passwort über die
Umgebungsvariable `MASCHINEN_PASSWORT` in der `.env` konfigurierbar
(Standard `admin` bitte unbedingt ändern!). Für die Login-Session wird
zusätzlich ein `SECRET_KEY` benötigt (ebenfalls in der `.env` setzen).
### Aufträge importieren (`/start_import`)
Excel- (.xlsx) oder CSV-Datei mit (mindestens) diesen Spalten hochladen
(Reihenfolge egal, Erkennung anhand von Stichworten in der Kopfzeile). Die
Datei kann per Drag & Drop auf das gestrichelte Feld gezogen oder klassisch
über die Dateiauswahl ausgewählt werden. Bei CSV werden Zeichenkodierung
(UTF-8/BOM, sonst cp1252), Trennzeichen (Komma, Semikolon wie bei
deutschem Excel-Export üblich oder Tab) sowie deutsches/internationales
Zahlformat (`1.234,56` oder `1234.56`) automatisch erkannt.
| Spalte | Verwendung |
|-------------------|---------------------------------------------------------|
| Maschine | muss exakt (Groß-/Kleinschreibung egal) einer bestehenden Maschine entsprechen, sonst wird die Zeile verworfen |
| man. Prio | wird direkt als Priorität (`sid`) übernommen (das Feld erlaubt auch Kommazahlen, z.B. `15.1`) |
| FA.-Nr. | → Auftragsnummer. Existiert diese FA.-Nr. bereits irgendwo im System, wird die Zeile unangetastet übersprungen |
| Rest-Menge | zusammen mit Ist-Menge → Produktionsmenge (Soll) = Rest + Ist |
| Ist-Menge | wird als bereits produzierte Menge übernommen (Start-Buchung in `MDE`), damit Fortschritt und Mengen-Validierung an der Maschine korrekt weiterlaufen |
| Artikel | wird 1:1 übernommen und angezeigt |
| Soll-pro-Stunde | → Stück/Stunde (Soll) |
| Bezeichnung, Auftrag, Lieferdatum, Bemerkung | werden ignoriert |
Ist die Rest-Menge einer Zeile `0`, wird der Auftrag direkt mit Status
"Abgeschlossen" angelegt (inkl. passender Buchung in der MDE-Historie).
Nach dem Import zeigt die Seite eine Liste, was importiert, was wegen
unbekannter Maschine verworfen und was wegen bereits vorhandener FA.-Nr.
übersprungen wurde.
### Artikel
Neues, optionales Textfeld je Auftrag (Spalte `artikel`). Kann beim
manuellen Anlegen eingetragen werden oder kommt aus dem Import; wird auf der
Maschinenseite, in der Auftragsauswahl, der Auftragsübersicht, der
Prioritätsliste und (sofern gerade ein Auftrag aktiv ist) auch in der
Maschinenübersicht ("Zu Maschine springen") mit angezeigt.
### Logo / Icon
`build/static/logo.svg` wird als Favicon und (in doppelter Standardgröße,
104×104px) über dem Seitentitel angezeigt. Einfach durch eine eigene Datei
mit demselben Namen (`logo.svg`, idealerweise quadratisch) ersetzen, um das
Firmenlogo einzubinden kein Code muss dafür angepasst werden.
### JavaScript-Einsatz (Ausnahmen vom "kein Client-JS"-Grundsatz)
Zwei bewusste, punktuelle Ausnahmen von der sonst reinen Server-Side-
Rendering-Philosophie:
- Die Filter-Dropdowns (Maschine/Status) in Auftragsübersicht, Buchungs-
korrektur und Auftragspriorität lösen die Filterung direkt beim Auswählen
aus (`onchange`-Submit) reiner Komfort, der "Filtern"-Button bleibt als
Fallback sichtbar und funktioniert auch ohne JavaScript.
- Die Drag-&-Drop-Sortierung auf der Auftragspriorität-Seite benötigt
zwingend JavaScript (ohne JS erscheint dort ein Hinweis, dass Sortieren
nicht möglich ist alle anderen Seiten funktionieren weiterhin ohne JS).
## Stabilität im Dauerbetrieb
- Backend läuft unter `gunicorn` (mehrere Worker/Threads statt Flask-Devserver)
- Datenbank-Connection-Pool mit automatischem Retry beim Start (verträgt
verzögerten DB-Start ohne Absturz)
- Docker-Healthchecks für App und DB, `restart: unless-stopped`
- Reines Server-Side-Rendering ohne Build-Step und ohne Client-JavaScript
jede Aktion ist ein klassischer Formular-Submit (Post-Redirect-Get), das
ist auf Tablets mit älteren/eingeschränkten Browsern besonders robust
## Struktur
```
wdm-performance/
├── Dockerfile Build-Anweisungen (Kontext = Projektwurzel)
├── docker-compose.yml
├── README.md
├── .env.example
└── build/
├── app.py Flask-Anwendung (alle Routen, Server-Side-Rendering)
├── db.py DB-Pool mit Retry-Logik
├── requirements.txt
├── db/init.sql Schema (dein Dump + Beispiel-Abweichungsgründe)
├── templates/ Jinja2-HTML-Templates (kein JavaScript)
└── static/
└── style.css Großflächiges Touch-Design
```
Wichtig: `docker compose` muss aus dem Projektwurzel-Verzeichnis heraus
aufgerufen werden (dort, wo `docker-compose.yml` liegt), nicht aus `build/`.