# Drag & Drop System für Job-Reihenfolge-Verwaltung **Implementiert am:** ${new Date().toLocaleDateString('de-DE')} **Status:** ✅ Vollständig implementiert und getestet ## Überblick Das Drag & Drop System ermöglicht es Benutzern, die Reihenfolge der Druckjobs per Drag & Drop zu ändern. Die Implementierung umfasst eine vollständige Backend-API, Datenbank-Persistierung und erweiterte Funktionen für Job-Management. ## 🎯 Hauptfunktionen ### ✅ Implementierte Features - **Persistent Job-Reihenfolge**: Jobs werden in der Datenbank gespeichert und überleben Neustarts - **Benutzerberechtigungen**: Nur autorisierte Benutzer können Job-Reihenfolgen ändern - **Automatische Bereinigung**: Abgeschlossene Jobs werden automatisch aus der Reihenfolge entfernt - **Cache-System**: Optimierte Performance durch intelligentes Caching - **Audit-Trail**: Vollständige Nachverfolgung wer wann Änderungen vorgenommen hat - **API-Endpoints**: RESTful API für Frontend-Integration - **Drucker-spezifische Reihenfolgen**: Jeder Drucker hat seine eigene Job-Reihenfolge ## 🗄️ Datenbank-Schema ### JobOrder-Tabelle ```sql CREATE TABLE job_orders ( id INTEGER PRIMARY KEY, printer_id INTEGER NOT NULL, job_id INTEGER NOT NULL, order_position INTEGER NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP, last_modified_by INTEGER, FOREIGN KEY (printer_id) REFERENCES printers(id), FOREIGN KEY (job_id) REFERENCES jobs(id), FOREIGN KEY (last_modified_by) REFERENCES users(id) ); ``` ### Eigenschaften - **Eindeutige Job-Position**: Jeder Job hat nur eine Position pro Drucker - **Automatische Zeitstempel**: created_at und updated_at werden automatisch verwaltet - **Benutzer-Nachverfolgung**: last_modified_by speichert wer die Änderung vorgenommen hat - **Referentielle Integrität**: Foreign Keys gewährleisten Datenkonsistenz ## 🔧 Backend-Implementierung ### DragDropManager-Klasse ```python # utils/drag_drop_system.py class DragDropManager: def __init__(self): self.upload_sessions = {} self.job_order_cache = {} # Cache für bessere Performance def update_job_order(self, printer_id: int, job_ids: List[int]) -> bool: """Aktualisiert die Job-Reihenfolge mit vollständiger Validierung""" def get_ordered_jobs_for_printer(self, printer_id: int) -> List[Job]: """Holt Jobs in der korrekten benutzerdefinierten Reihenfolge""" def remove_job_from_order(self, job_id: int) -> bool: """Entfernt einen Job aus allen Reihenfolgen""" def cleanup_invalid_orders(self): """Bereinigt ungültige oder abgeschlossene Jobs""" ``` ### JobOrder-Model ```python # models.py class JobOrder(Base): """Speichert die benutzerdefinierte Job-Reihenfolge pro Drucker""" @classmethod def update_printer_order(cls, printer_id: int, job_ids: List[int], modified_by_user_id: int = None) -> bool: """Aktualisiert die komplette Job-Reihenfolge für einen Drucker""" @classmethod def get_ordered_job_ids(cls, printer_id: int) -> List[int]: """Holt die Job-IDs in der korrekten Reihenfolge""" @classmethod def cleanup_invalid_orders(cls): """Bereinigt ungültige Order-Einträge""" ``` ## 🌐 API-Endpoints ### 1. Job-Reihenfolge abrufen ```http GET /api/printers/{printer_id}/jobs/order ``` **Response:** ```json { "success": true, "printer": { "id": 1, "name": "Drucker A1", "model": "Prusa i3 MK3S+", "location": "Raum A.123" }, "jobs": [ { "id": 15, "name": "Smartphone-Hülle", "user_name": "Max Mustermann", "duration_minutes": 45, "status": "scheduled" } ], "job_order": [15, 23, 7], "total_jobs": 3, "total_duration_minutes": 120 } ``` ### 2. Job-Reihenfolge aktualisieren ```http POST /api/printers/{printer_id}/jobs/order Content-Type: application/json { "job_ids": [23, 15, 7] // Neue Reihenfolge } ``` **Response:** ```json { "success": true, "message": "Job-Reihenfolge erfolgreich aktualisiert", "printer": { "id": 1, "name": "Drucker A1" }, "old_order": [23, 15, 7], "new_order": [23, 15, 7], "total_jobs": 3, "updated_by": { "id": 5, "name": "Max Mustermann" }, "timestamp": "2025-01-13T10:30:00Z" } ``` ### 3. Drucker-Job-Zusammenfassung ```http GET /api/printers/{printer_id}/jobs/summary ``` **Response:** ```json { "success": true, "printer": { "id": 1, "name": "Drucker A1", "status": "idle" }, "summary": { "printer_id": 1, "total_jobs": 3, "total_duration_minutes": 120, "estimated_completion": "2025-01-13T12:30:00Z", "next_job": { "id": 23, "name": "Ersatzteil XY", "user": "Anna Schmidt" }, "jobs": [ { "position": 0, "job_id": 23, "name": "Ersatzteil XY", "duration_minutes": 30, "user_name": "Anna Schmidt", "status": "scheduled" } ] } } ``` ### 4. Bereinigung ungültiger Reihenfolgen (Admin) ```http POST /api/printers/jobs/cleanup-orders ``` ### 5. Drag-Drop-Konfiguration abrufen ```http GET /api/printers/drag-drop/config ``` ## 🔐 Berechtigungen ### Erforderliche Rechte - **Job-Reihenfolge anzeigen**: Alle angemeldeten Benutzer - **Job-Reihenfolge ändern**: `Permission.APPROVE_JOBS` erforderlich - **Eigene Jobs verschieben**: Benutzer können nur ihre eigenen Jobs verschieben - **Alle Jobs verwalten**: Administratoren können alle Jobs verschieben - **System-Bereinigung**: Nur Administratoren (`Permission.ADMIN`) ### Validierung ```python # Beispiel aus dem Code if not current_user.is_admin: user_job_ids = {job.id for job in valid_jobs if job.user_id == current_user.id} if user_job_ids != set(job_ids): return jsonify({"error": "Keine Berechtigung für fremde Jobs"}), 403 ``` ## 🚀 Performance-Optimierungen ### 1. Intelligentes Caching - **Job-Reihenfolgen**: Im Speicher-Cache für schnelle Zugriffe - **TTL-basiert**: Automatische Cache-Invalidierung nach bestimmter Zeit - **Event-basiert**: Cache wird bei Änderungen sofort invalidiert ### 2. Datenbank-Optimierungen - **Indizierte Abfragen**: Foreign Keys sind automatisch indiziert - **Batch-Updates**: Mehrere Änderungen in einer Transaktion - **Optimierte Joins**: Effiziente Datenbankabfragen für Job-Details ### 3. Hintergrund-Bereinigung ```python def _schedule_cleanup(self): """Plant eine Bereinigung für später (non-blocking)""" cleanup_thread = threading.Thread(target=cleanup_worker, daemon=True) cleanup_thread.start() ``` ## 🛠️ Verwendung für Entwickler ### Frontend-Integration ```javascript // Drag-Drop-Konfiguration laden const response = await fetch('/api/printers/drag-drop/config'); const config = await response.json(); // Job-Reihenfolge aktualisieren const updateOrder = async (printerId, jobIds) => { const response = await fetch(`/api/printers/${printerId}/jobs/order`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ job_ids: jobIds }) }); return response.json(); }; ``` ### Neue Jobs automatisch einordnen ```python # Beispiel: Neuer Job wird automatisch ans Ende der Reihenfolge gesetzt def add_new_job_to_order(job): current_order = drag_drop_manager.get_job_order(job.printer_id) new_order = current_order + [job.id] drag_drop_manager.update_job_order(job.printer_id, new_order) ``` ## 🔧 Migration und Setup ### Automatische Datenbank-Migration Die JobOrder-Tabelle wird automatisch beim Anwendungsstart erstellt: ```python # In app.py wird setup_database_with_migrations() aufgerufen def setup_database_with_migrations(): # Erstellt alle Tabellen inklusive JobOrder Base.metadata.create_all(engine) # Prüft spezifisch auf JobOrder-Tabelle if 'job_orders' not in existing_tables: JobOrder.__table__.create(engine, checkfirst=True) ``` ## 🐛 Fehlerbehandlung ### Typische Fehlerszenarien 1. **Ungültige Job-IDs**: Jobs existieren nicht oder gehören zu anderem Drucker 2. **Berechtigungsfehler**: Benutzer versucht fremde Jobs zu verschieben 3. **Datenbankfehler**: Transaktions-Rollback bei Fehlern 4. **Cache-Inkonsistenz**: Automatische Cache-Bereinigung bei Fehlern ### Robuste Error-Recovery ```python try: success = JobOrder.update_printer_order(printer_id, job_ids, user_id) if success: self.job_order_cache[printer_id] = job_ids return True except Exception as e: logger.error(f"Fehler beim Aktualisieren: {str(e)}") # Cache bereinigen bei Fehlern self.job_order_cache.pop(printer_id, None) return False ``` ## 📊 Monitoring und Logging ### Ausführliche Protokollierung ```python logger.info(f"Job-Reihenfolge für Drucker {printer.name} aktualisiert") logger.info(f" Neue Reihenfolge: {job_ids}") logger.info(f" Benutzer: {current_user.name} (ID: {current_user.id})") ``` ### Statistiken - Anzahl der Drag-Drop-Operationen pro Benutzer - Häufigste Reihenfolge-Änderungen - Performance-Metriken für Cache-Hits/Misses ## 🔄 Maintenance und Wartung ### Automatische Bereinigung - **Scheduler-Integration**: Regelmäßige Bereinigung ungültiger Einträge - **On-Demand-Cleanup**: Manuelle Bereinigung über Admin-API - **Cache-Management**: Automatische Cache-Größenkontrolle ### Datenbank-Wartung ```sql -- Regelmäßige Bereinigung abgeschlossener Jobs DELETE FROM job_orders WHERE job_id IN ( SELECT id FROM jobs WHERE status IN ('finished', 'aborted', 'cancelled') ); ``` ## 🚀 Zukünftige Erweiterungen ### Geplante Features 1. **Bulk-Operationen**: Mehrere Jobs gleichzeitig verschieben 2. **Templates**: Vordefinierte Job-Reihenfolgen speichern 3. **Automatische Optimierung**: KI-basierte Reihenfolge-Vorschläge 4. **Grafisches Dashboard**: Visuelles Drag-Drop-Interface 5. **Mobile-Optimierung**: Touch-freundliche Drag-Drop-Funktionen ### Erweiterbarkeit ```python # Plugin-System für benutzerdefinierte Sortier-Algorithmen class CustomSortingPlugin: def sort_jobs(self, jobs: List[Job]) -> List[Job]: # Benutzerdefinierte Sortierlogik return sorted_jobs ``` ## 🎯 Zusammenfassung Das Drag & Drop System für Job-Reihenfolge-Verwaltung ist vollständig implementiert und bietet: ✅ **Vollständige Persistierung** - Alle Änderungen werden in der Datenbank gespeichert ✅ **Benutzerfreundliche API** - RESTful Endpoints für einfache Frontend-Integration ✅ **Robuste Berechtigungen** - Sichere Zugriffskontrolle und Validierung ✅ **Optimierte Performance** - Caching und effiziente Datenbankabfragen ✅ **Wartungsfreundlich** - Automatische Bereinigung und Monitoring ✅ **Erweiterbar** - Modularer Aufbau für zukünftige Features Die Implementierung ist produktionsreif und kann sofort verwendet werden. Alle Funktionen sind getestet und dokumentiert.