Files
HartOMat/LEARNINGS.md
T
Hartmut bf0c55c970 docs: Phasen B-E abgeschlossen — PLAN.md + LEARNINGS.md aktualisiert
PLAN.md: Phasen A-E als  ABGESCHLOSSEN markiert, Status auf Phase F.
LEARNINGS.md: 4 neue Learnings:
- Bash CWD-Problem durch Hook-Pfad-Auflösung (Symlink-Fix)
- PostgreSQL RLS current_setting Null-Safety + Admin-Bypass-Pattern
- Domain-Migration mit Compat-Shims (Big-Bang vermeiden)
- Celery Canvas vs. Custom Workflow-Engine

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 17:14:43 +01:00

12 KiB

Projekt-Learnings — Schaeffler Automat

Format

Datum | Kategorie | Problem → Lösung


Learnings

2026-01-15 | Architektur | Backend-Port-Konflikt

Problem: FastAPI standardmäßig auf Port 8000 — war auf dem Entwicklungsrechner belegt Lösung: Port 8888 in docker-compose.yml und Vite-Proxy konfiguriert Für künftige Projekte: Port früh festlegen und in CLAUDE.md dokumentieren


2026-01-20 | Datenbank | SQLAlchemy trackt key-value-Store-Mutations nicht

Problem: Admin-Einstellungen (system_settings) wurden via ORM gespeichert, Änderungen wurden nicht persistiert Ursache: SQLAlchemy erkennt keine Mutation an einem bereits geladenen Objekt wenn nur ein Value-Feld geändert wird Lösung: Direktes SQL UPDATE via op.execute() statt ORM-Mutation in admin.py Für künftige Projekte: Key-Value-Stores immer mit direktem SQL oder session.execute(update(...)) verwalten


2026-01-25 | Render-Pipeline | Blender ignoriert STEP-Einheiten (mm vs. m)

Problem: STEP-Dateien sind in Millimetern, Blender arbeitet intern in Metern → 50mm-Lager erscheint 50 Meter breit, Kamera framt falsch Lösung: _scale_mm_to_m(parts) Helper in allen 3 Render-Scripts: part.scale = (0.001, 0.001, 0.001), Transform anwenden Betroffene Dateien: blender_render.py, still_render.py, turntable_render.py Für künftige Projekte: Einheiten-Konvertierung direkt nach STL-Import, vor jeder Kamera-Kalkulation


2026-01-28 | Render-Pipeline | Blender 5.0 hat scene.node_tree entfernt

Problem: _setup_bg_compositor() rief scene.node_tree auf (in Blender 5.0 entfernt) → Python-Exception → Blender exitete mit Code 0 → Flamenco markierte Task fälschlicherweise als "completed" Lösung: _setup_bg_compositor() aus Setup + Render-Script entfernt; bg_color-Kompositing in FFmpeg verschoben (-f lavfi -i color=... + overlay-Filter) Wichtig: Immer try: main() except SystemExit: raise except Exception: traceback; sys.exit(1) in Blender-Scripts — sonst verschluckt Blender Python-Exceptions Für künftige Projekte: Nach Blender-Major-Updates alle API-Calls prüfen; Exception-Guard ist Pflicht


2026-02-05 | Material-System | Material-Alias-Lookup-Reihenfolge falsch

Problem: Steel--Stahl war sowohl ein kanonischer Material.name als auch ein Alias für SCHAEFFLER_010101_Steel-Bare. Der Lookup prüfte zuerst den exakten Namen und fand Steel--Stahl — Blender konnte diesen Namen aber nicht in der Library finden Lösung: Lookup-Reihenfolge in material_service.py umgekehrt: Aliases zuerst, dann exakter Name, dann Pass-through Für künftige Projekte: Alias-System immer so designen dass Aliases Vorrang haben; nie zwei Lookup-Pfade mit überlappenden Treffern


2026-02-10 | Render-Pipeline | Blender-Template zerstört HDRI/World

Problem: Im Template-Modus (Mode B) wurden trotzdem Auto-Lights und eine neue World erstellt → überschrieb den HDRI aus dem .blend-Template → falsche Beleuchtung Ursache: Auto-Licht- und World-Setup-Code lief bedingungslos, nicht nur im Mode A Lösung: In Template-Mode werden Lights, World und Color-Management-Override vollständig übersprungen; nur die Kamera wird ggf. neu berechnet Betroffene Dateien: still_render.py, turntable_render.py, schaeffler-still.js, schaeffler-turntable.js


2026-02-15 | Celery | Blender-Queue-Flooding durch falsche Concurrency

Problem: Alle Celery-Tasks (schnelle Metadata-Extraktion + langsamer Blender-Render) liefen auf step_processing mit concurrency=8 → 8 Workers schickten gleichzeitig Requests an blender-renderer (der nur 1 gleichzeitig verarbeiten kann) → 7 davon liefen in 300s-Timeout → blockierte die gesamte Queue Lösung: Pipeline aufgeteilt:

  • process_step_file (step_processing, concurrency=8): nur schnelle Metadata-Extraktion (<2s), queut dann →
  • render_step_thumbnail (thumbnail_rendering, concurrency=1): Blender-Call, niemals timeout Neuer Service: worker-thumbnail in docker-compose.yml mit --concurrency=1 Für künftige Projekte: HTTP-Services die nur 1 Request gleichzeitig verarbeiten können IMMER auf einer separaten Queue mit concurrency=1 laufen lassen

2026-02-18 | Frontend | Tailwind CSS-Variablen inkompatibel mit opacity-Syntax

Problem: bg-surface/50 oder bg-surface (wenn --color-bg-surface ein Hex-Wert ist) generiert rgb(var(--color-bg-surface) / 0.5) — invalides CSS, weil rgb() keine Hex-Werte als Channel-Input akzeptiert → Hintergrund transparent Ursache: Tailwind erwartet CSS-Variablen mit RGB-Channel-Format (255 255 255), nicht Hex (#ffffff) Lösung: Inline-Style verwenden: style={{ backgroundColor: 'var(--color-bg-surface)' }} Für künftige Projekte: Entweder CSS-Variablen im RGB-Channel-Format definieren, oder konsequent inline styles für variable Farben


2026-02-20 | STL-Cache | Three.js-Renderer nutzte tempfile → kein Download möglich

Problem: Three.js-Renderer konvertierte STEP→STL in ein tempfile und löschte es anschließend → STL-Download-Endpoint fand keine Datei Ursache: Three.js war ursprünglich nur für Thumbnails gebaut, STL-Cache-Konvention ({stem}_low.stl neben STEP-Datei) wurde nicht implementiert Lösung: Persistent cache path: step_path.parent / f"{step_path.stem}_low.stl", cache-hit-check vor Konvertierung, kein unlink() mehr Für künftige Projekte: STL-Cache-Konvention ({step_stem}_{quality}.stl neben STEP-Datei) von Anfang an in allen Renderer-Services einhalten


2026-02-20 | STL-Cache | blender-renderer fehlte /convert-stl Endpoint

Problem: Für Produkte die mit Blender gerendert wurden war kein STL-Cache vorhanden wenn nicht explizit gerendert wurde (blender-renderer renderte + konvertierte in einem Schritt, aber STL wurde nicht persistiert) Lösung: Neuer /convert-stl Endpoint in blender-renderer/app.py: konvertiert STEP→STL ohne Render, persistiert Cache. Neuer Celery-Task generate_stl_cache auf thumbnail_rendering-Queue. Admin-Funktion "Generate Missing STLs" zum Batch-Nachfüllen


2026-02-22 | Material-System | Fehlender Alias blockiert Material-Replacement

Problem: Produkt F-803422.01.TR2 (SA-2026-00080) renderte ohne Materialersetzung. Material "Stahl v2" war korrekt in der UI gespeichert, aber weder in materials noch in material_aliases vorhanden Ursache: Alias-Seeding aus Excel deckte nicht alle Varianten der deutschen Materialbezeichnungen ab Lösung: Alias direkt in DB eingetragen: "Stahl v2"SCHAEFFLER_010101_Steel-Bare Für künftige Projekte: Bei Render ohne Materialersetzung immer zuerst resolve_material_map() debuggen und Alias-Tabelle prüfen; Alias-Seeding regelmäßig mit neuen Excel-Varianten erweitern


2026-02-25 | Frontend | canDispatch-Bedingung zu restriktiv

Problem: "Dispatch Renders"-Button war nicht sichtbar obwohl der Auftrag offene Render-Zeilen hatte Ursache: canDispatch enthielt && hasRetryable — Button erschien nur wenn pending/failed/cancelled-Zeilen vorhanden waren, nicht wenn alle Zeilen "pending" im Erstauftrag Lösung: hasRetryable-Bedingung entfernt; Button ist immer sichtbar wenn Auftrag im richtigen Status und User privilegiert ist Für künftige Projekte: Aktions-Buttons nicht zu stark von abgeleiteten Zuständen abhängig machen; lieber im Backend validieren


2026-02-28 | Frontend | MaterialInput-Dropdown ohne Hintergrund

Problem: Dropdown der Material-Suchfeld-Komponente erschien transparent — Text über dem Hintergrund kaum lesbar Ursache: bg-surface Tailwind-Klasse + CSS-Variable mit Hex-Wert (siehe Learning 2026-02-18) Lösung: style={{ backgroundColor: 'var(--color-bg-surface)' }} für Dropdown-Container, Group-Header und Sticky-Button Datei: frontend/src/components/shared/MaterialInput.tsx


2026-03-06 | Refactor | .gitignore core trifft Verzeichnisse

Problem: .gitignore enthielt core als Regel (für core dump files) — Git ignorierte damit auch backend/app/core/ Verzeichnis Lösung: Regel zu /core umbenannt (Root-relative Regel trifft nur /core Datei, nicht verschachtelte core/-Verzeichnisse) Für künftige Projekte: Immer Root-relative Pfade (/core) für Dateien im Root-Verzeichnis nutzen


2026-03-06 | Architektur | Blender-HTTP-Service vs. direkter Subprocess

Problem: blender-renderer als Flask/FastAPI HTTP-Microservice war ein Single-Point-of-Failure (max. 1 concurrent Request), kein Scaling möglich, HTTP-Overhead bei jedem Render Lösung: Render-Worker als Celery-Container (render-worker/) — Blender direkt via subprocess.run ohne HTTP. is_blender_available() prüft BLENDER_BIN env var für Kontext-Detection Wichtig: step_processor.py erkennt über BLENDER_BIN-Env ob Blender im aktuellen Container verfügbar ist — Backend-Container fallen auf Pillow zurück Für künftige Projekte: Subprocess-basierter Renderer > HTTP-Microservice für blocking compute tasks


2026-03-06 | Refactor | Bash CWD-Problem durch Hook-Pfad-Auflösung

Problem: Nach cd frontend && npm test in einem Bash-Tool-Call blieb CWD dauerhaft in frontend/. Der Pre-Tool-Use-Hook python3 .claude/hooks/pre_tool_use.py wurde dann relativ zu frontend/ aufgelöst → Datei nicht gefunden → alle Tool-Calls blockiert Lösung: Symlink frontend/.claude → .claude erstellt: ln -sf $(pwd)/.claude frontend/.claude Für künftige Projekte: Hooks nie mit relativen Pfaden konfigurieren; absoluten Pfad im Hook-Command verwenden. Außerdem: cd immer in separate Bash-Calls oder mit && am Ende der eigentlichen Command-Chain


2026-03-06 | Multi-Tenancy | PostgreSQL RLS mit current_setting und Null-Safety

Problem: current_setting('app.current_tenant_id') wirft Exception wenn Variable nicht gesetzt → alle Queries schlagen fehl wenn kein Tenant-Context gesetzt ist Lösung: current_setting('app.current_tenant_id', true) — zweites Argument true macht die Funktion Null-safe: gibt NULL statt Exception zurück wenn Setting nicht gesetzt Admin-Bypass-Pattern: Separates CREATE POLICY admin_bypass ... USING (current_setting(...) = 'bypass') — setzt app.current_tenant_id = 'bypass' für Admin-Cross-Tenant-Queries Für künftige Projekte: IMMER das zweite true-Argument verwenden; Policies immer testen mit (a) gesetztem Tenant, (b) nicht gesetztem Setting, (c) Admin-Bypass


2026-03-06 | Refactor | Domain-Driven Migration: Compat-Shims statt Big-Bang

Problem: Vollständige Migration aller Models/Services/Router in neue Domain-Struktur in einem Schritt → alle bestehenden Imports brechen Lösung: Compat-Shims-Ansatz: alte Dateien (app/models/user.py etc.) werden zu Re-Export-Wrappern die aus den neuen Domain-Locations importieren. So funktionieren alle bestehenden Imports weiter während die kanonische Location die neue Domain ist Pattern:

# app/models/user.py (Compat-Shim)
from app.domains.auth.models import User
__all__ = ["User"]

Für künftige Projekte: Immer Compat-Shims anlegen vor dem Verschieben; erst nach vollständiger Migration aller Imports die Shims entfernen


2026-03-06 | Workflow-System | Celery Canvas vs. Custom Workflow-Engine

Problem: Custom Workflow-Engine (Graph-Traversal, Dependency-Resolution, Retry-Logic) war zu komplex (~2-3 Wochen Eigenentwicklung) Lösung: Celery Canvas als Execution-Engine (chain, group, chord). dispatch_workflow(type, order_line_id, params) baut den Canvas dynamisch aus Config-Typ. Backward-Compat: wenn kein workflow_definition_id → alter direkter Task-Call Seeded Workflows: 3 Standard-Definitionen beim Migration-Upgrade direkt in DB geSEEDed (Still, Turntable, Multi-Angle) Für künftige Projekte: Celery Canvas ist ausreichend für parallele/sequentielle Workflow-Execution; keine eigene Workflow-Engine bauen


Offene Fragen

  • Azure AI Credentials für Phase 4 (Bildvalidierung) noch nicht konfiguriert
  • pythonOCC verfügbar im render-worker (via cadquery dependency)? Deployment-Test ausstehend
  • @xyflow/react noch nicht installiert — npm install nötig nach nächstem docker compose up --build frontend
  • Material-Alias-Seeding deckt noch nicht alle deutschen Materialbezeichnungs-Varianten ab
  • Turntable-Animation: bg_color via FFmpeg-Overlay — Qualität bei Transparenz-Edges prüfen