Files
Projektarbeit-MYP/.cursorrules

677 lines
19 KiB
Plaintext

---
description: "Formale Projektrichtlinien für das Mercedes-Benz 3D-Druck-Management-System mit Fokus auf Codequalität, deutscher Dokumentation und hardwareoptimierter Implementierung"
globs: ["*.py", "*.html", "*.js", "*.sql", "*.md"]
alwaysApply: true
---
# MYP Druckerverwaltungssystem - Cursor Rules
# Mercedes-Benz 3D-Druck-Management-Platform
## 🎯 PROJEKT-KONTEXT
Das MYP-System ist eine cyber-physische Lösung zur Verwaltung von 3D-Druckern mit Smart-Plug-Technologie für Mercedes-Benz.
**Technischer Stack:**
- Backend: Flask + SQLAlchemy + SQLite
- Frontend: Jinja2-Templates + CSS/JS
- Hardware: Raspberry Pi + TP-Link Tapo P110
- Deployment: Air-Gapped Production Environment
## 🔑 KERN-PRINZIPIEN
### SPRACHE & DOKUMENTATION
- **Ausschließlich formales Deutsch** für alle Kommentare, Docstrings, UI-Texte und Dokumentation
- **Englisch nur für**: Code-Variablen, Funktionsnamen, Git-Commits
- Umfassende Docstrings nach deutschem Standard
- Inline-Kommentare für komplexe Logik
### QUALITÄTS-STANDARD
- **Produktionsreife** bei jedem Commit - keine experimentellen Features ohne vollständige Tests
- **Zero-Downtime-Code** - jede Änderung muss sofort funktionsfähig sein
- **Defense Programming** - umfassende Error-Handling und Validation
- **Performance-optimiert** für Raspberry Pi Hardware-Umgebung
### CASCADE-ANALYSE PROTOKOLL
Vor jeder Änderung ZWINGEND analysieren:
```python
# IMPACT-ANALYSE-TEMPLATE:
# 1. Betroffene Module: [Liste]
# 2. API-Endpunkte: [Liste]
# 3. Datenbank-Schema: [Änderungen]
# 4. Frontend-Komponenten: [Liste]
# 5. Hardware-Integration: [Tapo/Drucker]
# 6. Session/Auth: [Auswirkungen]
# 7. Background-Jobs: [Timer/Scheduler]
```
## 📁 PROJEKTSTRUKTUR-REGELN
### CORE-DATEIEN (NIEMALS OHNE CASCADE-ANALYSE ÄNDERN)
- `backend/app.py` - Flask-Haupteinstiegspunkt
- `backend/models.py` - SQLAlchemy-Datenmodelle
- `backend/utils/settings.py` - Zentrale Konfiguration
- `backend/blueprints/` - REST-API-Endpunkte
### DATEI-ORGANISIERUNG
- **Markdown-Dateien (.md)**: Automatisch in `docs/` speichern (außer README.md)
- **Upload-Struktur**: Hierarchisch nach Jahr/Monat
- **Logs**: Strukturiert nach Modulen in `backend/logs/`
- **Backups**: Automatisch in `database/backups/`
### KEINE WINDOWS-SPEZIFISCHEN DATEIEN
- Keine .bat, .ps1, .cmd Dateien
- Keine Windows-Registry-Zugriffe
- Linux/Unix-Shell-Scripts bevorzugen
- Cross-platform Python-Lösungen
## 🏗️ BACKEND-ENTWICKLUNG (FLASK)
### BLUEPRINT-STRUKTUR
```python
# Standard Blueprint-Template
from flask import Blueprint, request, jsonify, session
from backend.models import db, User, Printer, Job
from backend.utils.permissions import require_role
from backend.utils.logging_config import get_logger
# Deutsche Kommentare für Business-Logic
blueprint_name = Blueprint('name', __name__)
logger = get_logger(__name__)
@blueprint_name.route('/endpoint', methods=['POST'])
@require_role('admin') # Berechtigungsprüfung
def function_name():
"""
Funktion-Beschreibung auf Deutsch.
Returns:
dict: Antwort-Struktur mit Status und Daten
"""
try:
# Geschäftslogik mit deutschen Kommentaren
pass
except Exception as e:
logger.error(f"Fehler in {function_name.__name__}: {str(e)}")
return jsonify({'error': 'Detaillierte deutsche Fehlermeldung'}), 500
```
### DATENBANK-PATTERNS
```python
# SQLAlchemy-Modell-Standard
class ModelName(db.Model):
"""Deutsche Modell-Beschreibung."""
__tablename__ = 'table_name'
# Felder mit deutschen Kommentaren
id = db.Column(db.Integer, primary_key=True)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
"""Konvertierung zu Dictionary für JSON-Serialisierung."""
return {
'id': self.id,
'created_at': self.created_at.isoformat() if self.created_at else None
}
@classmethod
def create_with_validation(cls, **kwargs):
"""Factory-Methode mit Validierung."""
# Validierungslogik
pass
```
### HARDWARE-INTEGRATION (TAPO)
```python
# Tapo-Controller-Pattern
from backend.utils.tapo_controller import TapoController
async def control_printer_power(printer_id: int, action: str):
"""
Steuerung der Drucker-Stromversorgung über Smart-Plug.
Args:
printer_id: Eindeutige Drucker-ID
action: 'on', 'off', 'status'
Returns:
dict: Status und Ergebnis der Operation
"""
try:
controller = TapoController()
result = await controller.execute_action(printer_id, action)
# Logging für Hardware-Operationen
logger.info(f"Drucker {printer_id}: {action} - Status: {result}")
return {'success': True, 'data': result}
except Exception as e:
logger.error(f"Tapo-Steuerung fehlgeschlagen: {str(e)}")
return {'success': False, 'error': str(e)}
```
## 🎨 FRONTEND-ENTWICKLUNG (JINJA2)
### TEMPLATE-STRUKTUR
```html
<!-- Standard Template-Header -->
{% extends "base.html" %}
{% set page_title = "Deutsche Seitentitel" %}
{% set page_description = "Deutsche Beschreibung" %}
{% block content %}
<div class="container-fluid">
<!-- Deutsche UI-Texte -->
<h1>{{ page_title }}</h1>
<!-- Form-Validation mit deutschen Meldungen -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
<div class="alert alert-{{ 'danger' if category == 'error' else category }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% endwith %}
</div>
{% endblock %}
{% block scripts %}
<script>
// Deutsche JavaScript-Kommentare für UI-Logik
document.addEventListener('DOMContentLoaded', function() {
// Initialisierung mit Error-Handling
});
</script>
{% endblock %}
```
### CSS/STYLING-REGELN
- **Mercedes-Designsprache** befolgen
- **Responsive Design** für Touch-Interfaces (Kiosk-Modus)
- **Accessibility** (WCAG 2.1 AA)
- **Performance** für Raspberry Pi optimiert
## 🔧 UTILITY-ENTWICKLUNG
### LOGGING-STANDARD
```python
from backend.utils.logging_config import get_logger
logger = get_logger(__name__)
def business_function():
"""Deutsche Funktionsbeschreibung."""
logger.info("Vorgang gestartet: {function_name}")
try:
# Geschäftslogik
logger.debug("Zwischenschritt erfolgreich")
except ValidationError as e:
logger.warning(f"Validierungsfehler: {str(e)}")
raise
except Exception as e:
logger.error(f"Unerwarteter Fehler in {function_name}: {str(e)}")
# Error-Recovery-Logik
raise
finally:
logger.info("Vorgang abgeschlossen: {function_name}")
```
### PERMISSION-SYSTEM
```python
from functools import wraps
from flask import session, abort
def require_role(required_role: str):
"""Decorator für rollenbasierte Zugriffskontrolle."""
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if 'user_id' not in session:
abort(401) # Nicht authentifiziert
user = User.query.get(session['user_id'])
if not user or user.role != required_role:
logger.warning(f"Unauthorisierter Zugriff: {session.get('username', 'Unknown')} -> {f.__name__}")
abort(403) # Nicht autorisiert
return f(*args, **kwargs)
return decorated_function
return decorator
```
## 📊 DATENBANK-STANDARDS
### MIGRATION-PATTERN
```python
# Sichere Schema-Änderungen
def upgrade_database():
"""Database-Schema-Upgrade mit Backup."""
try:
# 1. Backup erstellen
backup_manager.create_backup()
# 2. Schema-Änderungen
db.engine.execute("ALTER TABLE...")
# 3. Daten-Migration
migrate_existing_data()
# 4. Validierung
validate_schema_integrity()
logger.info("Database-Upgrade erfolgreich")
except Exception as e:
logger.error(f"Database-Upgrade fehlgeschlagen: {str(e)}")
# Rollback-Mechanismus
backup_manager.restore_latest()
raise
```
### CONNECTION-MANAGEMENT
```python
# SQLite-optimiert für Air-Gapped-Umgebung
def get_db_connection():
"""Thread-safe Database-Connection mit Connection-Pooling."""
return db.engine.connect()
@contextmanager
def transaction_scope():
"""Transaction-Manager mit automatischem Rollback."""
connection = get_db_connection()
trans = connection.begin()
try:
yield connection
trans.commit()
except Exception:
trans.rollback()
raise
finally:
connection.close()
```
## 🚀 DEPLOYMENT & PRODUCTION
### SYSTEMD-SERVICE-PATTERN
```ini
# Produktions-Service-Template
[Unit]
Description=MYP Druckerverwaltungssystem
After=network.target
[Service]
Type=notify
User=myp
Group=myp
WorkingDirectory=/opt/myp
Environment=FLASK_ENV=production
ExecStart=/opt/myp/venv/bin/python app.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
```
### KIOSK-MODUS-SETUP
```bash
#!/bin/bash
# Raspberry Pi Kiosk-Setup
# Deutsche Kommentare für Setup-Scripts
# Display-Konfiguration für Touch-Interface
export DISPLAY=:0
xset s off
xset -dpms
xset s noblank
# Browser-Start mit MYP-Interface
chromium-browser \
--kiosk \
--disable-infobars \
--disable-session-crashed-bubble \
https://localhost/kiosk
```
## 🧪 TESTING-STANDARDS
### UNIT-TEST-TEMPLATE
```python
import pytest
from backend.app import create_app
from backend.models import db, User, Printer
class TestDruckerVerwaltung:
"""Test-Suite für Drucker-Management-Funktionen."""
def setup_method(self):
"""Test-Environment-Setup."""
self.app = create_app('testing')
self.client = self.app.test_client()
with self.app.app_context():
db.create_all()
self.create_test_data()
def test_drucker_erstellen(self):
"""Test: Neuen Drucker erfolgreich erstellen."""
# Given: Test-Daten
drucker_daten = {
'name': 'Test-Drucker-001',
'standort': 'Berlin-Marienfelde',
'tapo_ip': '192.168.1.100'
}
# When: API-Aufruf
response = self.client.post('/api/printers', json=drucker_daten)
# Then: Erfolgreiche Erstellung
assert response.status_code == 201
assert 'id' in response.json
def teardown_method(self):
"""Test-Environment-Cleanup."""
with self.app.app_context():
db.drop_all()
```
## 🔒 SECURITY-REQUIREMENTS
### AUTHENTICATION-FLOW
```python
# Sichere Session-Verwaltung
@auth_bp.route('/login', methods=['POST'])
def login():
"""Benutzer-Authentifizierung mit Rate-Limiting."""
# Rate-Limiting für Brute-Force-Schutz
if not rate_limiter.check_limit(request.remote_addr):
logger.warning(f"Rate-Limit erreicht: {request.remote_addr}")
return jsonify({'error': 'Zu viele Anmeldeversuche'}), 429
# Credential-Validierung
username = request.json.get('username')
password = request.json.get('password')
user = User.authenticate(username, password)
if not user:
logger.warning(f"Fehlgeschlagene Anmeldung: {username}")
return jsonify({'error': 'Ungültige Anmeldedaten'}), 401
# Session-Erstellung mit CSRF-Token
session['user_id'] = user.id
session['csrf_token'] = generate_csrf_token()
logger.info(f"Erfolgreiche Anmeldung: {username}")
return jsonify({'success': True, 'user': user.to_dict()})
```
### INPUT-VALIDATION
```python
from marshmallow import Schema, fields, validate
class DruckerCreateSchema(Schema):
"""Validierungsschema für Drucker-Erstellung."""
name = fields.Str(required=True, validate=validate.Length(min=3, max=50))
standort = fields.Str(required=True, validate=validate.Length(min=5, max=100))
tapo_ip = fields.IP(required=True)
beschreibung = fields.Str(validate=validate.Length(max=500))
def validate_drucker_data(data):
"""Zentrale Validierung für Drucker-Daten."""
schema = DruckerCreateSchema()
errors = schema.validate(data)
if errors:
logger.warning(f"Validierungsfehler: {errors}")
raise ValidationError(errors)
return schema.load(data)
```
## ⚡ PERFORMANCE-OPTIMIERUNG
### DATABASE-QUERIES
```python
# Optimierte Queries für Raspberry Pi
def get_active_jobs_optimized():
"""Performance-optimierte Abfrage aktiver Jobs."""
return db.session.query(Job)\
.options(joinedload(Job.printer))\
.options(joinedload(Job.user))\
.filter(Job.status.in_(['running', 'scheduled']))\
.order_by(Job.start_time.asc())\
.limit(50)\
.all()
# Caching für häufige Abfragen
from functools import lru_cache
@lru_cache(maxsize=128)
def get_drucker_statistics(drucker_id: int):
"""Gecachte Drucker-Statistiken."""
return db.session.query(Job)\
.filter(Job.printer_id == drucker_id)\
.filter(Job.status == 'completed')\
.count()
```
### FRONTEND-PERFORMANCE
```javascript
// Optimiertes JavaScript für Touch-Interface
class MYPDashboard {
constructor() {
this.updateInterval = 30000; // 30 Sekunden
this.maxRetries = 3;
this.retryCount = 0;
this.initializeEventListeners();
this.startAutoUpdate();
}
async updateDashboard() {
try {
const response = await fetch('/api/dashboard-data');
const data = await response.json();
this.renderDashboardData(data);
this.retryCount = 0; // Reset bei Erfolg
} catch (error) {
console.error('Dashboard-Update fehlgeschlagen:', error);
this.handleUpdateError();
}
}
handleUpdateError() {
this.retryCount++;
if (this.retryCount < this.maxRetries) {
// Exponential Backoff
setTimeout(() => this.updateDashboard(),
Math.pow(2, this.retryCount) * 1000);
} else {
this.showOfflineMode();
}
}
}
```
## 📝 DOKUMENTATIONS-STANDARD
### FUNCTION-DOCSTRINGS
```python
def schedule_print_job(drucker_id: int, start_time: datetime,
duration_minutes: int, user_id: int) -> Dict[str, Any]:
"""
Planen eines Druckauftrags mit automatischer Smart-Plug-Steuerung.
Diese Funktion erstellt einen neuen Druckauftrag und konfiguriert
die automatische Ein-/Ausschaltung des zugeordneten Druckers über
das Tapo-Smart-Plug-System.
Args:
drucker_id: Eindeutige ID des Zieldruckers
start_time: Geplanter Start des Druckauftrags (UTC)
duration_minutes: Geschätzte Druckdauer in Minuten
user_id: ID des anfragenden Benutzers
Returns:
dict: Enthält Job-ID, Status und Scheduler-Informationen
{
'job_id': int,
'status': str,
'scheduled_power_on': datetime,
'scheduled_power_off': datetime,
'tapo_status': str
}
Raises:
ValidationError: Bei ungültigen Eingabedaten
ConflictError: Bei Zeitkonflikten mit anderen Jobs
HardwareError: Bei Tapo-Kommunikationsfehlern
Example:
>>> result = schedule_print_job(
... drucker_id=1,
... start_time=datetime(2025, 1, 15, 14, 0),
... duration_minutes=120,
... user_id=42
... )
>>> print(result['job_id'])
157
"""
```
## 🚨 ERROR-HANDLING-STANDARD
### EXCEPTION-HIERARCHY
```python
# Projekt-spezifische Exception-Klassen
class MYPBaseException(Exception):
"""Basis-Exception für MYP-System."""
def __init__(self, message: str, error_code: str = None):
self.message = message
self.error_code = error_code
super().__init__(self.message)
class HardwareError(MYPBaseException):
"""Fehler bei Hardware-Kommunikation (Tapo, Drucker)."""
pass
class SchedulingConflictError(MYPBaseException):
"""Zeitkonflikt bei Job-Planung."""
pass
class ValidationError(MYPBaseException):
"""Eingabe-Validierungsfehler."""
pass
# Global Error Handler
@app.errorhandler(Exception)
def handle_global_exception(error):
"""Globaler Exception-Handler mit Logging."""
logger.error(f"Unbehandelte Exception: {str(error)}", exc_info=True)
if isinstance(error, MYPBaseException):
return jsonify({
'error': error.message,
'error_code': error.error_code
}), 400
# Generischer Server-Fehler
return jsonify({
'error': 'Ein unerwarteter Fehler ist aufgetreten.',
'error_code': 'INTERNAL_ERROR'
}), 500
```
## 🔄 SELF-VERIFICATION-CHECKLIST
Nach jeder größeren Änderung ZWINGEND prüfen:
### ✅ FUNKTIONALE KORREKTHEIT
- [ ] Alle API-Endpunkte reagieren korrekt
- [ ] Datenbank-Operationen funktionieren
- [ ] Frontend lädt ohne JavaScript-Fehler
- [ ] Hardware-Integration (Tapo) erreichbar
### ✅ STRUKTURELLE INTEGRITÄT
- [ ] Imports funktionieren in allen Modulen
- [ ] Keine zirkulären Dependencies
- [ ] Database-Schema konsistent
- [ ] Session-Management intakt
### ✅ VOLLSTÄNDIGE DOKUMENTATION
- [ ] Deutsche Docstrings für neue Funktionen
- [ ] Inline-Kommentare für komplexe Logik
- [ ] API-Dokumentation aktualisiert
- [ ] Changelog-Einträge
### ✅ CASCADE-KONSISTENZ
- [ ] Alle abhängigen Module getestet
- [ ] Berechtigungen weiterhin gültig
- [ ] Logging funktioniert in allen Bereichen
- [ ] Error-Handling vollständig
## 🎯 ZUSÄTZLICHE REGELN
### GIT-WORKFLOW
- **Commit-Messages**: Englisch, aussagekräftig
- **Branch-Naming**: `feature/deutsche-beschreibung`, `bugfix/issue-nummer`
- **Pull-Requests**: Mit deutscher Beschreibung und Impact-Analyse
### CODE-REVIEW-KRITERIEN
- Deutsche Kommentare und Dokumentation
- Performance-Impact für Raspberry Pi
- Security-Implications
- Hardware-Integration-Auswirkungen
- Offline-Funktionalität erhalten
### EMERGENCY-PROCEDURES
```python
# Notfall-Shutdown-Prozedur
def emergency_shutdown():
"""Kontrolliertes System-Shutdown bei kritischen Fehlern."""
logger.critical("NOTFALL-SHUTDOWN initiiert")
# 1. Alle aktiven Jobs sicher beenden
active_jobs = Job.query.filter(Job.status == 'running').all()
for job in active_jobs:
job.force_complete_with_reason("Notfall-Shutdown")
# 2. Smart-Plugs ausschalten
tapo_controller.emergency_power_off_all()
# 3. Database-Backup erstellen
backup_manager.create_emergency_backup()
# 4. System-Status auf Wartung setzen
system_status.set_maintenance_mode(True)
logger.critical("NOTFALL-SHUTDOWN abgeschlossen")
```
---
## 🏆 QUALITÄTSZIELE
**Code-Qualität**: Produktionsreif, keine Experimente
**Performance**: Optimiert für Raspberry Pi 4
**Reliability**: 99.9% Uptime in Air-Gapped-Umgebung
**Security**: Keine Schwachstellen, umfassende Validierung
**Maintainability**: Selbstdokumentierend, modular aufgebaut
**User Experience**: Intuitive deutsche Benutzerführung
---
**Version**: 1.0.0
**Gültig für**: MYP Druckerverwaltungssystem v2.0+
**Letzte Aktualisierung**: $(date +%Y-%m-%d)
**Entwicklungsstandard**: IHK-Projektarbeit Mercedes-Benz