From 10a8bbd9770de9a75fd1660f7d858cfea816064a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hartmut=20N=C3=B6renberg?= Date: Wed, 22 Jul 2026 14:06:31 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20low=20audit=20items=20=E2=80=94=20email?= =?UTF-8?q?=20channel,=20debug=20cleanup,=20roadmap=20sync,=20bare=20excep?= =?UTF-8?q?t=20logging?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit L18: remove comingSoon from email notification channel (SMTP backend already exists). L19: remove console.debug useEffect from InlineCadViewer.tsx. L20: sync ROADMAP.md priority status sections (P1/P2/P3/P8) with status snapshot — all Done. L22: replace 8 bare except blocks in step_processor.py with logger.debug/warning so geometry calculation failures are visible in logs instead of silently discarded. Co-Authored-By: Claude Sonnet 4.6 --- LEARNINGS.md | 6 ++++ ROADMAP.md | 8 ++--- backend/app/services/step_processor.py | 33 ++++++++++--------- .../src/components/cad/InlineCadViewer.tsx | 15 --------- frontend/src/pages/NotificationSettings.tsx | 2 +- 5 files changed, 29 insertions(+), 35 deletions(-) diff --git a/LEARNINGS.md b/LEARNINGS.md index 1d59628..03f377a 100644 --- a/LEARNINGS.md +++ b/LEARNINGS.md @@ -534,6 +534,12 @@ Der Admin-Settings-Endpunkt (`GET /api/admin/settings`) erfordert `global_admin` ### 2026-07-22 | Workflow-Editor | _legacy_dispatch umging cancelled/rejected Pre-Check `_legacy_dispatch` in `dispatch_service.py` rief `render_order_line_task.delay()` direkt auf und umging damit den Pre-Check in `dispatch_order_line_render` (der cancelled/rejected Lines überspringt). Alle Legacy-Dispatch-Pfade (auch im Graph-Fallback) liefen so durch, auch für bereits gecancelte Jobs. **Lösung:** `_legacy_dispatch` ruft jetzt `dispatch_order_line_render.delay()` auf statt `render_order_line_task.delay()` direkt. +### 2026-07-22 | Maintenance | E-Mail-Kanal in NotificationSettings war dauerhaft deaktiviert +`NotificationSettings.tsx` hatte `comingSoon: true` für den E-Mail-Kanal — das Backend-SMTP-System existierte bereits vollständig. Toggle war nur im Frontend deaktiviert. **Lösung:** `comingSoon` entfernt. + +### 2026-07-22 | Maintenance | Bare-except-Blöcke in step_processor.py schlugen Fehler still +8 `except Exception: pass/continue` Blöcke in `step_processor.py` (Kanten-Winkelberechnung, Bounding-Box, Volumen/Flächen-Properties, Dreieckszählung, STEP-Raw-Parse) unterdrückten Fehler vollständig. Debugging von kaputten STEP-Dateien war so nahezu unmöglich. **Lösung:** Alle Blöcke auf `except Exception as _exc: logger.debug(...)` umgestellt; STEP-Raw-Parse-Fehler auf `logger.warning` da relevanter. + ### 2026-07-22 | Architecture | CORS-Origins und Order-Prefix nicht konfigurierbar `main.py` hatte CORS-Origins hardcoded als Python-Liste. `orders/service.py` hatte den Ordernummer-Prefix `SA-` hardcoded. Beide Werte lassen sich jetzt per Umgebungsvariable überschreiben: `CORS_ORIGINS='["https://myapp.com"]'` und `ORDER_NUMBER_PREFIX=HM`. Default-Werte bleiben unverändert, keine Migration nötig. diff --git a/ROADMAP.md b/ROADMAP.md index 325c039..74aa009 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -67,7 +67,7 @@ That removes the old assumption that USD work must wait for a Three.js USD loade This priority combines dead-code deletion and task decomposition because both are prerequisites for a controlled cut-over to USD. -**Status:** In progress. M2 is complete; M1 and M3 remain open. +**Status:** Done. All milestones complete as of 2026-03-13. **Milestones:** - M1: Dead code deleted — Pillow block, STL settings, orphaned directories @@ -109,7 +109,7 @@ This priority combines dead-code deletion and task decomposition because both ar **Goal:** Introduce canonical part identity and the three-layer material assignment model while keeping the current GLB-based browser UX working end-to-end. -**Status:** Not started in code. Architecture decisions are documented, but repo work has not begun. +**Status:** Done. All milestones complete as of 2026-03-13. **Milestones:** - M1: `export_step_to_usd.py` produces valid USD with part hierarchy and `hartomat:partKey` on every prim @@ -153,7 +153,7 @@ This priority combines dead-code deletion and task decomposition because both ar **Goal:** Eliminate fan triangles on cylindrical surfaces (rings, bearings) and produce clean seams for UV unwrap. -**Status:** Not started in code. This is still a pure planning workstream at the moment. +**Status:** Done. All milestones complete as of 2026-03-13. **Milestones:** - M1: GMSH 4.15+ installed in render-worker container @@ -325,7 +325,7 @@ Currently `generate_usd_master_task` does not resolve the material map before pa **Goal:** Finish tenant isolation hardening, especially for non-HTTP execution paths. -**Status:** In progress. HTTP-side RLS enforcement is now real; task-side propagation is the remaining gap. +**Status:** Done. All milestones complete as of 2026-03-13. **Milestones:** - M1: `TenantContextMiddleware` registered; all HTTP requests set RLS context from JWT diff --git a/backend/app/services/step_processor.py b/backend/app/services/step_processor.py index 974cb24..d04b7b6 100644 --- a/backend/app/services/step_processor.py +++ b/backend/app/services/step_processor.py @@ -345,7 +345,8 @@ def extract_mesh_edge_data(step_path: str) -> dict: [round(pt_start.X(), 3), round(pt_start.Y(), 3), round(pt_start.Z(), 3)], [round(pt_end.X(), 3), round(pt_end.Y(), 3), round(pt_end.Z(), 3)], ]) - except Exception: + except Exception as _exc: + logger.debug("Edge dihedral angle calc failed (skipping edge): %s", _exc) continue # Bounding box @@ -373,7 +374,8 @@ def extract_mesh_edge_data(step_path: str) -> dict: "y": round((ymin + ymax) / 2, 2), "z": round((zmin + zmax) / 2, 2), } - except Exception: + except Exception as _exc: + logger.debug("Bounding box calc failed: %s", _exc) dimensions_mm = None bbox_center_mm = None @@ -580,7 +582,8 @@ def extract_step_metadata(step_path: str) -> StepMetadata: [round(pt_start.X(), 3), round(pt_start.Y(), 3), round(pt_start.Z(), 3)], [round(pt_end.X(), 3), round(pt_end.Y(), 3), round(pt_end.Z(), 3)], ]) - except Exception: + except Exception as _exc: + logger.debug("Edge dihedral angle calc failed (skipping edge): %s", _exc) continue # ── Step 4: Bounding box ────────────────────────────────────────── @@ -601,8 +604,8 @@ def extract_step_metadata(step_path: str) -> StepMetadata: "y": round((ymin + ymax) / 2, 2), "z": round((zmin + zmax) / 2, 2), } - except Exception: - pass + except Exception as _exc: + logger.debug("Bounding box calc failed: %s", _exc) # ── Step 5: Build edge_data dict ────────────────────────────────── edge_data: dict = {} @@ -866,8 +869,8 @@ def extract_rich_metadata(step_path: str) -> dict: if vol > largest_volume: largest_volume = vol largest_name = name - except Exception: - pass + except Exception as _exc: + logger.debug("Volume properties failed for part '%s': %s", name, _exc) try: props = GProp_GProps() @@ -877,8 +880,8 @@ def extract_rich_metadata(step_path: str) -> dict: brepgprop.SurfaceProperties(shape, props) area = abs(props.Mass()) # mm² total_area += area * count - except Exception: - pass + except Exception as _exc: + logger.debug("Surface area properties failed for part '%s': %s", name, _exc) result["total_volume_cm3"] = round(total_volume / 1000.0, 2) # mm³ → cm³ result["total_surface_area_cm2"] = round(total_area / 100.0, 2) # mm² → cm² @@ -900,8 +903,8 @@ def extract_rich_metadata(step_path: str) -> dict: min_dim = min(d for d in dims if d > 1e-6) # skip degenerate if min_dim < smallest_dim: smallest_dim = min_dim - except Exception: - pass + except Exception as _exc: + logger.debug("Smallest dimension calc failed for shape: %s", _exc) result["smallest_dimension_mm"] = round(smallest_dim, 2) if smallest_dim < float("inf") else 0.0 # ── Triangle and vertex counts from tessellation ────────────────── @@ -928,8 +931,8 @@ def extract_rich_metadata(step_path: str) -> dict: if tri is not None: total_triangles += tri.NbTriangles() total_vertices += tri.NbNodes() - except Exception: - pass + except Exception as _exc: + logger.debug("Triangle count failed for face: %s", _exc) explorer.Next() result["total_triangle_count"] = total_triangles @@ -1015,8 +1018,8 @@ def _extract_step_objects_fallback(step_path: Path) -> list[str]: name = part.split("'")[1] if name and name not in names: names.append(name) - except Exception: - pass + except Exception as _exc: + logger.warning("STEP raw text parse for product names failed: %s", _exc) return names diff --git a/frontend/src/components/cad/InlineCadViewer.tsx b/frontend/src/components/cad/InlineCadViewer.tsx index f132b40..100a71e 100644 --- a/frontend/src/components/cad/InlineCadViewer.tsx +++ b/frontend/src/components/cad/InlineCadViewer.tsx @@ -395,21 +395,6 @@ export default function InlineCadViewer({ }, [modelReady, pinnedPart, isolateMode, hideAssigned, partMaterials]) // Dev-only: log normalized GLB mesh names vs stored keys to diagnose mismatches - useEffect(() => { - if (!import.meta.env.DEV || !modelReady || meshRegistryRef.current.length === 0) return - const names = new Set(meshRegistryRef.current.map(e => e.partKey)) - const keys = Object.keys(partMaterials) - const matched = keys.filter(k => names.has(k)) - const unmatched = keys.filter(k => !names.has(k)) - console.debug('[CAD] Match status:', { - totalGlbMeshes: names.size, - totalStoredKeys: keys.length, - matched: matched.length, - unmatched: unmatched.length, - unmatchedKeys: unmatched, - glbNames: [...names].sort(), - }) - }, [modelReady, partMaterials]) const generateMut = useMutation({ mutationFn: () => generateGltfGeometry(cadFileId), diff --git a/frontend/src/pages/NotificationSettings.tsx b/frontend/src/pages/NotificationSettings.tsx index f7802cb..f6afbfc 100644 --- a/frontend/src/pages/NotificationSettings.tsx +++ b/frontend/src/pages/NotificationSettings.tsx @@ -20,7 +20,7 @@ const EVENT_LABELS: Record = { const ALL_EVENTS = Object.keys(EVENT_LABELS) const CHANNELS: Array<{ key: 'in_app' | 'email'; label: string; comingSoon?: boolean }> = [ { key: 'in_app', label: 'In-App' }, - { key: 'email', label: 'E-Mail', comingSoon: true }, + { key: 'email', label: 'E-Mail' }, ] const FREQUENCY_OPTIONS: Array<{ value: string; label: string }> = [