RUDI RegioFrucht Unternehmens Daten Intelligenz

RUDI ist die KI-gestuetzte Unternehmens-Intelligenz der Regio Frucht GmbH (kuechenfertige Verarbeitung von Obst, Gemuese und Salaten). RUDI kombiniert einen Claude-basierten KI-Chat mit einem vollstaendigen QMS-System nach IFS Food 8.

Kernfunktionen

  • KI-Chat mit Tool-Zugriff auf Dateisystem, QMS und System
  • QMS Dashboard mit Gap-Analyse (127 IFS-Anforderungen, Ampelsystem)
  • Automatische Dokumentenerstellung aus Firmenvorlage (Word DOCX)
  • Dateibrowser mit Vorschau fuer PDF, Excel, Word, Code
  • Spracheingabe (Web Speech API + Whisper-Transkription)

Modul-Uebersicht

Alle RUDI-Module auf einen Blick. Fuer die interaktive Version: System-Karte

ModulFrontendAPI-Route~EndpunkteClaude-ToolsStatus
Chat/chat/chat.js1 (SSE)68 (alle)aktiv
QMS/qms/qms.js~20gap_analysis, search_qms_files, create_qms_document, ...aktiv
Reklamationen/qms/reklamation.htmlqms.js7qms_save_erkenntnis, qms_create_documentaktiv
Maschinen/maschinen/maschinen.js18maschinen_liste, maschinen_info, wartung_*aktiv
Vorschlaege/vorschlaege/vorschlaege.js8vorschlag_erstellen, vorschlaege_lesen, ...aktiv
Pipeline/pipeline/pipeline.js16pipeline_save_hinweis, pipeline_read_hinweiseaktiv
Einkauf/einkauf/einkauf.js~12(via Chat-Kontext)aktiv
Fuhrpark(Dashboard-Kachel)fuhrpark.js~10(via Chat-Kontext)aktiv
Produktionsplanung/produktionsplanung/produktionsplanung.js~8get_batch_planaktiv
Intelligence(via Chat)intelligence.js6semantic_search, find_similaraktiv
Kommunikation/kommunikation/email.js, kalender.js~18email_inbox, email_senden, kalender_termine, kalender_termin_erstellenaktiv
QMS-E-Mail(im QMS-Dashboard)qms.js (Email-Endpoints)~8qms_email_inbox, qms_email_entwurfaktiv
System/system/system.js5system_info, audit_runaktiv
Dateien/dateien/files.js~15read_file, write_file, list_directory, ...aktiv
HFX360/hfx360/hfx360.js~25hfx360_api_status, hfx360_auftrag_vorschauaktiv
Verkauf/verkauf/kunden.js~10kunden_info, kunden_liste, kunden_touren_uebersichtaktiv
Etiketten/etiketten/etiketten.js~12(via Agent-Token)aktiv
Mein RUDI PWA/mein/mein.js~30memory_*, mein_config, todo_*, routine_*, mail_regel_verwaltenaktiv
Admin/admin/auth.js (admin)~8aktiv (nur Rolle admin)
Benachrichtigungen/benachrichtigungen/push.js~6aktiv (VAPID)
Downloads/downloads/(statisch)Notfall-PDF
Lager/lager/lager.js~14lager_artikel_*, lager_platz_*, lager_bild_analysieren, lager_statsaktiv
Leergut/leergut/leergut.js~6(geplant 2026-Q3, OCR+Vision+Acumatica)Frontend-Stub
Intratool/intratool/intratool.js~5aktiv (Token-Auth)
Verkaufsanalyse/verkaufsanalyse/verkaufsanalyse.js~6verkaufsmengen_abfragenaktiv
Verkaufspreise/verkaufspreise/(statisch + via Einkauf)preise_abfragen, preis_analyseaktiv
Bestellungen/einkauf/bestellungen.htmlbestellung.js~7bestellung_erfassen, bestellung_kopierenaktiv

Architektur

Internet
  |
  HTTPS (Let's Encrypt)
  |
Nginx Reverse Proxy (:443)
  |-- Basic Auth (global)
  |-- Security Headers (HSTS, CSP, XSS)
  |-- Rate Limiting (10 req/min Chat)
  |
  |-- /              --> /var/www/html/         (Zentrale)
  |-- /qms/          --> /var/www/qms/          (QMS Dashboard)
  |-- /system/       --> /var/www/html/system/  (System Dashboard)
  |-- /dateien/      --> /var/www/dateien/       (Dateibrowser)
  |-- /chat/         --> proxy 127.0.0.1:3456   (Node.js App)
  |-- /chat/api/*    --> proxy 127.0.0.1:3456   (REST API)

Node.js/Express (:3456, nur localhost)
  |-- Claude API (claude-opus-4-6)
  |-- Agentic Tool Loop (max 10 Iterationen)
  |-- 14 Tools
  |-- SSE Streaming

Projektstruktur

PfadInhalt
~/rudi-chat/server.jsBackend Entry-Point (Express-Setup, Route-Mounting, 39 Zeilen)
~/rudi-chat/lib/shared.jsGemeinsame Funktionen, Pfade, Konstanten, QMS-Helpers
~/rudi-chat/lib/tools.jsTOOLS-Array, System-Prompt, executeTool (Claude-Tools)
~/rudi-chat/lib/validation.jsZentraler Validation-Helper (Phase 0) — Mengen, Preise, Belegnummern, Datum, IBAN, USt-ID, E-Mail, Country-ISO, Chargennummern, Lieferanten-Alias, validateAll-Batch
~/rudi-chat/lib/validation.test.jsStandalone-Testskript (100 Tests, kein Test-Runner) — node ~/rudi-chat/lib/validation.test.js
~/rudi-chat/routes/chat.jsChat-API mit SSE-Streaming und Agentic Loop
~/rudi-chat/routes/qms.jsQMS-Dashboard, Annotations, Recurring, Upload APIs
~/rudi-chat/routes/system.jsSystem-Status API (CPU, RAM, Disk, Services)
~/rudi-chat/routes/vorschlaege.jsÄnderungsvorschläge CRUD + Datei-Upload API
~/rudi-chat/routes/files.jsDatei-Viewer, Chats CRUD, Upload, Transkription
~/rudi-chat/public/Chat-Frontend (erreichbar unter /chat/)
~/rudi-chat/chat-history/Chat-Verlaeufe (JSON pro Chat/User)
~/rudi-chat/audio-handler.jsWhisper-Transkription
/var/www/html/Zentrale (Startseite)
/var/www/qms/QMS Dashboard + Aufgaben
/var/www/dateien/Dateibrowser
~/qms/QMS/QMS-Dateien (unsortiert + Struktur)
~/qms/QMS/QMS_RegioFrucht/Neue QMS-Ordnerstruktur (IFS-konform)
~/qms/QMS/output/arbeitsdaten/IFS-Mapping (JSON, Excel)
~/qms/QMS/Vorlagen/DOCX-Vorlage + Skill-Referenz
/var/www/html/system/System Dashboard
/var/www/html/shared/Shared Components (Chat-Panel CSS + JS)
~/uploads/Benutzer-Uploads (max 50 MB)
~/bin/Hilfsskripte (Layout-Test, Tree-Generator)

Schnellstart

Zugang

URL: https://rudi-regiofrucht.de
Auth: Basic Authentication (Benutzername/Passwort)

Was kann ich RUDI fragen?

Zentrale

Die Startseite unter / zeigt 4 Kacheln im Apple-Glasmorphism-Design:

Das System-Badge laedt dynamisch den Server-Status und zeigt "Alles OK" oder Warnungen an.

Chat

Der Chat unter /chat/ ist das Herztueck von RUDI. Features:

Kontext-Links

Der Chat kann mit Kontext gestartet werden:

URL-ParameterEffekt
?start=systemStartet automatisch einen Systembericht
?start=recurring&rec_id=...Oeffnet eine wiederkehrende Aufgabe
?context=IFS_4.10.1Stellt IFS-Kontext bereit (Anforderung + Leitfaden + Dokumente)
?open=chatIdOeffnet einen bestehenden Chat

Dokumenten-Pipeline

Die Dokumenten-Pipeline unter /pipeline/ verarbeitet eingehende Papierdokumente automatisch. Dokumente werden per Scanner (FTP/FTPS) oder manuellen Upload eingespeist.

Pipeline-Ablauf (Phase 5: Dual-Processing + Vorgang-Verlinkung)

  1. Eingang: Scanner sendet PDF per FTPS an eingang/ oder eingang_personal/
  2. OCR (Dual-Processing): pdfplumber/Tesseract PLUS Claude Vision Cross-Check (Flag pipeline_vision_cross ON)
    • Similarity-Ratio > 0.80: Vision-Text bevorzugt (besser bei Tabellen/Layout), conf=0.95
    • Similarity-Ratio ≤ 0.80: Beide Texte kombiniert, conf=0.70
    • Vision fehlgeschlagen: Tesseract-Fallback automatisch
    • Tagesbudget: max 50 Vision-Calls/Tag (PIPELINE_VISION_MAX). Audit-Log: modul=pipeline-vision
  3. Lieferanten-Normalisierung: Alias-Resolver gegen lieferant_aliase-Tabelle
  4. Dedup-Check: SHA-1-Hash ueber Lieferant+Belegnummer+Betrag+Datum; Duplikate nach ~/pipeline/duplikate/
  5. Klassifikation: Claude API (Sonnet) extrahiert Metadaten als JSON
  6. Ablage: Datei umbenannt + verschoben
  7. DB-Eintrag: pipeline.db mit allen Daten inkl. dedup_hash
  8. Vorgang-Verlinkung (NEU): Pipeline-Dokument wird mit Vorgang in einkauf.db verlinkt (vorgang_referenz.beleg_db='pipeline'). Fuzzy-Lieferant-Match, offener Vorgang ±30 Tage. Kein Vorgang: auto-angelegt.
  9. Abgleich: Automatischer Abgleich Lieferschein/Rechnung

Lieferanten-Aliase

Tabelle lieferant_aliase in pipeline.db normalisiert Schreibvarianten auf kanonische Namen. Migrations-Skript: ~/pipeline/migrations/001_lieferant_aliase.py (idempotent). Aktuell 10 Aliase konfiguriert (Stand 2026-04-27).

Dedup-Hash & Duplikatserkennung

Spalte dedup_hash (SHA-1 ueber Lieferant|Belegnummer|Betrag|Datum) verhindert Doppeleintraege bei Re-Upload. Bestehende Duplikate werden in ~/pipeline/duplikate_vorschlag.json dokumentiert (kein automatisches Loeschen). Migrations-Skript: ~/pipeline/migrations/002_dedup_hash.py (idempotent, Backfill aller vorhandenen Dokumente).

Dashboard-Funktionen

Dokument-Kategorien

KategorieBeschreibungZielordner
lieferant_lsLieferschein (Lieferant)lieferanten/lieferscheine/{Name}/
lieferant_reRechnung (Lieferant)lieferanten/rechnungen/{Name}/
kunde_lsLieferschein (Kunde)kunden/lieferscheine/{Name}/
gutschriftGutschriftkunden/gutschriften/
personal_*Personaldokumente (7 Unterkategorien)personal/{Nachname_Vorname}/{Typ}/
schriftverkehr_*Behoerden, Versicherungen, Sonstigesschriftverkehr/{Typ}/

Scanner-Anbindung (FTPS)

Hintergrundprozess

QMS Dashboard

Das QMS Dashboard unter /qms/ ist als Tab-System aufgebaut mit zwei Tabs:

Tab: Dashboard (Gap-Analyse)

Tab: Aufgaben

Integrierter Aufgaben-Tab (erreichbar ueber /qms/#aufgaben) mit:

Ampelsystem

FarbeBedeutungKriterium
GruenAbgedeckt2+ Quelldokumente zugeordnet
GelbTeilweise1 Quelldokument zugeordnet
RotFehlendKeine Dokumente zugeordnet

Dateibrowser

Der Dateibrowser unter /dateien/ zeigt die gesamte RUDI-Verzeichnisstruktur:

System Dashboard

Das System Dashboard unter /system/ zeigt Server-Informationen in Echtzeit:

Die Daten kommen von der API-Route /chat/api/system/status, die CPU, RAM, Disk und Services ueber das os-Modul und systemctl abruft.

System-Karte (/system/map.html)

Die System-Karte bietet eine interaktive, statische Uebersicht aller RUDI-Komponenten als aufklappbarer Baum:

Änderungsvorschläge

Die Seite /vorschlaege/ sammelt Ideen, Verbesserungen und Bugfixes für RUDI. Vorschläge können manuell per Formular oder im Gespräch mit RUDI erstellt werden.

Funktionen

RUDI-Tools (Vorschläge-Kontext)

Wenn das Chat-Panel auf der Vorschläge-Seite geöffnet wird, erhält RUDI drei zusätzliche Tools:

ToolBeschreibung
vorschlag_erstellenLegt einen neuen Vorschlag an (Titel, Beschreibung, Kategorie, Priorität)
vorschlaege_lesenLiest alle Vorschläge, optional nach Status gefiltert
vorschlag_aktualisierenÄndert Titel, Beschreibung, Kategorie, Priorität oder Status eines Vorschlags

API-Endpunkte

MethodePfadBeschreibung
GET/chat/api/vorschlaege/Alle Vorschläge (neueste zuerst)
GET/chat/api/vorschlaege/statsZähler für Dashboard-Badge
POST/chat/api/vorschlaege/Neuen Vorschlag anlegen
POST/chat/api/vorschlaege/:id/uploadDateien an Vorschlag anhängen (max 10, 50 MB)
PATCH/chat/api/vorschlaege/:idVorschlag bearbeiten
DELETE/chat/api/vorschlaege/:idVorschlag + Dateien löschen
GET/chat/api/vorschlaege/:id/dateien/:nameDatei ausliefern (Vorschau)
DELETE/chat/api/vorschlaege/:id/dateien/:nameEinzelne Datei löschen

Speicherung

Agentic Loop

RUDI nutzt einen agentic Tool-Loop mit Claude. Das bedeutet: Claude kann eigenstaendig Tools aufrufen, die Ergebnisse lesen, und weitere Tools aufrufen – bis zu 10 Iterationen pro Nachricht.

Ablauf

  1. Benutzer sendet Nachricht
  2. Server sendet Nachricht + System-Prompt + letzte 20 Nachrichten an Claude API
  3. Claude antwortet mit Text und/oder Tool-Aufrufen
  4. Falls Tool-Aufrufe: Server fuehrt Tools aus, sendet Ergebnisse zurueck an Claude
  5. Schritte 3-4 wiederholen sich bis Claude fertig ist (max 10x)
  6. Finale Antwort wird per SSE gestreamt
  7. Automatische IFS-Verknuepfung im Hintergrund

Modell: claude-opus-4-6 | Max Tokens: 4096 | Streaming: Echtes SSE-Streaming (Zeichen fuer Zeichen)

Live Tool-Status

Waehrend RUDI im Hintergrund arbeitet (Dateien liest, Dokumente erstellt), zeigt das Chat-Frontend live an, welches Tool gerade laeuft:

Papierkorb

Geloeschte Chats werden nicht sofort entfernt, sondern in einen Papierkorb verschoben (soft delete):

RUDI Tools

RUDI hat 17 Tools zur Verfuegung. Jedes Tool wird von Claude eigenstaendig aufgerufen.

Datei & System

ToolParameterBeschreibung
read_file path Liest Dateien: Text (max 500 KB), DOCX (max 10 MB, via PizZip), PDF (max 20 MB, via pdf-parse), Excel (max 10 MB, via xlsx). Pfad relativ zu /home/regiofrucht/.
list_directory path Listet Dateien und Ordner auf. Zeigt Dateien mit Groesse (KB), Ordner mit Eintragsanzahl.
system_info type Systeminformationen: disk, memory, cpu, services, network, uptime, overview

QMS Analyse

ToolParameterBeschreibung
qms_gap_analysis kapitel (opt.) IFS Gap-Analyse mit Ampelstatus. Zeigt pro Anforderung: Status, Dokumentenanzahl, Text.
qms_list_requirements ref IFS-Anforderungen mit Leitfaden, zugeordneten Dokumenten und Status.
qms_source_documents ref, read_content (opt.) Zeigt alle Quelldokumente einer IFS-Ref. Bei read_content=true: Liest vollen Text aus DOCX, PDF und Excel.
qms_batch_plan kapitel (opt.), status (opt.) Erstellt Plan fuer Batch-Dokumentenerstellung. Zeigt welche Dokumente fehlen, schlaegt Typ vor.

QMS Aktionen

ToolParameterBeschreibung
qms_create_folder path Erstellt Ordner in QMS_RegioFrucht/.
qms_move_file source, destination Kopiert Datei innerhalb QMS (Original bleibt erhalten).
qms_create_document typ, kapitel, nummer, titel, version, zielordner, inhalt Erstellt DOCX aus Firmenvorlage. Ersetzt Header/Footer-Platzhalter, fuegt Inhalt ein (Markdown mit Tabellen). Dokumenttypen: VA, AA, FB, PB, CL, QMH.
qms_link_chat refs (Array), summary Verknuepft Chat mit IFS-Anforderungen (wird auch automatisch im Hintergrund aufgerufen).

Wiederkehrende Aufgaben

ToolParameterBeschreibung
qms_recurring_create title, interval, responsible, ifs_ref, description, force Erstellt wiederkehrende Aufgabe mit Duplikat-Erkennung. Prueft automatisch ob eine aehnliche Aufgabe existiert (gleiche IFS-Ref oder aehnlicher Titel). Bei Treffer: Warnung statt Erstellung. Mit force=true trotzdem erstellen.
qms_recurring_complete id, by, notes Markiert Aufgabe als erledigt, berechnet naechsten Faelligkeitstermin.
qms_recurring_list Zeigt alle Aufgaben sortiert (ueberfaellig zuerst).

Pipeline

ToolParameterBeschreibung
pipeline_status Zeigt Pipeline-Statistiken: heute verarbeitet, Gesamtzahl, Fehler, offene Dokumente, offene Abgleiche.
pipeline_search lieferant, kunde, kategorie, status, von, bis, limit Sucht Dokumente in der Pipeline-Datenbank nach verschiedenen Kriterien.
pipeline_match_invoice Zeigt offene Rechnungen ohne Lieferschein-Zuordnung und bisherige Abgleich-Ergebnisse.

Gap-Analyse

Die Gap-Analyse vergleicht 127 IFS Food 8 Grundstufe-Anforderungen (davon 11 KO-Anforderungen) mit den vorhandenen Dokumenten.

Datenquellen

DateiInhalt
all_grundstufe.json (101 KB)127 Anforderungen mit ref, Anforderungstext, Leitfaden, Stufe, KO-Status
all_requirements.json (176 KB)Alle 266 IFS-Anforderungen (Grund + Mittelstufe)
refined_mapping.json (343 KB)621 Dokumente mit IFS-Zuordnung, Kategorie, Pfad, Vorschau

Berechnung

Fuer jede Grundstufe-Anforderung wird gezaehlt, wie viele Dokumente aus dem Mapping zugeordnet sind. >=2 = Gruen, 1 = Gelb, 0 = Rot.

Dokumente erstellen

RUDI erstellt QMS-Dokumente in einem mehrstufigen Dialog:

  1. Vorhandene pruefen: Schon Dokumente fuer diese Anforderung vorhanden?
  2. Infos klaeren: Fehlende Informationen beim Benutzer abfragen (keine Platzhalter!)
  3. Entwurf zeigen: Vollstaendiger Entwurf im Chat
  4. Bestaetigung abwarten: Benutzer gibt OK
  5. Dokument erstellen: DOCX aus Vorlage generieren

Dokumenten-Kodierung

[Typ]-[Kapitel].[Nummer]_[Titel]_v[Version].docx

Beispiel: VA-4.10.001_Reinigungsplan_v1.0.docx
TypBedeutung
VAVerfahrensanweisung
AAArbeitsanweisung
FBFormblatt
PBPruefbericht
CLCheckliste
QMHQM-Handbuch

Vorlage

Alle Dokumente basieren auf QMS-Vorlage-Regio-Frucht.docx:

Word-Tabellen

Markdown-Tabellen im Inhalt werden als formatierte Word-Tabellen gerendert:

Batch-Erstellung

RUDI kann fuer alle gruenen/gelben Anforderungen automatisch Dokumente erstellen:

  1. Batch-Plan anfordern: "Erstelle alle gruenen Dokumente" oder "Batch-Plan fuer Kapitel 4"
  2. Plan bestauetigen: RUDI zeigt welche Dokumente erstellt werden
  3. Automatische Abarbeitung: Pro Anforderung: Quelldokumente lesen → echte Daten extrahieren → Dokument erstellen
  4. Fortschritt: "3/50 erstellt..."

Wichtig: RUDI verwendet nur echte Daten aus den Quelldokumenten – keine erfundenen Inhalte.

Wiederkehrende Aufgaben

Pruefungen, Checklisten und Formular-Durchgaenge koennen als wiederkehrende Aufgaben angelegt werden:

Kundenreklamationen

Das Reklamationsmodul ermoeglicht die strukturierte Erfassung, Bearbeitung und Dokumentation von Kundenreklamationen gemaess IFS 5.7.2–5.7.4.

Reklamation anlegen

Erreichbar ueber QMS Dashboard → Reklamationen → Neue Reklamation oder direkt unter /qms/reklamation.html.

Formularfelder

FeldPflichtBeschreibung
KundeJaName des reklamierenden Kunden
DatumJaReklamationsdatum (Standard: heute)
ProduktNeinBetroffenes Produkt / Artikel
Charge / Los-Nr.NeinChargen- oder Losnummer zur Rueckverfolgung
ReklamationsgrundJaKategorie: Qualitaetsmangel, Fremdkoerper, Mindesthaltbarkeit, Falschlieferung, Transportschaden, Sonstiges
BeschreibungNeinDetaillierte Problembeschreibung
SofortmassnahmeNeinBereits eingeleitete Sofortmassnahmen
StatusJaOffen, In Bearbeitung, Abgeschlossen
DateienNeinFotos, Lieferscheine, Pruefberichte etc.

Entwurf & Speicherung

RUDI Chat-Integration

Ueber den Button “Mit RUDI bearbeiten” (unten rechts) oeffnet sich das Chat-Panel mit vollem Reklamationskontext. Quick-Actions:

RUDI nutzt die vorhandenen Reklamationsdaten automatisch und erstellt Dokumente mit der Regio Frucht QMS-Vorlage (Kopf-/Fusszeile, Dok-ID, Version).

Bilder-Vorschau

Hochgeladene Bilder (JPG, PNG, WebP) werden als Thumbnail-Galerie angezeigt. Ein Klick oeffnet die Lightbox mit Vollbild-Ansicht, Pfeil-Navigation (auch per Tastatur), und optionalem Download-Button.

Dateispeicherung

Dateien aus E-Mail-Analysen werden zunaechst in einem Staging-Bereich zwischengespeichert. Beim Speichern der Reklamation werden sie automatisch in den permanenten Ordner (~/uploads/reklamationen/{rek_id}/) verschoben und mit der Reklamation verknuepft.

Bildanalyse (Claude Vision)

RUDI kann Bilder aus Reklamationen visuell analysieren (Tool: reklamation_bild_analysieren). Dabei werden Qualitaetsmaengel wie Druckstellen, Schimmel, Verfaerbungen, Fremdkoerper oder Verpackungsschaeden erkannt.

Reklamationssuche (ChromaDB)

Historische Reklamationen werden in der Vektordatenbank indexiert. Das Tool reklamationen_suche findet aehnliche Faelle, z.B. “Druckstellen bei Erdbeeren” oder “Temperaturproblem Lieferung”. Hilfreich um Muster zu erkennen.

IFS-Referenz

IFS 5.7.2–5.7.4: Reklamationen muessen aufgezeichnet, ausgewertet und den zustaendigen Verantwortlichen mitgeteilt werden. Korrekturmassnahmen sind zu dokumentieren.

Vektordatenbank & Semantische Suche

RUDI nutzt eine Vektordatenbank (ChromaDB) kombiniert mit Google Gemini Embedding 2, um Dokumente, Bilder und Reklamationen inhaltlich durchsuchbar zu machen – nicht nur nach Stichworten, sondern nach Bedeutung.

Wie funktioniert das?

Jedes Dokument, Bild oder jeder Text wird in einen Zahlenvektor (768 Zahlen) umgewandelt. Aehnliche Inhalte erzeugen aehnliche Vektoren. So findet die Suche nach “kaputter Riemen” auch ein Foto eines gerissenen Riemens – selbst wenn das Foto nicht beschriftet ist.

Suchprozess am Beispiel

Szenario: Du suchst Bilder von einem kaputten Riemen an der GS 10.

Schritt 1: Du fragst RUDI

Du: "Zeig mir Bilder von kaputten Riemen"

Schritt 2: Text wird zum Vektor

Gemini Embedding API wandelt deinen Text in 768 Zahlen um:

"kaputter Riemen" → [0.21, -0.39, 0.11, 0.85, ...]

Schritt 3: ChromaDB vergleicht

Dein Vektor wird mit allen gespeicherten Medien-Vektoren verglichen:

Gespeichertes MediumScoreErgebnis
Foto: gerissener Riemen GS 100.87Treffer
Video: Riemenwechsel-Anleitung0.71Treffer
Foto: verschlissenes Messer0.31
Foto: saubere Maschine0.12

Schritt 4: RUDI antwortet

RUDI: "Ich habe 2 passende Medien gefunden:
  - Bild: gerissener_riemen.jpg (GS 10, Kategorie: Fehler)
  - Video: riemenwechsel.mp4 (GS 10, Kategorie: Wartung)"

Warum findet die Suche auch Bilder OHNE Beschreibung?

Gemini Embedding 2 ist multimodal – es versteht Text UND Bilder gleichzeitig. Wenn du ein Foto hochlaedst, erzeugt Gemini einen Vektor der den visuellen Inhalt repraesentiert. Dieser Vektor liegt im selben Raum wie Text-Vektoren:

Bild hochladen                    Text-Suche
     |                                |
     v                                v
Gemini "sieht" das Bild       Gemini "versteht" den Text
     |                                |
     v                                v
Vektor: [0.22, -0.40, ...]    Vektor: [0.21, -0.39, ...]
     |                                |
     +----------- aehnlich! ----------+
                    |
                    v
              TREFFER!

Was passiert beim Bild-Upload?

1. Bild wird hochgeladen
      |
      v
2. Datei gespeichert in ~/maschinen/medien/{id}/{YYYY-MM}/
      |
      v
3. Gemini Vision analysiert das Bild automatisch
   → "Foto zeigt ausgefransten Antriebsriemen mit Verschleissspuren"
      |
      v
4. Beschreibung wird in Datenbank gespeichert
      |
      v
5. Zwei Embeddings werden erzeugt:
   a) Bild-Vektor (multimodal, vom Foto selbst)
   b) Text-Vektor (von der Auto-Beschreibung)
      |
      v
6. RUDI weiss jetzt was auf dem Bild ist
   und kann es per Textsuche finden

OCR-Fallback (seit 27.03.2026)

Gescannte PDFs (Bilder statt Text) werden automatisch per Tesseract OCR gelesen. Der Fallback greift systemweit — egal in welchem Modul oder Chat ein PDF hochgeladen wird.

WoVorherNachher
Maschinen-Anleitungen (vectordb.py)Gescannte Seiten uebersprungenOCR-Fallback pro Seite, Text in ChromaDB
Anleitungs-Analyse (analyse_anleitung.py)Kein Text → FehlerOCR-Fallback, Wartungsplaene auch aus Scans
Chat read_file (tools.js)"Kein extrahierbarer Text"OCR via ocr.py CLI, Text angezeigt

Ablauf: pdfplumber versucht Text zu extrahieren (schnell). Nur wenn kein/wenig Text gefunden wird (<50 Zeichen/Seite), startet Tesseract OCR als Fallback (2-5 Sek/Seite, max 20 Seiten).

Force-Reprocessing: Bereits verarbeitete Anleitungen koennen mit force=true erneut verarbeitet werden (z.B. nach OCR-Update oder wenn ein Scan beim ersten Mal nicht erkannt wurde).

ChromaDB Collections

CollectionInhaltEmbedding-Typ
pipeline_dokumenteLieferscheine, Rechnungen (OCR-Text)Text
maschinen_anleitungenBedienungsanleitungen (seitenweise, mit OCR-Fallback)Text + Visuell
maschinen_medienMaschinenfotos und -videosBild + Text
qms_reklamationenKundenreklamationenText
wareneingang_bilderWareneingangsdoku (vorbereitet)

Kosten

AktionKosten pro StueckBei 30/Tag
Text embedden~$0.00003~$0.03/Monat
Bild embedden~$0.00005~$0.05/Monat
Bild beschreiben (Vision)~$0.001~$0.90/Monat
Suche (pro Anfrage)~$0.00003vernachlaessigbar

Gesamt bei intensiver Nutzung: unter $1/Monat.

Maschinenmanagement

Das Maschinenmodul verwaltet Produktionsmaschinen (Schneiden, Waschen, Verpacken, Kuehlung) mit Stammdaten, Bedienungsanleitungen, Wartungsplaenen und Medien. Erreichbar unter /maschinen/.

Funktionen

Maschinen-Wissen

RUDI speichert maschinenspezifisches Wissen dauerhaft – Tipps, Warnungen und Erfahrungswerte die nicht in der Bedienungsanleitung stehen.

Du im Chat: "Merk dir: Beim Riemenwechsel an der GS 10
             muss die Spannung auf 3,5 Nm gestellt werden"
     |
     v
RUDI speichert als Hinweis:
  Typ:    Tipp
  Inhalt: "Beim Riemenwechsel Spannung auf 3,5 Nm einstellen"
     |
     v
Bei jeder zukuenftigen Frage zur GS 10:
  RUDI laedt automatisch alle aktiven Hinweise
  und beruecksichtigt sie in der Antwort.

Hinweise-Typen: Tipp (Praxistipp), Warnung (Sicherheit), Fehler (bekannte Probleme), Prozess (Arbeitsablaeufe). Max. 20 aktive Hinweise pro Maschine werden in den Chat-Kontext geladen.

Medien & Dokumentation

Jede Maschine kann mit Bildern, Videos und Dokumenten angereichert werden:

Medien sind ueber die semantische Suche auffindbar: "Zeig mir Bilder von kaputten Riemen" → RUDI durchsucht ChromaDB und findet passende Fotos (siehe Semantische Suche).

Fuhrparkmodul

Das Fuhrparkmodul verwaltet alle 11 Firmenfahrzeuge mit Stammdaten, TUeV-Terminen, Wartungsplaenen, KM-Eintraegen, Dokumenten und Fahrerkarten. Datenbasis: SQLite unter ~/fuhrpark/fuhrpark.db.

Fahrzeugtypen

TUeV-Verwaltung

TUeV-Faelligkeiten werden im Format MM/YYYY gespeichert. Die API liefert Fahrzeuge nach TUeV-Dringlichkeit sortiert. Bremswerte aus der HU werden als JSON in der TUeV-Historie gespeichert.

Wartungsplanung

Wartungsplaene haben zeit- und/oder KM-basierte Intervalle. Bei Protokolleintrag wird naechste_faellig automatisch berechnet und km_stand im Fahrzeug aktualisiert.

Dateipfade

API-Endpunkte

Alle Endpunkte sind unter /chat/api/ erreichbar (via Nginx Proxy). Basis: https://rudi-regiofrucht.de

Chat

MethodeRouteBeschreibung
POST/chat/api/chatHaupt-Chat (SSE Streaming). Body: {message, chatId}
GET/chat/api/chatsAlle Chats auflisten. Optional: ?filter=qms|recurring|chat
GET/chat/api/chats/:idEinzelnen Chat laden
PATCH/chat/api/chats/:idChat umbenennen
DELETE/chat/api/chats/:idChat in Papierkorb verschieben (soft delete). ?permanent=true fuer endgueltiges Loeschen
GET/chat/api/chats/trash/listPapierkorb auflisten
POST/chat/api/chats/trash/restore/:idChat aus Papierkorb wiederherstellen
DELETE/chat/api/chats/trash/emptyPapierkorb komplett leeren

Dateien

MethodeRouteBeschreibung
POST/chat/api/uploadDatei-Upload (Multer, max 50 MB)
POST/chat/api/transcribeAudio-Transkription (Whisper)
GET/chat/api/view?path=...&download=1Datei anzeigen/herunterladen

QMS

MethodeRouteBeschreibung
GET/chat/api/qms/dashboardDashboard-Daten (Stats, Kapitel, Ordner, Annotations)
GET/chat/api/qms/annotationsAlle Annotations
PUT/chat/api/qms/annotations/:refAnnotations fuer Ref aktualisieren
POST/chat/api/qms/annotations/:ref/taskNeue Aufgabe erstellen
PATCH/chat/api/qms/annotations/:ref/task/:idAufgabe aktualisieren
DELETE/chat/api/qms/annotations/:ref/task/:idAufgabe loeschen
GET/chat/api/qms/recurringWiederkehrende Aufgaben
POST/chat/api/qms/recurringNeue Recurring-Aufgabe
POST/chat/api/qms/recurring/:id/completeAufgabe erledigen
PATCH/chat/api/qms/recurring/:idAufgabe bearbeiten
DELETE/chat/api/qms/recurring/:idAufgabe loeschen
POST/chat/api/qms/uploadQMS-Datei-Upload (max 200 Dateien, Ordner-Upload)
GET/chat/api/qms/foldersQMS-Ordnerliste (fuer Upload-Zielwahl)

Reklamationen

MethodeRouteBeschreibung
GET/chat/api/qms/reklamationenAlle Reklamationen auflisten
POST/chat/api/qms/reklamationenNeue Reklamation anlegen. Body: {kunde, datum, produkt, charge, reklamationsgrund, beschreibung, sofortmassnahme, status}
PUT/chat/api/qms/reklamationen/:idReklamation aktualisieren
DELETE/chat/api/qms/reklamationen/:idReklamation loeschen
POST/chat/api/qms/reklamationen/:id/dateienDateien (Fotos, Dokumente) zu Reklamation hochladen
POST/chat/api/qms/parse-emailE-Mail (.eml/.msg) oder Bilder analysieren. Multipart-Upload. Gibt vorausgefuellte Felder + _meta.stagingId zurueck. Dateien werden in Staging gespeichert.
POST/chat/api/qms/reklamationen/:id/claim-stagingStaging-Dateien in Reklamation uebernehmen. Body: {stagingId}. Verschiebt Dateien von Staging nach uploads/reklamationen/{id}/

Pipeline

MethodeRouteBeschreibung
GET/chat/api/pipeline/statsDashboard-Statistiken (heute, gesamt, fehler, offen)
GET/chat/api/pipeline/dokumenteDokumentenliste. Filter: ?kategorie=&status=&lieferant=&von=&bis=
GET/chat/api/pipeline/dokumente/:idEinzeldokument mit extrahierten Daten
POST/chat/api/pipeline/dokumente/:id/statusStatus aendern. Body: {status: "geprueft"}
POST/chat/api/pipeline/dokumente/:id/zuordnenLS/RE manuell zuordnen. Body: {lieferschein_id}
GET/chat/api/pipeline/abgleichLS/RE-Abgleich-Ergebnisse
GET/chat/api/pipeline/alertsAktuelle Meldungen (Fehler, offene Rechnungen)
POST/chat/api/pipeline/uploadDokument hochladen (multipart, Feld: datei) → eingang/
POST/chat/api/pipeline/upload-personalPersonaldokument hochladen (nur Admin) → eingang_personal/
POST/chat/api/pipeline/reprocess/:idFehlgeschlagenes Dokument erneut verarbeiten

Personal-Routen (nur Admin)

MethodeRouteBeschreibung
GET/chat/api/pipeline/personal/mitarbeiterMitarbeiterliste (aktive)
GET/chat/api/pipeline/personal/mitarbeiter/:idPersonalakte mit allen Dokumenten
POST/chat/api/pipeline/personal/mitarbeiterNeuen Mitarbeiter anlegen
GET/chat/api/pipeline/personal/dokumenteAlle Personaldokumente (gefiltert)
GET/chat/api/pipeline/personal/erinnerungenAblaufende Dokumente (Belehrungen etc.)

Fuhrpark

MethodeRouteBeschreibung
GET/chat/api/fuhrparkAlle Fahrzeuge (aktive). Filter: ?typ=kuehl_lkw|pkw|e_auto|lkw. Sortiert nach TUeV-Dringlichkeit.
GET/chat/api/fuhrpark/statsUebersicht: {gesamt, tuev_dringend, wartung_faellig}
GET/chat/api/fuhrpark/tuev-faelligFahrzeuge mit TUeV in naechsten N Wochen. Filter: ?wochen=6
GET/chat/api/fuhrpark/:idEinzelfahrzeug mit wartungsplaene, letzte_protokolle, letzte_km_eintraege, dokumente, tuev_historie, fahrerkarten
POST/chat/api/fuhrparkFahrzeug anlegen. Pflicht: kennzeichen, fahrzeug
PUT/chat/api/fuhrpark/:idFahrzeug aktualisieren
DELETE/chat/api/fuhrpark/:idFahrzeug deaktivieren (Soft-Delete, aktiv=0)
POST/chat/api/fuhrpark/:id/tuevTUeV-Eintrag hinzufuegen. Body: {datum, pruefstelle, pruefer, ergebnis, bremswerte, tuev_faellig_neu}
GET/chat/api/fuhrpark/:id/tuevTUeV-Historie des Fahrzeugs
GET/chat/api/fuhrpark/:id/wartungWartungsplaene des Fahrzeugs
POST/chat/api/fuhrpark/:id/wartungWartungsplan anlegen. Body: {bezeichnung, kategorie, intervall_tage, intervall_km, ...}
PUT/chat/api/fuhrpark/:id/wartung/:planIdWartungsplan bearbeiten
DELETE/chat/api/fuhrpark/:id/wartung/:planIdWartungsplan loeschen (inkl. Protokolle)
POST/chat/api/fuhrpark/:id/protokollWartung protokollieren. Body: {wartungsplan_id, durchgefuehrt_am, km_stand, werkstatt, kosten, ergebnis}
POST/chat/api/fuhrpark/:id/kmKM-Stand eintragen. Body: {km_stand, datum, quelle}. Plausibilitaetspruefung.
GET/chat/api/fuhrpark/:id/kmKM-Verlauf. Filter: ?limit=50
POST/chat/api/fuhrpark/:id/dokumentDokument hochladen (PDF, JPG, PNG; 50 MB). Felder: datei, typ, beschreibung
DELETE/chat/api/fuhrpark/:id/dokument/:docIdDokument loeschen (DB + Datei)
GET/chat/api/fuhrpark/:id/dokument/:docId/viewDokument anzeigen/herunterladen
POST/chat/api/fuhrpark/:id/fahrerkarteFahrerkarte hochladen (.ddd, 10 MB). Felder: datei, fahrer_name, kartennummer
GET/chat/api/fuhrpark/:id/fahrerkarteFahrerkarten des Fahrzeugs
POST/chat/api/fuhrpark/sync-gpsGPS-Sync (501 Not Implemented – fuer kuenftige FindCar-Integration)

Tacho-Auswertung

Digitale Tachograph-Auswertung (.ddd-Dateien). Frontend: /fuhrpark/tacho.html. Parser-Binary: ~/fuhrpark/bin/dddparser. Gespeichert unter ~/fuhrpark/dokumente/tacho/. Verstoesspruefung nach EU VO 561/2006.

MethodeRouteBeschreibung
POST/chat/api/fuhrpark/tacho/parseDDD-Datei hochladen (max 200 MB). Felder: datei, fahrzeug_id (opt). Auto-Detect Fahrerkarte/VU. Response: {auswertung_id, type, fahrer_name, verstoesse_count, zusammenfassung, tagesauswertung}
GET/chat/api/fuhrpark/tacho/auswertungenAlle Tacho-Auswertungen. Filter: ?fahrzeug_id=&fahrer_name=&limit=
GET/chat/api/fuhrpark/tacho/statsTacho-Statistik: {auswertungen_gesamt, verstoesse_gesamt, verstoesse_nach_schwere}
GET/chat/api/fuhrpark/tacho/verstoesseVerstoesse-Liste. Filter: ?fahrer_name=&schwere=leicht|schwer|sehr_schwer&typ=&von=&bis=
GET/chat/api/fuhrpark/tacho/fahrer/:nameAlle Auswertungen + Verstoesse fuer einen Fahrer
GET/chat/api/fuhrpark/tacho/auswertung/:idEinzelne Auswertung mit parsed_data + Verstoessen
DELETE/chat/api/fuhrpark/tacho/auswertung/:idAuswertung loeschen (DB-Eintraege + Datei)

Team-Chat

Interner Messenger unter /team/ — Direktnachrichten + Gruppen, Medienversand, Sprachnachrichten, automatische Uebersetzung (DE/RO) und WebSocket-Echtzeit.

Seiten

SeitePfadFunktion
Konversationsliste/team/Alle Chats, Suche, Ungelesen-Badges, neuer Chat per FAB
Nachrichtenansicht/team/chat.html?id=CONV_IDVollbild-Chat, Medien, Sprachnachricht, Antworten, Kontextmenu
Profil/team/profil.htmlAvatar, Status-Text, Sprache (DE/RO)

Features

API-Basis

/chat/api/team-chat/ (Nginx Proxy → :3456/)

Kommunikation (E-Mail & Kalender)

Das Kommunikationsmodul unter /kommunikation/ integriert E-Mail und Kalender ueber die Microsoft Graph API mit zwei Shared Mailboxen.

Mailboxen

MailboxAdresseZweckSenden
RUDIrudi@regiofrucht.deAllgemeine KommunikationJa (direkt)
QMSqms@regiofrucht.deReklamationen, Audits, LieferantenNur Entwuerfe (User sendet in Outlook)

Authentifizierung

Azure App Registration mit Client Credentials Flow (app-only, kein User-Login). Berechtigungen: Mail.Read, Mail.ReadWrite, Mail.Send, Calendars.Read, Calendars.ReadWrite, User.Read.All. Die Berechtigungen gelten tenant-weit fuer beide Mailboxen. Credentials in /etc/environment: AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, RUDI_MAILBOX, QMS_MAILBOX.

E-Mail-Tab (rudi@)

Layout: Outlook-Style 3-Spalten (Ordner-Sidebar | E-Mail-Liste | Lesebereich). Ordner: Posteingang, Gesendet, Entwuerfe, Papierkorb, Junk, Archiv. Features: Datum-Gruppierung (Heute/Gestern/Woche/Aelter), CID-Inline-Bilder, Signatur (global + individuell), Antworten/Weiterleiten, Sync-Button, Ungelesen-Filter.

Signatur: Gespeichert in auth.db (Tabelle email_signatures). Global (Admin) + individuell (pro User). Wird serverseitig an ausgehende E-Mails angehaengt. API: GET/PUT /chat/api/email/signatur, GET/PUT /chat/api/email/signatur/global.

E-Mail-Sync: Polling alle 5 Minuten via Graph API Delta Query. Neue/geaenderte E-Mails werden in die lokale SQLite-DB gespeichert (AES-256-GCM verschluesselt). Geloeschte oder verschobene E-Mails werden ueber @removed-Marker aus der Delta-Response erkannt und automatisch aus dem lokalen Cache entfernt. Bei verwaisten Eintraegen (z.B. vor dem Fix geloescht) werden beim manuellen Sync (POST /chat/api/email/sync) alle DB-Eintraege gegen den Live-Inbox abgeglichen und nicht mehr vorhandene Mails bereinigt.

Kalender-Tab

Wochenansicht mit Zeitraster (6:00–21:00 Uhr, 48px/Stunde). Mitarbeiter-Kalender: Checkbox-Liste in der Sidebar, farbcodiert (blau/gruen/orange/lila/rot). Mehrere Kalender gleichzeitig als Overlay. Termine: Erstellen per Klick auf Zeitslot oder Button, Bearbeiten/Loeschen per Klick auf Event. Zeitzonen: Europe/Berlin.

QMS-E-Mail (qms@)

Sicherheitskonzept: RUDI darf ueber qms@ KEINE E-Mails direkt senden. Sende-Blockierung auf Graph-API-Ebene (assertSendAllowed). Nur Entwuerfe (Drafts) koennen erstellt werden. User sendet in Outlook.

Dashboard-Integration: Im QMS-Dashboard (/qms/) zeigt eine kompakte Sektion die letzten QMS-E-Mails + Ungelesen-Badge + Links zu Outlook Inbox und Entwuerfe.

API-Endpoints (unter /chat/api/qms/email/, geschuetzt mit requireModule('qms')):

MethodeEndpointBeschreibung
GET/chat/api/qms/email/inboxQMS-Posteingang (lokale DB)
GET/chat/api/qms/email/inbox/:idEinzelne QMS-E-Mail (mit CID-Bilder-Auflosung)
GET/chat/api/qms/email/statsUngelesen-Count, letzte E-Mail
GET/chat/api/qms/email/draftsOffene Entwuerfe in qms@
POST/chat/api/qms/email/draftEntwurf erstellen (an, betreff, text)
POST/chat/api/qms/email/draft/:id/sendEntwurf absenden (User-Aktion)
POST/chat/api/qms/reklamationen/:id/email-entwurfReklamations-Antwort als Entwurf
POST/chat/api/qms/email/syncManueller QMS-Mail-Sync

RUDI-Chat-Tools

ToolMailboxBeschreibung
email_inboxrudi@E-Mails anzeigen/filtern
email_sendenrudi@E-Mail senden (mit Bestaetigung)
email_anhang_lesenrudi/br/info@Anhaenge lesen: detail="summary" (Haiku-Kurzfassung, gecached) oder detail="volltext" (Rohtext aller Seiten, Sonnet Vision bei Scan-PDFs/Bildern). PFLICHT bei konkreten Zahlen/Mengen/Preisen/Artikelnummern.
qms_email_inboxqms@QMS-Posteingang lesen
qms_email_entwurfqms@Entwurf erstellen (kein Senden!)
kalender_terminerudi@Termine anzeigen (eigen + Mitarbeiter)
kalender_termin_erstellenrudi@Termin anlegen mit Teilnehmern

Technische Details


Einkauf-Dashboard

Das Einkauf-Dashboard unter /einkauf/ ist das Eingangsmodul fuer Wareneingang, Chargen und Lieferantenmanagement. Es folgt dem Standard-Design-System mit Apple Glasmorphism, Dark/Light Mode und eingebettetem RUDI Chat-Panel.

Wareneingang

Vollstaendige Seite unter /einkauf/wareneingang.html. Erfassung und Pruefung von Wareneingaengen mit Lieferant, Charge, Typ (Bio/Standard/Packaging) und Status-Workflow (neu → geprueft → eingelagert / abgelehnt). Includes Accordion-Liste, Erfassungs-Modal mit Drag&Drop-Bild-Upload, client-seitiger Bild-Komprimierung (max 2560×1440, 85% JPEG), Duplikat-Check fuer Chargen, LocalStorage-Autosave und Excel-Export.

Phase-3-Erweiterungen (2026-04-27): Country-of-Origin-Pflichtfeld (Feature-Flag we_country_pflicht) mit Dropdown (30 Laender), Auto-Vorbefuellung via GET /vorbereiten nach Lieferant-Auswahl · Quelle-Badge zeigt ob Country aus Avis, Lieferanten-Default oder manuell · Vorgang-Info-Box: zeigt offene Vorgaenge, Dropdown bei mehreren, "Neuer Vorgang" wenn keiner · Avis-Positionen-Box (collapsible): "Alle uebernehmen" matcht Rohwaren automatisch · Vision-Live-Warnung: nach Bild-Upload Polling alle 5s, gelbe/rote Box bei Maengeln (Feature-Flag we_vision_warnung) · Quality-Filter Dropdown (Alle/OK/Mangel/Gesperrt) · Quality-Badge als neue Spalte in der Liste · capture="environment" fuer direkten Smartphone-Kamera-Aufruf.

Features: Filter nach Typ/Status/Quality/Datum/Suche · Thumbnails mit Lightbox · RUDI Chat-Panel (Modul: einkauf) · Detail-Link zu /einkauf/detail.html?id=X

Wareneingang Detail

Detailseite /einkauf/detail.html?id=X mit 2-Spalten-Layout (Main + 340px Sidebar). Laedt Daten von GET /chat/api/einkauf/wareneingang/{id}.

Main-Bereich: Stammdaten-Card (Lieferant, Datum, Typ, Status) · Daten-Card (Charge, Rohwaren als Chips, Notizen) · Bilder-Galerie mit Tabs (Lieferscheine / Waren), Thumbnail-Grid, Lightbox · Direkter Bild-Upload je Tab · KI-Bildanalyse-Card (MIB-Audit Korrektur 4, 2026-04-28): Pro Bild Thumbnail + vision_beschreibung aus wareneingang_bilder + Vision-Status-Badge (done/pending/error). Bei pending: Spinner "Analyse laeuft...". Bei error: graue Box + "Erneut versuchen"-Button (POST /quality-check). Zusammenfassungs-Zeile (X analysiert, Y ausstehend, Z Fehler). Button "Neu analysieren" fuer alle Bilder. Kein Backend-Change noetig: SELECT * liefert bereits vision_status + vision_beschreibung. · OCR-Text-Section (collapsible).

Sidebar (Phase 3): Lieferanten-Info · Chargen-Info · Herkunftsland-Card · Quality-Pruefung-Card: Status-Badge, Maengel-Liste, Button "Neu analysieren" (POST /quality-check), nur sichtbar wenn Feature-Flag we_vision_warnung ON · Vorgang-Card: Vorgang-ID als Link, Belege-Typen-Uebersicht · Soll-Ist-Vergleich-Card (Phase 4 Vorbereitung): bei vorhandener Vorgang-ID ladbar via GET /vorbereiten · Zeitstempel · Sync-Badge.

Edit-Modal (Phase 3 ergaenzt): Herkunftsland-Dropdown (30 Laender) · Herkunftsland wird bei PUT /wareneingang/{id} als herkunftsland_iso mitgesendet.

API-Calls der Detailseite: GET /wareneingang/{id}, PUT /wareneingang/{id} (Edit + Status + herkunftsland_iso), DELETE /wareneingang/{id}, POST /wareneingang/{id}/bilder, DELETE /wareneingang/{id}/bilder/{bildId}, POST /wareneingang/{id}/quality-check (Phase 3)

API-Pfade (alle ueber /chat/api/einkauf/):

MethodeRouteBeschreibung
GET/chat/api/einkauf/statistikStatistik: heute, offen, woche (Felder als Zahlen)
GET/chat/api/einkauf/wareneingangListe. Query: q, von, bis, typ, status, charge. Antwort: { items, stats }
GET/chat/api/einkauf/wareneingang/vorbereitenPhase 3 NEU: Vorbefuellung fuer Wareneingang-Erfassung. Query: lieferant_id (Pflicht), datum (opt.). Antwort: { lieferant, vorschlag_charge, vorschlag_typ, vorschlag_country, country_quelle, offene_vorgaenge[], avis_positionen[], letzte_lieferungen[], lieferant_default_country, warnungen[] }. requireAuth + requireModule('einkauf').
POST/chat/api/einkauf/wareneingangNeuer Eintrag. Body: lieferant_id, datum, typ, chargennummer, notizen, rohwareIds[], herkunftsland_iso (Pflicht wenn Feature-Flag we_country_pflicht aktiv), vorgang_id (opt., auto-verlinkt). Antwort: { id, status, vorgang_id, vorgang_auto_angelegt }. Bei mehreren Vorgang-Kandidaten: 422 mit Kandidaten-Liste.
PATCH/chat/api/einkauf/wareneingang/:idTeilupdate (z.B. Status aendern)
DELETE/chat/api/einkauf/wareneingang/:idLoeschen
POST/chat/api/einkauf/wareneingang/:id/bilderBild hochladen (multipart). Felder: dateien[], typ (lieferschein|ware). Triggert Vision-Embedding + auto Quality-Check wenn alle Bilder done.
POST/chat/api/einkauf/wareneingang/:id/quality-checkPhase 3 NEU: Vision-Live-Qualitaetsanalyse. Body: { prompt_zusatz?: string }. Antwort: { status, quality_status, bio_sperre, bio_sperre_grund, ergebnis: { maengel[], gesamteindruck } }. Speichert in auto_validierung_json + cockpit_auffaelligkeiten. Bei typ='bio' + Mangel und Feature-Flag bio_quality_gate ON: setzt quality_status='gesperrt', Cockpit-Eintrag 'bio_konflikt', Audit-Log 'bio_sperre'. Feature-Flag we_vision_warnung muss ON sein (sonst 403). requireAuth + requireWrite + requireCsrf + requireModule('einkauf').
POST/chat/api/einkauf/wareneingang/:id/bio-freigabeMIB-Audit Korrektur 2 NEU: BIO-Sperre aufheben. Body: { grund: string (min 10 Zeichen) }. Nur bei quality_status='gesperrt' ausfuehrbar (sonst 422). Setzt quality_status='ok', schreibt sperre_freigabe_durch/grund/am in auto_validierung_json, Audit-Log 'bio_freigabe'. Auth: requireAuth + requireWrite + requireCsrf + (role='admin' ODER module='qms') — einkauf-Rolle allein darf NICHT freigeben (IFS-Pflicht). PUT /wareneingang/:id liefert 423 wenn quality_status='gesperrt' und Status-Aenderung versucht wird.
GET/chat/api/einkauf/wareneingang/exportExcel-Export mit denselben Filtern wie Liste
GET/chat/api/einkauf/lieferantenLieferantenliste (Top-5 haeufigste zuerst)
GET/chat/api/einkauf/rohwarenRohwaren-Liste. Query: gruppiert=true liefert Objekt nach Kategorie
GET/chat/api/einkauf/charge/vorschlagAuto-Vorschlag. Query: typ, datum

Vorgangsmodell – Phase 4: Auto-Reklamation Solvega (Schatten-Modus)

Automatische Soll/Ist-Diff-Detektion mit Claude Vision fuer Lieferanten-Handschrifterkennung auf Albarane. 4-Wochen-Schatten-Modus: Vorschlaege landen in DB, kein Mail-Versand. Mensch gibt frei.

Solvega-Spezifik: Vereinbarung Regio Frucht ↔ Solvega: Regio Frucht wiegt jede Lieferung, teilt Ist-Mengen mit, Solvega korrigiert die Rechnung entsprechend. Mengen werden handschriftlich auf das Albaran notiert. Vision liest Soll (gedruckt) + Ist (Handschrift) automatisch.

Neue Dateien:

Feature-Flags: auto_reklamation_solvega (ON = Schatten-Modus) · auto_reklamation_versand (OFF = kein Auto-Versand)

Cron-Datei: /etc/cron.d/auto-reklamation (30 Min Diff-Trigger + 60 Min Rechnung-Check)

Log-Dateien: ~/backups/auto-reklamation.log, ~/backups/rechnung-korrektur.log

Env-Konfiguration: AUTO_REKL_LIEFERANTEN (Komma-Liste), AUTO_REKL_DIFF_PCT (default 2.0), AUTO_REKL_KRITISCH_PCT (default 10.0), VISION_HANDSCHRIFT_MAX (default 100/Tag)

DB-Felder: reklamationen.auto_erstellt=1, .freigabe_status='vorgeschlagen', .ki_vorschlag_json (vision_konfidenz, vorschlag_text, gutschrift_berechnung). cockpit_auffaelligkeiten.typ='gewichtsdiff', .schweregrad='warn'|'kritisch'.

Score-Gate: 4 Wochen Schatten-Modus, mind. 40 Vorschlaege, davon ≥90% akzeptiert → dann Auto-Versand aktivierbar via auto_reklamation_versand=ON

Vorgangsmodell – Phase 4: Lieferanten-Risiko-Score (woechentlich)

Woechentliche automatische Risiko-Bewertung aller aktiven Lieferanten mit Wareneingaengen in den letzten 90 Tagen. Score-Berechnung aus drei Komponenten: Reklamationsquote (50%), Mengen-Abweichungsquote (30%), Vision-Maengel-Quote (20%). Trend-Berechnung (besser/stabil/schlechter) aus Vergleich aktueller 90 Tage vs. vorangehende 90 Tage.

Score-Logik: base_score = (rek_pct * 0.5) + (diff_pct * 0.3) + (vision_pct * 0.2). Kategorie: ≥30 = rot, ≥10 = gelb, sonst gruen.

Neue Dateien:

DB-Schema-Erweiterung (einkauf.db Tabelle lieferanten):

Cron-Datei: /etc/cron.d/lieferanten-risiko-score (Mo 04:00 UTC)

Log-Datei: ~/backups/lieferanten-risiko-score.log

Audit-Log: modul=lieferanten-risiko, aktion=woechentlich, after_json={count_rot, count_gelb, count_gruen, top_3_rot, ergebnisse[{id, name, score, kategorie, trend}]}

Briefing-Integration: ~/rudi-chat/lib/briefing.jsbuild() gibt jetzt einkauf.risiko_lieferanten (rot, max 5), einkauf.top_auffaelligkeiten (offen, max 3), einkauf.offene_rek_vorschlaege (Anzahl auto_erstellt+vorgeschlagen) zurueck. formatRisikoText(einkauf) erzeugt lesbaren Warntext fuer Voice/Chat.

REST-Endpoints:

MethodeRouteBeschreibung
GET/chat/api/einkauf/lieferanten/risiko-scoreAlle Lieferanten mit Risiko-Score. Query: kategorie=rot|gelb|gruen (opt.). Sortierung: rot zuerst, dann Score desc. Antwort: [{lieferant_id, name, risiko_score, risiko_kategorie, risiko_komponenten, risiko_trend, risiko_aktualisiert_am, anzahl_wes_90, anzahl_reks_90}]. requireAuth + requireModule('einkauf').
GET/chat/api/einkauf/lieferanten/:id/risiko-historieLetzte 12 Wochen aus Audit-Log. Antwort: {lieferant_id, name, historie:[{datum, score, kategorie, trend, reks_90, wes_90}]}. requireAuth + requireModule('einkauf').

Aktuell (2026-04-27): Solvega Crops = rot (Score 46.9, Rek-Quote 93.8%) · Kraaijeveld BV = gelb (Score 17.8) · GP green produce = gelb (Score 13.6) · Schwehr Georg = kein Score (keine WE in 90 Tagen, implizit gruen)

Vorgangsmodell – Phase 4: Mensch-in-the-Loop UI (Reklamations-Vorschlaege)

Frontend fuer die Pruefung und Freigabe automatisch erzeugter Reklamations-Vorschlaege (Cron alle 30 Min, bin/soll-ist-diff-trigger.js). Seite: /einkauf/reklamationen/.

Features: 4 Tabs (Vorschlaege/Freigegeben/Abgelehnt/Manuell) · Statistik-Kacheln (offene Vorschlaege, ausstehende Gutschriften, rote Lieferanten, letzter Cron-Lauf) · Detail-Modal mit Vision-Beschreibung, editierbarem Vorschlagstext und Gutschrift-Betrag · Freigeben-Button (gruen/grau je nach Feature-Flag) · Ablehnen mit Pflicht-Grund · Risiko-Badge inline bei Lieferant · Konfidenz-Balken · Chat-Sidepanel.

Neue Backend-Endpoints (in routes/einkauf.js):

MethodeRouteBeschreibung
POST/chat/api/einkauf/reklamationen/:id/freigebenSetzt freigabe_status='freigegeben'. Body: optional {vorschlag_text, gutschrift_betrag, grund}. Prueft Feature-Flag auto_reklamation_versand. Audit-Log. requireAuth + requireWrite + requireCsrf + requireModule('einkauf').
POST/chat/api/einkauf/reklamationen/:id/ablehnenSetzt freigabe_status='abgelehnt' + status='abgeschlossen'. Body: {grund} (Pflicht). Audit-Log. requireAuth + requireWrite + requireCsrf + requireModule('einkauf').
GET/chat/api/einkauf/reklamationen/vorschlaege/statistikOffene Vorschlaege, Summe Gutschriften, rote Lieferanten, letzter Cron-Lauf. requireAuth + requireModule('einkauf').

Schatten-Modus: Feature-Flag auto_reklamation_versand = false (Standard). Bei Freigabe wird Status gesetzt, aber keine Mail versendet. Freigeben-Button zeigt "(Schatten-Modus aktiv)" und ist grau statt gruen.

Dateien: /var/www/html/einkauf/reklamationen/index.html, index.css, index.js

Vorgangsmodell – Phase 4: Risiko-Dashboard UI

Frontend fuer die Uebersicht des Lieferanten-Risiko-Scores. Seite: /einkauf/risiko/.

Features: 3 Ampel-Kacheln (rot/gelb/gruen, klickbar als Filter) · Tabelle aller Lieferanten sortiert nach Score · Mini-Bar-Charts inline fuer Rek-Quote, Diff-Quote, Vision-Mangel · Trend-Pfeil · Detail-Modal mit Score-Verlauf aus Audit-Log · Direkt-Link zu Reklamationen des Lieferanten · Chat-Sidepanel.

Dateien: /var/www/html/einkauf/risiko/index.html, index.css, index.js

Einkauf-Index ergaenzt: Zwei neue Kacheln "KI-Vorschlaege" und "Lieferanten-Risiko" mit animiertem Badge (rot wenn Vorschlaege offen / rote Lieferanten vorhanden).

Einkauf – Avis-Pipeline

Seite /einkauf/avis.html — Verwaltung avisierter Wareneingaenge. Zeigt alle vorab gemeldeten Lieferungen mit Status-Workflow (avisiert → geliefert → geprueft) und Soll/Ist-Abgleich.

Features: Stat-Kacheln (Gesamt/Geliefert/Geprueft/Abweichungen, interaktiv als Filter) · Status-Filter-Buttons · Lieferant-Dropdown-Filter · Datumsbereich-Filter (Standard: letzte 30 Tage) · Klick auf Zeile → /einkauf/avis-detail.html?id=X · Modal "Neues Avis" mit Lieferant-Dropdown, Datum und dynamischer Positionen-Tabelle · Ampel-Zusammenfassung (gruen=OK, orange=Warnung, rot=Fehler) · Status-Badges (avisiert=gelb, geliefert=blau, geprueft=gruen) · RUDI Chat-Panel (Modul: einkauf) · escHtml XSS-Schutz · Toast-System

API-Pfade (alle ueber /chat/api/einkauf/):

MethodeRouteBeschreibung
GET/chat/api/einkauf/avisListe. Query: status, lieferant_id, von, bis. Antwort: { items[], anzahl, stats }
POST/chat/api/einkauf/avisNeues Avis. Body: lieferant_id, datum, positionen[{artikel_bezeichnung, soll_menge, soll_einheit, soll_preis}]
GET/chat/api/einkauf/lieferanten/avis-configLieferanten mit Avis-Feldern fuer Dropdown

Einkauf – Lieferanten-Konfiguration

Seite /einkauf/lieferanten-config.html — Avis-Einstellungen und Artikel-Cross-Reference pro Lieferant. Accordion-Liste aller Lieferanten mit Inline-Konfiguration und Cross-Reference-Tabelle pro Lieferant.

Features: Stat-Kacheln (Gesamt/Aktiv/Verwogen/Cross-Refs) · Suche + Filter (Alle/Aktiv/Inaktiv) · Accordion-Details mit zwei Tabs (Konfiguration + Cross-Reference) · Quick-Toggle Avis aktiv/inaktiv direkt in der Listenzeile · Formular-Felder: avis_aktiv, gewichts_logik, toleranz_gewicht_prozent, toleranz_preis_prozent, referenz_dokumente · Expliziter Speichern-Button (kein Auto-Save) · Cross-Reference-Tabelle: Lieferant-Bezeichnung ↔ Interne Rohware ↔ Einheit ↔ Umrechnungsfaktor · Inline-Hinzufuegen neuer Cross-Refs · Loeschen mit Bestaetigung · RUDI Chat-Panel (Modul: einkauf) · escHtml XSS-Schutz · Toast-System

API-Pfade:

MethodeRouteBeschreibung
GET/chat/api/einkauf/lieferanten/avis-configAlle Lieferanten mit Avis-Feldern + cross_ref_count
PUT/chat/api/einkauf/lieferanten/:id/avis-configAvis-Konfiguration speichern. Body: avis_aktiv, gewichts_logik, toleranz_gewicht_prozent, toleranz_preis_prozent, referenz_dokumente
GET/chat/api/einkauf/cross-reference/:lieferantIdCross-Reference-Eintraege fuer einen Lieferanten
POST/chat/api/einkauf/cross-referenceNeuen Eintrag anlegen. Body: lieferant_id, rohware_id, lieferant_bezeichnung, lieferant_einheit, umrechnungsfaktor
DELETE/chat/api/einkauf/cross-reference/:idEintrag loeschen

Chargen-Verwaltung

Seite /einkauf/chargen.html — Tages- und Wochenansicht der Rohwaren-Chargen. Tag-Navigation, collapsible Kategorie-Gruppen, klickbare Zellen zum Bearbeiten (Modal), Farbkodierung nach Herkunft (Lieferung / Manuell), Suche ueber API + lokales Highlight, Excel- und PDF-Export.

Features: Tag/Woche-Ansicht · Datum-Navigation (Vor/Zurueck/Heute) · Bis zu 10 Zaehlung-Spalten (dynamisch erweiterbar) · Edit-Modal mit Past-Date-Warnung · Statistik-Kacheln (Gesamt/Befuellt/Offen/Vollstaendigkeit) · RUDI Chat-Panel (Modul: einkauf) · Excel-Export (SheetJS, nach Kategorie gruppiert) · PDF-Export (jsPDF + AutoTable, A4 Quer)

API-Pfade (alle ueber /chat/api/einkauf/chargen/):

MethodeRouteBeschreibung
GET/chat/api/einkauf/chargen/tag?datum=YYYY-MM-DDAlle Rohwaren + Chargen-Eintraege fuer einen Tag
GET/chat/api/einkauf/chargen/woche?start=YYYY-MM-DDWochenfortschritt (Mo-So): befuellt/gesamt pro Tag
GET/chat/api/einkauf/chargen/suche?q=TERMVolltext-Suche ueber Rohware und Chargennummern
GET/chat/api/einkauf/chargen/statistik?datum=YYYY-MM-DDTagesstatistik: befuellt, gesamt
PUT/chat/api/einkauf/chargen/:id/zelleZelle aktualisieren. Body: spalte, wert, origin
POST/chat/api/einkauf/chargen/zelleNeue Zelle erstellen. Body: datum, rohware_id, spalte, wert, origin
DELETE/chat/api/einkauf/chargen/:id/zelleZelle loeschen. Body: spalte

Bestand / Inventur

Seite /einkauf/bestand.html — Tages- und Wocheninventur der Rohwaren-Bestaende. Tag/Woche-Toggle, Suchfeld (Komma-getrennte Mehrfachsuche mit Gelb-Highlight), Vortagsvergleich (Auge-Button), Vortag kopieren, Tag loeschen mit 60s-Undo, Mehrfachzeilen pro Rohware, Kategorie-Export-Modal.

Rohware-Typen: 4 Typen — standard (Rohwaren in kg), bio (Bio-Rohwaren), packaging (Verpackungen in Stueck), supplies (Hilfsstoffe & Sonstiges: Bleche, Koerbe, Rollwagen, Aufguss, Behandlungsmittel, Saftbinder). Gruppierung nach Kategorie (BIO-Rohwaren, Fruechte, Gemuese, Kraeuter, Salat, Verpackung & Hilfsstoffe, Sonstiges).

Features: Tag/Woche-Ansicht · Suchfeld (Rohware oder Charge, komma-separiert) · Vortagsvergleich (Auge-Icon, Vortag-Werte in klein/grau) · Vortag kopieren (nur wenn Tag leer) · Tag loeschen + Undo (60s) · + Zusatzzeilen pro Rohware (x zum Loeschen) · Alle auf-/zuklappen-Button · Kategorie-Auswahl beim Excel/PDF-Export · Datum-Navigation · Inline-Edit (Enter/Blur/Escape) · Auto-Berechnung (colli × kg_pro_colli, lief_colli × lief_kg_pro_colli) · Unterdeckungs-Warnung (rot) · Statistik-Kacheln · Summenzeile · RUDI Chat-Panel (Modul: einkauf)

API-Pfade (alle ueber /chat/api/einkauf/bestand/):

MethodeRouteBeschreibung
GET/chat/api/einkauf/bestand?datum=YYYY-MM-DDAlle Rohwaren + Bestandszeilen fuer einen Tag
GET/chat/api/einkauf/bestand/statistik?datum=YYYY-MM-DDTagesstatistik: erfasst, gesamt, bestand_kg
GET/chat/api/einkauf/bestand/woche?start=YYYY-MM-DDWochendaten ab Montag: { start, tage: [{erfasst, gesamt}] }
POST/chat/api/einkauf/bestandNeue Zeile anlegen. Body: datum, rohware_id, feld-Werte
PUT/chat/api/einkauf/bestand/:id/zelleZelle aktualisieren. Body: spalte, wert
DELETE/chat/api/einkauf/bestand/:idEinzelne Zeile loeschen
DELETE/chat/api/einkauf/bestand/tag?datum=YYYY-MM-DDGanzen Tag loeschen. Gibt backup-Array zurueck.
POST/chat/api/einkauf/bestand/kopierenVortag kopieren. Body: { quellDatum, zielDatum }
POST/chat/api/einkauf/bestand/wiederherstellenGeloeschten Tag wiederherstellen. Body: { eintraege }
POST/chat/api/einkauf/bestand/zeile-hinzufuegenZusatzzeile fuer Rohware. Body: { datum, rohware_id }

Einkauf – Kontrakte

Seite /einkauf/kontrakte.html — Verwaltung von Rahmenvertraegen mit Lieferanten. Stats-Kacheln (aktive Kontrakte, bald ablaufend, gesamt), sortierbare Tabelle mit Ablauf-Warnung (90 Tage), Glasmorphism-Modal zum Erstellen/Bearbeiten, Excel- und PDF-Export (A4 Quer).

Features: Filter nach Lieferant/Rohware/Suchtext/Nur-aktive · Ablauf-Badge (rot wenn < 90 Tage) · Abgelaufene Zeilen grau/durchgestrichen · Sortierung per Spalten-Header · RUDI Chat-Panel (Modul: einkauf) · Excel-Export (SheetJS) · PDF-Export (jsPDF + AutoTable, A4 Quer)

API-Pfade (alle ueber /chat/api/einkauf/):

MethodeRouteBeschreibung
GET/chat/api/einkauf/kontrakteAlle Kontrakte. Query: aktiv=1, suche=TEXT
GET/chat/api/einkauf/kontrakte/faellig?tage=90Bald ablaufende Kontrakte
POST/chat/api/einkauf/kontrakteNeuer Kontrakt. Body: lieferant_id, rohware_id, datum_von, datum_bis, menge, intervall, preis, notizen, benachrichtigung_email
PATCH/chat/api/einkauf/kontrakte/:idKontrakt aktualisieren. Body: beliebige Felder
DELETE/chat/api/einkauf/kontrakte/:idKontrakt loeschen

Einkauf – Preislisten

Seite /einkauf/preislisten.html — Verwaltung und KI-gestuetzte Extraktion von Lieferanten-Preislisten. Upload per Drag&Drop (xlsx, xls, csv, pdf), KI-Analyse mit Fortschrittsanzeige, Mapping unbekannter Artikel auf Rohwaren per Dropdown.

Features: Stat-Kacheln (Aktiv/Entwurf/Archiviert/Letzte Aktualisierung – klickbar, filternd) · Upload-Karte mit Drag&Drop-Zone, Lieferant-Dropdown, Gueltig-ab-Datum · Fortschrittsbalken waehrend KI-Extraktion · Portal-Scraper-Status (wenn Portal-Quellen vorhanden) · Sortierbare Tabelle (Lieferant, Datei, Quelle-Badge, Positionen, Status, Datum, Aenderungen) · Detail-Modal mit Positionstabelle und Preisvergleich (gruen=guenstiger, rot=teurer) · Ungemappte Artikel gelb markiert mit Zuordnungs-Dropdown · "Aktivieren" und "Loeschen" nur fuer Entwuerfe · RUDI Chat-Panel (Modul: einkauf)

API-Pfade (alle ueber /chat/api/einkauf/):

MethodeRouteBeschreibung
GET/chat/api/einkauf/lieferantenLieferantenliste fuer Dropdown
GET/chat/api/einkauf/preislistenListe. Query: status, lieferant_id, quelle
GET/chat/api/einkauf/preislisten/:idDetail mit Positionen-Array
POST/chat/api/einkauf/preislisten/uploadDatei hochladen (multipart). Felder: datei, lieferant_id, gueltig_von, quelle
POST/chat/api/einkauf/preislisten/:id/aktivierenPreisliste aktivieren (Entwurf -> Aktiv, bisherige archivieren)
DELETE/chat/api/einkauf/preislisten/:idPreisliste loeschen (nur Entwuerfe)
POST/chat/api/einkauf/preislisten/:id/positionen/:posId/mappingRohware zuordnen. Body: { rohware_id }
GET/chat/api/einkauf/preise/scrape/statusPortal-Scraper-Status (laufend, fehler, zuletzt_lauf, naechster)
GET/chat/api/einkauf/rohwarenRohwaren fuer Mapping-Dropdown

Einkauf – Preisabweichungen

Seite /einkauf/preisabweichungen.html — Preisabweichungs-Dashboard: Uebersicht aller Abweichungen zwischen Soll- und Referenzpreis mit Ampel-Visualisierung (gruen/gelb/rot), Akzeptanz- und Reklamations-Workflow sowie Top-Lieferanten-Auswertung.

Features: 4 Stat-Kacheln (Offen, Rot/Dringend, Gelb/Pruefen, Offene Differenz EUR) als klickbare Filter · Filter-Bar: Lieferant, Datum von/bis, Status · Tabelle mit 10 Spalten, sortierbar, horizontales Scrollen auf Mobile · Ampel-Dot (gruen/gelb/rot) pro Zeile · Aktions-Buttons: Akzeptieren (nur offen), Reklamieren (nur offen), Notiz-Textarea pro Zeile · Batch-Button "Alle Bagatellen akzeptieren" · Top-Lieferanten-Karten mit Abweichungs-Balken · RUDI Chat-Panel (Modul: einkauf)

API-Pfade:

MethodeRouteBeschreibung
GET/api/einkauf/preisabweichungenListe. Query: status, ampel, lieferant_id, datum_von, datum_bis
GET/api/einkauf/preisabweichungen/dashboardKachel-Werte + top_lieferanten[]
PUT/api/einkauf/preisabweichungen/:idAktion. Body: { aktion: "akzeptiert"|"reklamiert", notizen: "..." }
POST/api/einkauf/preisabweichungen/bagatellenAlle Bagatellen akzeptieren. Body: { lieferant_id? }
GET/api/einkauf/lieferantenLieferantenliste fuer Dropdown

Einkauf – Preisanalyse

Seite /einkauf/preisanalyse.html — Preisanalyse-Dashboard mit Trendverlauf, Lieferantenvergleich und auto-generierten Einsparhinweisen. Chart.js-Liniendiagramm mit Zeitraum-Wahl (3M/6M/12M), Dark-Mode-optimierten Farben und EUR-Tooltip-Format.

Features: 4 Stat-Kacheln (Aktive Lieferanten, Rohwaren mit Preisen, Aenderungen letzter Monat, Einsparpotenziale) · Rohware-Dropdown (GET /rohwaren) · Preisverlauf-Chart (Chart.js lokal, /shared/chart.umd.min.js) mit einer Linie je Lieferant · Zeitraum-Buttons 3M/6M/12M · Lieferantenvergleich-Tabelle: Rang, Lieferant, Preis, Avg 12M, Trend-Pfeil, vs-Bester · Hinweise-Grid (gruen/orange/rot-Karten) · Export-Button (xlsx-Download) · RUDI Chat-Panel (Modul: einkauf)

API-Pfade (alle ueber /chat/api/einkauf/):

MethodeRouteBeschreibung
GET/chat/api/einkauf/analyse/statsKachel-Werte: lieferanten, rohwaren, aenderungen, einsparpotenziale
GET/chat/api/einkauf/analyse/trend/:rohwareIdPreisverlauf. Query: monate=3|6|12. Antwort: { labels[], datasets[{label, data[]}] }
GET/chat/api/einkauf/analyse/vergleich/:rohwareIdLieferantenvergleich fuer Rohware. Antwort: [{lieferant_name, preis_aktuell, preis_avg_12m, trend_prozent}]
GET/chat/api/einkauf/analyse/hinweiseAuto-generierte Hinweise. Antwort: [{titel, text, typ: gruen|orange|rot}]
GET/chat/api/einkauf/analyse/exportExcel-Export. Query: rohware_id?, lieferant_id?. Datei: preisanalyse.xlsx
GET/chat/api/einkauf/rohwarenRohwaren-Liste fuer Dropdown

Einkauf – Bestellungen

Seite /einkauf/bestellungen.html — Kundenbestellungen erstellen und verwalten. Zwei Tabs: "Bestellung erstellen" (Einstellungen + Multi-Select-Artikel + Positionstabelle + Excel-Export) und "Bestellhistorie" (collapsible Cards, loeschbar).

Features: Bestelldatum (default: morgen) · Empfaenger + CC E-Mails · Multi-Select-Dropdown mit Suchfeld und Checkbox pro Rohware · Ausgewaehlte Artikel als Tags · Bestand-Daten (Bedarf/Einkauf) automatisch befuellt · Editierbare Mengen und Einheiten · Excel-Export (SheetJS, Dateiname Bestellung_DD-MM-YYYY.xlsx) · Bestellhistorie collapsible mit Loeschen-Button · RUDI Chat-Panel (Modul: einkauf)

API-Pfade (alle ueber /chat/api/einkauf/):

MethodeRouteBeschreibung
GET/chat/api/einkauf/bestellungenListe aller Bestellungen mit positionen[]
GET/chat/api/einkauf/bestellungen/:idEinzelne Bestellung
POST/chat/api/einkauf/bestellungenNeue Bestellung. Body: bestelldatum, empfaenger_email, cc_emails[], notizen, positionen[{rohware_id, rohware_name, menge, einheit}]
DELETE/chat/api/einkauf/bestellungen/:idBestellung loeschen. Antwort: {status: 'geloescht'}
GET/chat/api/einkauf/rohwarenRohwaren-Liste fuer Artikel-Auswahl
GET/chat/api/einkauf/bestand?datum=YYYY-MM-DDBestand fuer Bedarf/Einkauf-Vorbefuellung

Einkauf – Stammdaten

Seite /einkauf/stammdaten.html — Verwaltung von Lieferanten, Rohwaren (Artikeln) und Kategorien. Drei Tabs, jeweils mit Suchfeld, Filtern, Tabelle und Glasmorphism-Modals zum Erstellen/Bearbeiten.

Features: Lieferanten (Name, E-Mail, Kontaktperson, Telefon, CRUD) · Rohwaren (Name, Kategorie, Typ: bio/standard/packaging/supplies, CRUD) · Typ-Badges (gruen=bio, cyan=standard, grau=packaging, braun=supplies) · Kategorien (CRUD, Loeschen mit Hinweis) · Kategorie-Dropdown synchronisiert zwischen Tab und Modal · Confirm-Dialog vor Loeschungen · Skeleton-Loader · RUDI Chat-Panel (Modul: einkauf)

API-Pfade (alle ueber /chat/api/einkauf/):

MethodeRouteBeschreibung
GET/chat/api/einkauf/lieferantenAlle Lieferanten
POST/chat/api/einkauf/lieferantenNeuer Lieferant. Body: name, email, kontakt, telefon
PUT/chat/api/einkauf/lieferanten/:idLieferant aktualisieren
DELETE/chat/api/einkauf/lieferanten/:idLieferant loeschen
GET/chat/api/einkauf/rohwarenAlle Rohwaren mit kategorie_id und typ
POST/chat/api/einkauf/rohwarenNeue Rohware. Body: name, kategorie_id, typ
PUT/chat/api/einkauf/rohwaren/:idRohware aktualisieren
GET/chat/api/einkauf/kategorienAlle Kategorien
POST/chat/api/einkauf/kategorienNeue Kategorie. Body: name
PUT/chat/api/einkauf/kategorien/:idKategorie umbenennen
DELETE/chat/api/einkauf/kategorien/:idKategorie loeschen

Vorgangsmodell – Phase 1 (Datenmodell & Migration)

Das zentrale Vorgangsmodell klamert alle Beschaffungsbelege (Bestellung → Avis → Wareneingang → Reklamation → Rechnung → Gutschrift) in einer einzigen vorgang-Tabelle. Phase 1 legt das Datenbankschema an und backfilled alle bestehenden Wareneingaenge (1770 Stk.), Reklamationen (144 Stk.) und Rechnungen.

Neue Tabellen in ~/einkauf/einkauf.db:

TabelleBeschreibung
vorgangZentrale Klammer. Status: angelegt|bestellt|avisiert|teilgeliefert|geliefert|geprueft|reklamiert|verrechnet|abgeschlossen|storniert
vorgang_referenzn:m Belege zu Vorgang (beleg_typ: bestellung|avis|lieferschein|wareneingang|rechnung|reklamation|gutschrift)
bestellungBestellungen (Telefon/Mail/Portal/App) mit kanal, voicenote_pfad, erfasst_von
bestellung_positionPositionen pro Bestellung (rohware_id, soll_menge, einheit, country_hint)
lieferant_zertifikatBio/IFS/GLOBALG.A.P./QS-Zertifikate pro Lieferant mit Ablauf-Erinnerung

Neue Spalten (ALTER TABLE, bestehende Daten unveraendert): wareneingaenge.vorgang_id, .herkunftsland_iso, .quality_status, .auto_validierung_json · we_positionen.soll_menge_quelle, .abweichung_kategorie · reklamationen.vorgang_id, .auto_erstellt, .ki_vorschlag_json, .freigabe_status · cockpit_auffaelligkeiten.vorgang_id, .claude_kommentar

View: vorgang_uebersicht — Joined-View mit Lieferant-Name und Beleg-Zaehler (WE/Reks/Rechnungen/Bestellungen).

DB-Layer:

DateiFunktionen
~/rudi-chat/lib/edb/vorgang.jscreateVorgang, getVorgang, listVorgaenge, updateStatus, updateRisiko, linkBeleg, getReferenzen, getVorgangByBeleg, closeVorgang, getRisikoStats, getVorgangsKette
~/rudi-chat/lib/edb/bestellung.jscreateBestellung, getBestellung, listBestellungen, copyLastBestellung, storniereBestellung

Migration-Skripte:

SkriptFunktion
~/einkauf/migrations/001_vorgangsmodell.jsMigration ausfuehren (idempotent, 2x laufbar ohne Schaden)
~/einkauf/migrations/001_vorgangsmodell_rollback.jsRollback: neue Tabellen loeschen, neue Spalten nullen

Backfill-Ergebnisse (2026-04-27): 1770 WE-Vorgaenge · 144 Reklamationen verlinkt · 25 Rechnungen an WE-Vorgaenge · 744 neue Rechnungs-Vorgaenge (verrechnet) · 0 WE ohne vorgang_id

Hinweis: Phase 1 legt das Datenmodell an. API-Routes fuer Bestellungen: Phase 2 (routes/bestellung.js). Feature-Flag vorgang_anzeige steuert Frontend-Sichtbarkeit.

Migration 002 – Backfill-Cleanup (2026-04-28, Korrektur 3 mib-logik-Audit)

Phase-1 hatte fuer jede Rechnung ohne eindeutigen WE-Match einen eigenen Vorgang angelegt. Ergebnis: 746 "Rechnung-ohne-WE"-Vorgaenge (30% Datenmüll). Migration 002 bereinigt das idempotent in 3 Stufen:

SkriptFunktion
~/einkauf/migrations/002_vorgang_cleanup.jsCleanup ausfuehren (idempotent). Backups: 002_backup_*.json. Bericht: 002_cleanup_report.json.
~/einkauf/migrations/002_vorgang_cleanup_rollback.jsRollback: stellt geloeschte Vorgaenge + Referenzen aus Backup-JSON wieder her

Ergebnis (2026-04-28): 2516 → 2513 Vorgaenge · Operational: 1771 · Nur-Rechnung: 742 (aus Listen rausgefiltert) · 1 Leervorgang geloescht

Vorgangsmodell – Phase 2: Bestellungs-Erfassung

Backend-Route ~/rudi-chat/routes/bestellung.js, gemountet als /chat/api/bestellung. Alle Endpunkte benoetigen requireAuth + requireModule('einkauf'). Schreib-Endpunkte zusaetzlich requireWrite + requireCsrf. Audit-Log bei jeder Mutation (modul='bestellung').

Feature-Flag: bestellung_voice (Default: OFF) — Voice-Endpoint gibt 403 wenn deaktiviert.

MethodeRouteAuthBeschreibung
GET/chat/api/bestellungAuth+ModulListe. Filter: ?lieferant_id=&status=&kanal=&von=&bis=&limit=50&offset=0
GET/chat/api/bestellung/:idAuth+ModulEinzelne Bestellung mit Positionen + verlinktem Vorgang
POST/chat/api/bestellungAuth+Write+CSRFNeue Bestellung anlegen. Body: {lieferant_id, datum, kanal, bemerkung_freitext, positionen:[{artikel_text, soll_menge, einheit, country_hint}]}. Legt automatisch Vorgang an (status='bestellt'). Response: {bestellung_id, vorgang_id}
PUT/chat/api/bestellung/:idAuth+Write+CSRFFelder aendern (nur wenn status='aktiv'): kanal, bemerkung_freitext, datum
DELETE/chat/api/bestellung/:idAuth+Write+CSRFStornieren (kein hard delete). Setzt Bestellung + verlinkten Vorgang auf status='storniert'
POST/chat/api/bestellung/copy-lastAuth+Modul+CSRFPositionen der letzten Bestellung eines Lieferanten laden. Body: {lieferant_id}. Response: {kopiert_von, positionen}
GET/chat/api/bestellung/lieferant/:id/templateAuth+ModulStandardkorb: haeufigste Positionen der letzten 30 Tage. Query: ?tage=30
POST/chat/api/bestellung/:id/voiceAuth+Write+CSRFVoice-Notiz (multipart audio). Transkription via Gemini STT + Claude Positions-Extraktion. Nur wenn Feature-Flag bestellung_voice aktiv (sonst 403). Response: {transcription, vorgeschlagene_positionen}

Claude-Tools (Chat):

ToolBeschreibung
bestellung_erfassenErfasst eine neue Bestellung im Chat. Input: lieferant_name (fuzzy), datum, kanal, positionen[]. Legt Vorgang an und bestaetigt mit ID.
bestellung_kopierenZeigt letzte Bestellung eines Lieferanten als Vorlage. Input: lieferant_name. Gibt Positionen zur Pruefung aus.

Handler-Dateien: ~/rudi-chat/routes/bestellung.js · ~/rudi-chat/lib/tools/handlers/bestellung.js · multer-secure.js um Audio-Preset erweitert (wav/mp3/m4a/webm/ogg)

Multer Audio-Preset: max 25 MB, Magic-Bytes-Check (WAV/MP3/OGG/WebM/M4A), kein EXIF-Strip (Audio hat kein EXIF). Destination: ~/uploads/voice-bestellung/

Frontend Bestellungs-Erfassung (Phase 2 UI)

Ziel: Telefonbestellungen in <30 Sekunden erfassen. Mobile-first, 375px-tauglich, Touch-Targets ≥36px, Apple Glasmorphism.

SeitePfadBeschreibung
Listen-Seite/einkauf/bestellung/Tabelle aller Bestellungen mit Filtern (Lieferant, Datum, Status, Suche). Paginiert (50/Seite). Klick auf Zeile → Detail. "+ Neue Bestellung" oben rechts.
Neu-Seite (Quickform)/einkauf/bestellung/neu.html4-Schritt-Wizard: (1) Lieferant-Autocomplete → (2) Modus (Letzte kopieren / Standardkorb / Leer / Voice wenn Flag aktiv) → (3) Positionen-Editor → (4) Bemerkung + Speichern. Stoppuhr-KPI in Nav-Bar sichtbar.
Detail-Seite/einkauf/bestellung/detail.html?id=XBestellungs-Kopf + Positionen-Tabelle + Vorgang-ID + Aktionen (Bearbeiten, Stornieren mit Modal). Voice-Bereich nur wenn Feature-Flag bestellung_voice aktiv.

Feature-Flag bestellung_voice (Default OFF): Wenn aus → Voice-Modus-Card in Schritt 2 versteckt, Voice-Sektion in Detail-Seite ausgeblendet. Schaltbar in /admin/feature-flags.

Kachel in Einkauf-Dashboard: "Bestellung erfassen" (/einkauf/index.html) verlinkt direkt auf /einkauf/bestellung/neu.html (hervorgehoben in Accent-Farbe).

Dateien: /var/www/html/einkauf/bestellung/ (index.html, index.js, neu.html, neu.js, detail.html, detail.js, bestellung.css)

Produktionsplanung

Rohwaren-Bedarfsberechnung aus OData-Sync + Stücklisten. Datenbank: ~/produktionsplanung/produktionsplanung.db.

MethodeRouteBeschreibung
POST/chat/api/produktionsplanung/uploadExcel-Tagesbedarf hochladen. Feld: datei.
POST/chat/api/produktionsplanung/stuecklisten/importStücklisten-Excel importieren. Feld: datei.
GET/chat/api/produktionsplanung/stuecklisten/statusStücklisten-Status: Anzahl Zeilen, Artikel, letzter Import.
GET/chat/api/produktionsplanung/tageVerfuegbare Tage mit importierten Daten.
GET/chat/api/produktionsplanung/ergebnis/:datumBerechnetes Ergebnis (Rohwaren + Unmatched) fuer ein Datum.
GET/chat/api/produktionsplanung/detail/:datum/:rw_idDetail-Aufschlüsselung einer Rohware fuer ein Datum.
GET/chat/api/produktionsplanung/unmatched/:datumNicht zugeordnete Artikel fuer ein Datum.
POST/chat/api/produktionsplanung/odata/syncManueller OData-Sync. Body: {datum} (opt, Default heute).
GET/chat/api/produktionsplanung/odata/statusSync-Status: aktiv, letzter Sync, Credentials vorhanden.

Prognose-Endpunkte

KI-gestuetztes Lernmodell (EWMA) fuer 14-Tage-Rohwaren-Prognose. Externe Faktoren: Wetter (Open-Meteo, Freiburg), Schulferien + Feiertage BW. Modell-Faktoren werden nach jedem OData-Sync automatisch aktualisiert.

MethodeRouteBeschreibung
GET/chat/api/produktionsplanung/prognose/rohwarenAlle Rohwaren mit Historik-Länge und MAPE.
GET/chat/api/produktionsplanung/prognose/historik/:rohware_idHistorische Ist-Werte + aktuelle 14-Tage-Prognose. Query: ?tage=365.
POST/chat/api/produktionsplanung/prognose/berechnen/:rohware_idPrognose neu berechnen und in DB speichern. Response: {prognosen, mape, warnung}.
GET/chat/api/produktionsplanung/prognose/vergleich/:rohware_idPrognose vs. Ist (rueckwirkend). Query: ?von=&bis= (Default: letzte 90 Tage). Response: {vergleich, mape}.
GET/chat/api/produktionsplanung/prognose/externe-faktorenWetter + Ferien fuer die naechsten 14 Tage.
POST/chat/api/produktionsplanung/prognose/uploadExcel-Upload fuer historische Daten. Feld: file.
POST/chat/api/produktionsplanung/prognose/ausreisser/:datum/:rohware_idAusreisser ein-/ausschalten. Body: {ausgeschlossen: true|false}.
GET/chat/api/produktionsplanung/prognose/lernfortschritt/:rohware_idModell-Faktoren, MAPE-Verlauf (woechentlich) und KI-Erklaerungen.

System

MethodeRouteBeschreibung
GET/chat/api/system/statusServer-Status: CPU, RAM, Disk, Services, Uptime, OS-Info

Feature-Flag-System

Zentrale Laufzeit-Schalter fuer RUDI-Features. Kein Code-Aenderung, kein Service-Restart noetig. DB: ~/feature-flags/flags.db (eigene SQLite, WAL-Mode). Cache-Reload alle 30 Sekunden. Jede Aenderung wird in flags_history auditiert.

Aktuelle Flags (Phase-0-Matrix)

FlagDefaultWirkung wenn OFF
vorgang_anzeigeOFFFrontend zeigt nur alten Wareneingang
bestellung_voiceOFFVoice-Bestellung versteckt, nur Quickform
we_country_pflichtONCountry-of-Origin wird optional (FSMA-Risiko!)
we_vision_warnungONVision-Hinweise im WE-Modal versteckt
auto_reklamation_solvegaON (Schatten)Reklamations-Vorschlaege nicht generiert
auto_reklamation_versandOFFVorschlaege ja, kein Auto-Mail-Versand
pipeline_vision_crossONPipeline laeuft nur mit Tesseract
bolt_sync_activeONBolt.new-Datenpull pausiert (Kill-Switch)
recall_drill_cronONWoechentlicher FSMA-Recall-Drill deaktiviert
vision_backfill_nightlyONVision-Backfill-Cron aktiv (02:45 UTC, 500 Bilder/Nacht, wareneingang_bilder + reklamation_bilder)
claude_briefing_pwaONAuffaelligkeiten nicht in PWA-Briefing gepusht
upload_hardeningONLegacy-Multer (50 MB, kein EXIF-Strip, kein Magic-Bytes-Check)
bio_quality_gateONBIO-WE mit Vision-Mangel wird NICHT gesperrt — nur Warnung (IFS-Risiko! Nur fuer Tests deaktivieren)

API-Endpunkte (Feature Flags)

MethodeRouteAuthBeschreibung
GET/chat/api/auth/flagsrequireAuthAlle Flags als Name->Boolean-Map (scope-aware, fuer Frontend-Loader)
GET/chat/api/admin/flagsrequireAdminAlle Flags mit History-Anzahl (Admin-UI)
GET/chat/api/admin/flags/:namerequireAdminEin Flag
PUT/chat/api/admin/flags/:namerequireAdmin + CSRFFlag setzen. Body: {aktiv: bool, grund: string}. Schreibt Audit-Eintrag (modul: flags, aktion: flag_change).
GET/chat/api/admin/flags/:name/historyrequireAdminLetzte 50 Aenderungen

Zentrales Audit-Log (Phase 0)

FSMA-204 / EU-Lebensmittelrueckverfolgung konformes Audit-Log. Eigenstaendige SQLite-DB ~/audit/audit.db (WAL, append-only via SQL-Trigger). Jede Datenänderung an Vorgangs-relevanten Daten wird unveraenderlich geloggt.

Backend: ~/rudi-chat/lib/audit.js | Route: ~/rudi-chat/routes/admin-audit.js | Mount: /chat/api/admin/audit

Append-only: SQL-Trigger blockieren UPDATE + DELETE auf der log-Tabelle (SQLite RAISE ABORT). Cloud-Backup: ~/bin/cloud-sync.sh databases (alle 2h direkt aus ~/audit/audit.db).

MethodeRouteAuthBeschreibung
GET/chat/api/admin/auditrequireAdminPaginierte Abfrage. Query-Params: ressource_typ, ressource_id, user_id, modul, aktion, ts_from, ts_to, limit, offset
GET/chat/api/admin/audit/statsrequireAdminStatistiken: Eintraege heute/Woche/Monat, Top-User, Top-Module, Top-Aktionen
GET/chat/api/admin/audit/ressource/:typ/:idrequireAdminLebenslauf einer Ressource (chronologisch, fuer FSMA-Recall)

Bolt-Migration-Dashboard (Phase 6 Vorgangsmodell)

Backend: ~/rudi-chat/routes/admin-bolt.js | Mount: /chat/api/admin/bolt-diff | Frontend: /admin/bolt-migration.html

Taeglicher Drift-Report zwischen bolt.new (Firebase) und RUDI fuer die drei Hauptkacheln: Bestand, Wareneingang, Reklamation. 4-Wochen-Parallelbetrieb mit Empfehlung fuer Umschaltung.

MethodeEndpunktAuthBeschreibung
GET/chat/api/admin/bolt-diff/latestrequireAdminLetzter Diff-Bericht aus ~/backups/bolt-diff/
GET/chat/api/admin/bolt-diff/trend?days=7requireAdminTrend-Daten (max 30 Tage). Gibt Drift-Zeitreihe + Zaehler aller-Kacheln-unter-Schwelle.

Cron: /etc/cron.d/bolt-diff-report — taeglich 03:00 UTC. Skript: ~/bin/bolt-diff-report.js. Output: ~/backups/bolt-diff/YYYY-MM-DD.json. Audit-Eintrag: modul=bolt-migration, aktion=diff_report.

Schwelle: 0.5% Drift je Kachel. Empfehlung BOLT_READONLY_OK wenn 7 Tage am Stueck alle Kacheln darunter. "Bolt auf Read-Only"-Button in Frontend setzt Feature-Flag bolt_sync_active=OFF (nur manuell, nie automatisch).

workflow-audit.js prueft taeglich ob letzter Bericht juenger als 36h ist und ob Drift-Schwelle ueberschritten.

Vorgangsmodell – Phase 7: Compliance & Claude-Briefing-Layer (2026-04-28)

FSMA-204-Compliance-Automatisierung + Lieferanten-Zertifikat-Management + vorgang_analyse-Tool fuer RUDI-Chat.

1. Recall-Drill aktiviert

Cron /etc/cron.d/recall-drill ist seit 2026-04-28 aktiv (Mo 06:00 UTC, vorher auskommentiert). Feature-Flag recall_drill_cron auf ON gesetzt. Skript: ~/bin/recall-drill.js. Log: ~/backups/recall-drill.log. CLI: --random | --charge <nr> | --we-id <id> | --json.

2. Lieferanten-Zertifikate

Frontend: /einkauf/zertifikate/index.html — Tabelle aller Zertifikate, Filter (alle/ablaufend/abgelaufen), + Neu / Edit-Modal / Loeschen. Rollen: requireAuth + requireModule('einkauf').

Cron: /etc/cron.d/zertifikat-erinnerung — taeglich 05:00 UTC. Skript: ~/bin/zertifikat-erinnerung.js. Prueft lieferant_zertifikat mit erinnerung_aktiv=1. Legt Cockpit-Eintraege typ='zertifikat_ablauf' an (warn = ablaufend, kritisch = abgelaufen). Duplikat-Schutz per UNIQUE-Check. Log: ~/backups/zertifikat-erinnerung.log.

MethodeRouteBeschreibung
GET/chat/api/einkauf/zertifikateListe. Query: lieferant_id, filter (alle|ablaufend|abgelaufen). Antwort: { zertifikate[], total }. Felder: id, lieferant_id, lieferant_name, typ, nummer, ausgestellt_am, gueltig_bis, status_berechnet. Auth: requireAuth + requireModule('einkauf').
POST/chat/api/einkauf/zertifikateNeues Zertifikat anlegen. Body: lieferant_id*, typ*, nummer, ausgestellt_am, gueltig_bis, beleg_pfad, ausgestellt_von, erinnerung_aktiv, erinnerung_tage_vorher. Auth: requireWrite + requireCsrf + requireModule('einkauf').
PUT/chat/api/einkauf/zertifikate/:idZertifikat aktualisieren. Body: alle Felder optional (COALESCE-Update). Auth: requireWrite + requireCsrf + requireModule('einkauf').
DELETE/chat/api/einkauf/zertifikate/:idZertifikat loeschen. Auth: requireWrite + requireCsrf + requireModule('einkauf').

3. Tool vorgang_analyse

Neues RUDI-Chat-Tool (definitions.js + handlers/vorgang.js). Eingabe: vorgang_id ODER charge ODER we_id. Ausgabe: strukturierter Text mit Stammdaten, Beleg-Kette, Mengenvergleich, Reklamationen, Bilder/Vision, Lieferanten-Risiko-Score, Vollstaendigkeits-Score (0-1), FSMA-4h-Bewertung.

4. Briefing-Erweiterung (Phase 7)

briefing.js gibt jetzt compliance: { recall_drill_letzte, bolt_diff_status, zertifikate_ablaufend } zurueck. formatComplianceText() formatiert als lesbaren Text fuer Voice/Chat. shortSummary() erwaehnt ablaufende Zertifikate. Neue Exports: getRecallDrillLetzteErgebnisse(n), getBoltDiffStatus(), getZertifikateAblaufend(tage).

5. workflow-audit.js — checkZertifikate()

Neuer Check: prueft abgelaufene Zertifikate (→ kritisch) und in 14 Tagen ablaufende (→ warn). Laeuft im taegl. Workflow-Audit-Cron (04:00 UTC).

Backend-API (lib/audit.js)

FunktionBeschreibung
write(entry)Synchroner Audit-Eintrag <2ms (better-sqlite3, prepared stmt). entry: {user, modul, aktion, ressource_typ, ressource_id, before, after, req?, notiz?, opts?}
writeAsync(entry)Non-blocking via setImmediate (fuer hot paths)
query(opts)Paginierte Abfrage mit Filtern (ressource_typ, user_id, modul, aktion, ts_from, ts_to, limit, offset)
getRecent(limit)Letzte N Eintraege fuer Admin-UI
getForRessource(typ, id)Lebenslauf einer Ressource (chronologisch, Recall-faehig)
getStats()Zaehler heute/Woche/Monat + Top-User/Module/Aktionen
middleware(modul)Express-Middleware-Factory: loggt HTTP-Requests nach Response (non-blocking)

Sensible Felder (password, password_hash, pin, api_key, token, secret etc.) werden vor dem Speichern automatisch durch [REDACTED] ersetzt. before/after-Felder auf max. 50 KB begrenzt (Truncation-Hinweis bei Ueberschreitung).

Backend-Modul (lib/feature-flags.js)

FunktionBeschreibung
init()DB oeffnen, Schema, Default-Flags seeden, Cache laden, 30s-Reload starten
getFlag(name, default)Synchron aus Cache (boolean). Fuer Backend-Checks.
getFlagsForUser(user)Map aller Flags, scope-aware (global / rolle:X / user:UUID)
setFlag(name, aktiv, von, grund)Schreibt + History-Eintrag + Cache sofort neu laden
seedFlags(array)Idempotent: legt Flags an ohne bestehende aktiv-Werte zu ueberschreiben

Phase-0-Sicherheitsbausteine

Drei Sicherheitsmodule, die als Fundament fuer DSGVO-konforme Uploads und HMAC-gesicherte Webhook-Integrationen dienen. Hinzugefuegt 2026-04-27.

EXIF-Stripper (lib/exif-strip.js)

Entfernt EXIF-Metadaten (GPS, Kamera-Daten, Timestamps) aus Bild-Uploads. Verhindert DSGVO-Risiko bei Reklamations-/Wareneingangs-Fotos mit Mitarbeiter-Bezug (Geo-Koordinaten). Nutzt sharp().rotate() ohne withMetadata() — atomarer Datei-Tausch via tmp-Datei.

FunktionBeschreibung
stripFile(srcPath, dstPath?)Entfernt EXIF in-place (oder nach dstPath). Bei Fehler: ok:false, Original unveraendert.
stripBuffer(buf, hint?)Verarbeitet Buffer direkt. Bei HEIC/HEIF: Konvertierung zu JPEG.
needsStripping(filePath)Prueft ob Dateiformat EXIF enthalten kann (JPEG, PNG, WebP, HEIC, HEIF, AVIF, TIFF).

Gehaerteter Multer-Helper (lib/multer-secure.js)

Factory fuer gehaertete Multer-Instanzen. Ersetzt direkte multer()-Aufrufe in Routen. Integriert: Mime-Whitelist, Magic-Bytes-Check (defense-in-depth gegen MIME-Spoofing), EXIF-Stripping, File-Size-Limit 25 MB. Feature-Flag upload_hardening schaltet gehaertete Pipeline ein (ON = Default) oder zurueck auf Legacy.

Mime-Presets: 'image' (JPEG/PNG/WebP/HEIC/HEIF), 'document' (PDF + Bilder), 'mixed' (alle). Magic-Bytes werden aus den ersten 12 Bytes der Datei gelesen — keine externe NPM-Abhaengigkeit.

APIBeschreibung
createMulter({destination, maxSize, maxFiles, accept, stripExif, filename})Gibt Multer-kompatibles Objekt mit .single(), .array(), .fields(), .any() zurueck.
detectMagicType(filePath)Liest erste 12 Bytes, gibt 'jpeg' | 'png' | 'webp' | 'heic' | 'pdf' | null zurueck.

Aktuell genutzt: routes/einkauf.js — Wareneingang-Bild-Upload (WE-Fotos + Lieferschein-Scans).

HMAC-Middleware (lib/hmac-middleware.js)

Signaturpruefung fuer kuenftige Webhook-Endpunkte von Lieferanten-Portalen (Push-Avis). Kein Session-Cookie, kein CSRF. Auth via HMAC-SHA256 ueber timestamp + '\n' + rawBody. Clock-Skew-Pruefung (default 5 Min) verhindert Replay-Angriffe. crypto.timingSafeEqual verhindert Timing-Angriffe. Secrets werden nie geloggt.

Mount-Reihenfolge: Webhook-Router MUSS vor express.json() gemountet werden (raw body muss unverbraucht sein). In server.js am Anfang, vor globalem Body-Parser.

ExportBeschreibung
captureRawBodyMiddleware: liest Stream, setzt req.rawBody (Buffer) und req.body (JSON-Objekt).
hmacAuth({secret, header, algorithm, format, maxClockSkewSeconds})Factory: gibt Auth-Middleware zurueck. secret: 'env:NAME' | 'literal:...' | (req)=>string.

Test-Endpunkt: POST /chat/api/hooks/test — HMAC-Secret: 'test-shared-secret'. Fuer Produktion: env:WEBHOOK_SECRET_LIEFERANTNAME in /etc/environment.

Webhook-Route-Gruppe (routes/hooks-example.js)

Gemountet als /api/hooks/* VOR globalem Auth. Neue Lieferanten-Webhooks werden hier als zusaetzliche router.post()-Eintraege angelegt.

MethodeRouteAuthBeschreibung
POST/chat/api/hooks/testHMAC (literal:test-shared-secret)Test/Entwicklungs-Endpunkt. Antwortet mit ok:true + empfangenen Daten.

Test-Suite & Self-Improvement

RUDI hat ein automatisches Test- und Lernsystem. Jeder gemeldete Bug fuehrt zu einem Fix, einem neuen Test und einer gelernten Regel — damit der gleiche Fehler nie wieder auftritt.

Master-Testrunner

BefehlBeschreibung
node ~/bin/rudi-test.jsAlle Tests (Layout + API + Custom)
node ~/bin/rudi-test.js --layoutNur Layout-Tests (15 Seiten via Puppeteer)
node ~/bin/rudi-test.js --apiNur API-Endpunkte (14 Endpoints)
node ~/bin/rudi-test.js --customNur Custom-Checks (test-checks.json)
node ~/bin/rudi-test.js --verboseAusfuehrliche Ausgabe

Ergebnis: ~/rudi-chat/test-results.json (JSON), Exit-Code 0 = bestanden, 1 = Fehler.

Layout-Tests (15 Seiten)

Getestete Seiten: Dashboard, QMS, Aufgaben, Reklamation, Dateien, System, Pipeline, Maschinen, Maschine-Detail, Vorschlaege, Vorschlag-Detail, Notfall, Notfall-Druck, Doku, Chat.

Checks pro Seite:

Screenshots: ~/layout-tests/

/bugfix Skill — Self-Improvement-Loop

Der /bugfix Skill ist der Kern des Lernsystems. Er wird automatisch aktiviert wenn der User ein Problem beschreibt:

Der Skill fuehrt automatisch 5 Schritte durch:

  1. Analyse: Betroffene Datei lesen, Root-Cause finden
  2. Fix: Minimaler, gezielter Fix implementieren
  3. Test: Neuen Check in test-checks.json hinzufuegen (Regressions-Test)
  4. Memory: Feedback-Datei schreiben (alle Agents lernen daraus)
  5. Verifikation: node ~/bin/rudi-test.js ausfuehren

Deploy-Gate

Der /deploy Skill fuehrt vor jedem Deployment node ~/bin/rudi-test.js aus. Bei Fehlern wird das Deployment gestoppt.

Skills & Agents

TypNameBeschreibung
Skill/bugfixBug fixen + Test + Memory (Self-Improvement)
Skill/testTests manuell starten
Skill/deployDeployment mit Pflicht-Test-Gate
Skill/new-moduleNeues RUDI-Modul erstellen
Skill/qms-managementQMS-Verwaltung (IFS 2025)
Skill/energiePV, Speicher, BHKW
Skill/mib-auditMIB-Team starten (4 parallele Sicherheits-Agents)
Skill/system-auditEinzelner System-Audit (6 Bereiche, Score)
AgenttesterQA — Layout-Tests, API-Tests, Bug-Registrierung (Haiku)
Agentfrontend-devHTML/CSS/JS mit Apple Glasmorphism (Sonnet)
Agentbackend-devNode.js/Express API-Routen (Sonnet)
Agentchat-integratorClaude-Tools registrieren (Sonnet)
Agentqms-specialistIFS 2025, Dokumente, Gap-Analyse (Sonnet)
Agentpipeline-optimizerDokumenten-Pipeline QA (Sonnet)
MIBmib-securitySecurity-Audit: Auth, CSRF, CSP, Firewall (Opus)
MIBmib-backendBackend-Audit: Tools, Routes, Daten (Sonnet)
MIBmib-frontendFrontend-Audit: Chat, CDN, Auth-Guard (Sonnet)
MIBmib-dokuDoku-Audit: Memory, Rules, Agents (Haiku)

MIB-Team (Men in Black)

Automatisiertes Sicherheits- und Qualitaets-Audit durch 4 parallele Spezialisten-Agents.

AgentModellPruefbereich
mib-securityOpusAPI-Keys, Auth, CSRF, CSP, Path-Traversal, Uploads, Nginx, Firewall
mib-backendSonnetTool-Handler, Route-Konsistenz, Datenintegritaet, Server-Stabilitaet
mib-frontendSonnetChat-Panel, CDN-Violations, Auth-Guard, Viewport, Script-Reihenfolge
mib-dokuHaikuMemory-Links, Telegram-Reste, Agent-Definitionen, Rules, Doku

Manuell starten: Im Chat sagen: Lasse die Men in Black ausruecken oder /mib-audit

Automatisch: Jeden Sonntag um 03:00 UTC via Cron-Job (~/bin/mib-audit.sh)

Berichte: ~/rudi-chat/audit-log.json (Score-Historie mit Trend)

Score-Berechnung: Security × 0.35 + Backend × 0.25 + Frontend × 0.20 + Doku × 0.20

ScoreStatusAktion
9–10GruenKein Handlungsbedarf
7–8GelbVerbesserungen empfohlen
5–6OrangePrioritaer beheben
< 5RotSofort handeln

Hintergrund-Jobs (Cron)

Zeit (UTC)SkriptBeschreibung
Mo 06:00 (AKTIV seit 2026-04-28)~/bin/recall-drill.jsFSMA-204-Compliance-Recall-Drill: zufaellige Charge, Rueckverfolgung 1-Schritt-vor+zurueck, Score ≥ 0.70 = bestanden. Feature-Flag recall_drill_cron ON. Log: ~/backups/recall-drill.log. Cron: /etc/cron.d/recall-drill. CLI: --random | --charge <nr> | --we-id <id> | --json. Phase 7 aktiviert.
05:00 taeg.~/bin/zertifikat-erinnerung.jsLieferanten-Zertifikat-Ablauf-Erinnerung: prueft lieferant_zertifikat mit erinnerung_aktiv=1, legt Cockpit-Eintraege typ='zertifikat_ablauf' an. Log: ~/backups/zertifikat-erinnerung.log. Cron: /etc/cron.d/zertifikat-erinnerung. Phase 7.
02:45 taeg.~/bin/vision-backfill.jsVision-Backfill: 500 Bilder/Nacht aus wareneingang_bilder + reklamation_bilder, Tagesbudget 5 EUR Hardstop. Feature-Flag: vision_backfill_nightly. Log: ~/backups/vision-backfill.log. Cron: /etc/cron.d/vision-backfill.
So 03:00~/bin/mib-audit.shMIB-Security-Audit (4 Agents, Score-Bericht)
06:15 taeg.~/bin/rudi-test.jsMaster-Testrunner (API + Layout + Custom-Checks)
04:30/05:30~/bin/briefing-benjamin.jsTages-Briefing Mein RUDI PWA
jede Min.~/bin/routines-runner.jsMein-RUDI-Routinen-Runner
03:30 taeg.~/bin/memory-hygiene.jsMemory-Hygiene Mein RUDI
06:00 taeg.~/bin/bestand-alert.jsBestand-Alert (E-Mail bei Unterschreitung)
Mo-Fr 08:00~/bin/rek-erinnerung.jsReklamations-Erinnerung (offene Faelle)
Min 23 stl.~/bin/lern-ruecklauf.jsHFX360-Lern-Ruecklauf
03:45 taeg.~/bin/hfx360-stockitems-sync.jsHFX360 Stockitems-Sync
05:30 taeg.~/bin/lern-frageliste.jsHFX360 Lern-Frageliste
5 Min.~/bin/healthcheck-ping.shHealth-Ping (Resilience)
5 Min.~/bin/mcp-whitelist-update.shMCP-Whitelist-Update
15 Min.~/bin/cleanup-chrome.shChrome-Prozess-Cleanup
2-stl.~/bin/cloud-sync.shCloud-Sync DBs + Dateien (Resilience)
01:00 taeg.~/bin/backup-config.shConfig-Backup
04:00 taeg.~/bin/disk-cleanup.shTemp-Cleanup + Disk-Cleanup
05:30 taeg.~/bin/threat-intel.jsThreat-Intel-Check
03:00 taeg.~/bin/email-backup.jsE-Mail-Backup (rudi@ + qms@, Delta-Query)
So 21+22 UTC~/bin/weekly-meta-run.jsWoechentlicher Meta-Run Mein RUDI

Wichtige Dateien (Testing)

DateiBeschreibung
~/bin/layout-test.jsLayout- & Funktions-Tests (Puppeteer, 15 Seiten)
~/bin/rudi-test.jsMaster-Testrunner (Layout + API + Custom)
~/rudi-chat/test-checks.jsonCustom-Checks (waechst mit jedem /bugfix)
~/rudi-chat/test-results.jsonLetztes Test-Ergebnis (JSON)
~/layout-tests/Screenshots aller Seiten (Desktop + Mobile)
~/.claude/skills/bugfix/skill.mdBugfix-Skill Definition
~/.claude/skills/test/skill.mdTest-Skill Definition

Server-Setup

KomponenteDetail
HostingHostinger VPS (Ubuntu)
Domainrudi-regiofrucht.de
SSLLet's Encrypt (Auto-Renewal)
WebserverNginx (Reverse Proxy)
BackendNode.js + Express 5 (Port 3456, nur localhost)
Servicesystemd: rudi-chat.service
KIAnthropic Claude API (claude-opus-4-6)
TranskriptionWhisper (lokal, Modell: small, Deutsch)

Nginx-Konfiguration

Sicherheit

Sicherheitsmassnahmen

  • Pfad-Traversal-Schutz: path.resolve() + startsWith() auf allen Dateioperationen
  • Basic Auth: Alle Webseiten geschuetzt
  • Firewall: UFW deny-by-default, SSH + HTTPS offen, RDP nur von Heim-IP
  • fail2ban: SSH + Nginx-Auth + Bot-Schutz (3 Jails)
  • Node.js: Lauscht nur auf 127.0.0.1 (nicht extern erreichbar)
  • Secrets: In /etc/environment, nie in Dateien oder Chat

Versionierung & Rollback

Alle Code-Verzeichnisse sind mit Git versioniert. Vor jeder Aenderung wird committed – so kann jeder Stand wiederhergestellt werden.

Git-Repositories

RepoPfadInhalt
Backend~/rudi-chat/Server, Routes, Tools, Chat-Frontend
Frontend/var/www/html/Dashboard, Doku, System-Monitor
QMS/var/www/qms/QMS-Dashboard, Gap-Analyse

Die .gitignore schliesst automatisch aus: node_modules/, chat-history/, qms-annotations.json, qms-recurring.json, Backups und Logs.

Aenderungen sichern

# Status pruefen (welche Dateien geaendert?)
cd ~/rudi-chat && git status

# Aenderungen ansehen
git diff

# Commit erstellen (vor weiteren Aenderungen!)
git add -A && git commit -m "Beschreibung der Aenderung"

Rollback: Code zuruecksetzen

# Einzelne Datei zuruecksetzen
git checkout -- server.js

# ALLE Aenderungen verwerfen (zurueck zum letzten Commit)
git checkout .

# Zu einem bestimmten Commit zurueckspringen
git log --oneline          # Commits auflisten
git checkout abc1234 .     # Alles auf Stand abc1234 setzen

# Letzten Commit rueckgaengig machen (Aenderungen bleiben als unstaged)
git revert HEAD

Nginx-Backup

Nginx-Config ist kein Git-Repo (liegt unter /etc/). Dafuer gibt es ein Backup-Skript:

# Backup erstellen (vor Nginx-Aenderungen!)
~/bin/backup-nginx.sh "beschreibung"

# Backups auflisten
ls ~/backups/nginx/

# Zuruecksetzen
sudo cp ~/backups/nginx/nginx-XXXXXX.conf /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

Es werden automatisch die letzten 20 Backups behalten, aeltere werden geloescht.

System-Status pruefen

# Gesamtstatus: Git-Stand aller Repos + Services
~/bin/rudi-status.sh

Zeigt fuer jedes Repo den letzten Commit, ob ungesicherte Aenderungen vorliegen, Nginx-Backups und den Service-Status.

Workflow bei System-Aenderungen

  1. ~/bin/rudi-status.sh – Aktuellen Stand pruefen
  2. git add -A && git commit -m "..." – Sauberen Punkt setzen
  3. ~/bin/backup-nginx.sh "..." – Falls Nginx betroffen
  4. Aenderungen durchfuehren
  5. Testen (sudo nginx -t, node ~/bin/layout-test.js)
  6. Wenn OK: neuer Commit. Wenn nicht: git checkout .

Wartung

Service-Befehle

# Backend neustarten
sudo systemctl restart rudi-chat

# Logs anzeigen
sudo journalctl -u rudi-chat -f

# Nginx pruefen & laden
sudo nginx -t && sudo systemctl reload nginx

# Pipeline neustarten
sudo systemctl restart regio-pipeline
sudo journalctl -u regio-pipeline -f

# Layout-Tests
node ~/bin/layout-test.js
node ~/bin/layout-test.js --mobile
node ~/bin/layout-test.js --verbose

# Tree.json aktualisieren
bash ~/bin/generate-tree.sh

# System-Status (Git + Services)
~/bin/rudi-status.sh

# Nginx-Backup erstellen
~/bin/backup-nginx.sh "beschreibung"

Wichtige Dateien

DateiZweck
~/rudi-chat/qms-annotations.jsonQMS-Tasks und Notizen
~/rudi-chat/qms-recurring.jsonWiederkehrende Aufgaben
~/rudi-chat/chat-history/*.jsonChat-Verlaeufe
~/pipeline/pipeline.dbPipeline-Datenbank (SQLite)
~/pipeline/pipeline.pyPipeline-Hauptprozess (Watchdog)
~/dokumente/Dokumentenablage (Eingang, Verarbeitung, Archiv)
/var/www/dateien/tree.jsonDateibrowser-Baumstruktur
/etc/nginx/sites-enabled/defaultNginx-Konfiguration
/etc/environmentAPI-Keys und Tokens

RUDI v2.1 · Regio Frucht GmbH · Stand: 14. Maerz 2026
Erstellt mit Claude Code