feat: per-position camera settings, material alias dialog, product delete, media browser links

- Per-render-position focal_length_mm/sensor_width_mm (DB → pipeline → Blender)
- FOV-based camera distance with min clamp fix for wide-angle lenses
- Unmapped materials blocking dialog on "Dispatch Renders" with batch alias creation
- Material check endpoint (GET /orders/{id}/check-materials)
- Batch alias endpoint (POST /materials/batch-aliases)
- Quick-map "No alias" badges on Materials page
- Full product hard-delete with storage cleanup (MinIO + disk files + orphaned CadFile)
- Delete button on ProductDetail page with confirmation
- Clickable product names in Media Browser (links to product page)
- Single-line render dispatch/retry (POST /orders/{id}/lines/{id}/dispatch-render)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-14 12:16:37 +01:00
parent 0020376702
commit b583b0d7a2
48 changed files with 1827 additions and 376 deletions
+15 -4
View File
@@ -7,6 +7,12 @@
## Learnings
### 2026-03-14 | Blender | OBJ-Rotation Turntable: Reparenting von USD-Parts verschiebt Geometrie
USD-importierte Parts haben existierende Eltern-Objekte (Xform-Nodes). `part.parent = pivot; part.matrix_parent_inverse = pivot.matrix_world.inverted()` verliert den Beitrag des alten Parents zur Welt-Position → Parts verschieben sich ~14m. Fix: World-Matrix vor Reparenting sichern, dann via `part.matrix_local = pivot.inverted() @ saved_world` wiederherstellen. Zusätzlich `bpy.context.view_layer.update()` vor dem Parenting aufrufen, damit `pivot.matrix_world` aktuell ist.
### 2026-03-13 | Blender/USD | USD-Import erzeugt leere Material-Stubs → schwarze Renders
Blender's `bpy.ops.wm.usd_import()` erstellt leere Material-Stubs (use_nodes=True, nodes=0) aus USD MaterialBinding-Referenzen. Wenn `apply_material_library_direct` dann die echten Materialien aus der .blend-Bibliothek laden will, findet es die Stubs bereits in `bpy.data.materials` und nutzt sie direkt — ohne die echten Shader-Node-Trees zu laden. Leere Materialien rendern in Cycles als pures Schwarz (RGB max=1). Fix: `_find_material_with_nodes()` Hilfsfunktion, die `.NNN`-Suffix-Kollisionen auflöst und nur Materialien mit echten Nodes zurückgibt.
### 2026-03-12 | Caching | Composite Cache Keys für Tessellierung
Hash-basiertes Caching in Celery Tasks muss alle relevanten Parameter einschließen, nicht nur den Datei-Hash. Bei `generate_gltf_geometry_task` und `generate_usd_master_task` wurde der Cache-Key auf `{hash}:{linear}:{angular}:{engine}` erweitert. Außerdem: immer Disk-Existenz des gecachten Assets prüfen (`storage_key.exists()`) bevor ein Cache-Hit zurückgegeben wird — der Asset-Record kann existieren, die Datei aber nicht.
@@ -466,11 +472,7 @@ for obj in mesh_objects:
---
## 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
### 2026-03-11 | OCP/Python | id(solid.TShape()) ist nicht stabil
In OCP (pybind11-basiert) gibt jeder Aufruf von `solid.TShape()` ein neues Python-Wrapper-Objekt zurück, das dieselbe C++ TShape-Instanz wrapet. `id()` gibt daher jedes Mal einen anderen Wert → Deduplizierung per `id()` schlägt immer fehl. **Lösung:** `solid.IsSame(other_solid)` verwenden (vergleicht TShape-Zeiger intern, liefert True für gleiche TShape mit unterschiedlicher Location/Orientation).
@@ -492,3 +494,12 @@ GMSH 4.15.1 in render-worker installiert. `tessellation_engine=gmsh` ist der akt
### 2026-03-12 | Debugging | Stale GLB-Cache maskiert Code-Fixes
Bug "Wälzkörper an falscher Position" war in Code durch commit 638b93b (IsSame-Fix) bereits behoben. Aber gecachtes Produktions-GLB (vor dem Fix generiert) zeigte weiterhin falsche Positionen im Viewer. Lösung: Geometry-GLB manuell neu generieren oder `step_file_hash = NULL` in DB um Cache-Invalidierung zu erzwingen. Nach Code-Fixes an Tessellierung/Export IMMER alle betroffenen GLB-Caches invalidieren.
### 2026-03-13 | OCC/GLB | BRepBuilderAPI_Transform zerstört Tessellierung + RWGltf_CafWriter MergeFaces
**Problem**: GLB-Dateien hatten nur ~164 Vertices pro Bauteil statt ~7000. Zwei Ursachen:
1. `BRepBuilderAPI_Transform(shape, trsf, copy=True)` zerstört **alle** `Poly_Triangulation`-Daten. Die mm→m-Skalierung vor dem Export löschte die BRepMesh-Tessellierung.
2. `RWGltf_CafWriter` mit `MergeFaces=False` (Default) findet keine per-Face-Tessellierung aus der XCAF-Komponentenhierarchie und produziert degenerierte Meshes.
**Lösung**:
- `BRepBuilderAPI_Transform` komplett entfernt — `RWGltf_CafWriter` konvertiert intern mm→m und Z-up→Y-up.
- `writer.SetMergeFaces(True)` hinzugefügt — composited Face-Triangulationen zu korrekten Shape-Buffern (1.212 → 46.573 Vertices).
**Merke**: OCC `TopLoc_Location` kann keine Skalierung (wirft `Standard_DomainError`). Für Skalierung entweder den Writer intern konvertieren lassen oder GLB post-process.