bfd58e3419
Bug A: Media Library thumbnails were gray because <img src> cannot send JWT auth headers. Added useAuthBlob() hook (fetch + createObjectURL) in MediaBrowser.tsx. Also fixed publish_asset Celery task to populate product_id + cad_file_id on MediaAsset for thumbnail fallback resolution. Bug B: Product dimensions now shown in Product Details card with Ruler icon and "from CAD" label when cad_mesh_attributes.dimensions_mm exists. Bug C: Replaced 128×128 CAD thumbnail with InlineCadViewer component. Queries gltf_geometry MediaAssets, fetches GLB via auth fetch → blob URL → Three.js Canvas with OrbitControls. Falls back to thumbnail + "Load 3D Model" button. Polling when GLB generation is in progress. Bug D: trimesh was in [cad] optional extra but Dockerfile only installed [dev]. Changed to pip install -e ".[dev,cad]" — trimesh now available in backend container, GLB + Colors export works. Also added bbox extraction (STL-first numpy parsing) in render_step_thumbnail and admin "Re-extract CAD Metadata" bulk endpoint. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
82 lines
4.8 KiB
Markdown
82 lines
4.8 KiB
Markdown
# Plan: 4 Bug Fixes — Media Thumbnails, Product Dimensions, Inline 3D Viewer, GLB Export
|
||
|
||
## Root Cause Analysis
|
||
|
||
### Bug A — Missing Thumbnails in Media Library
|
||
`<img src="/api/media/{id}/download">` fails silently: the download endpoint requires JWT auth, but `<img>` tags don't send auth headers → 401 → `imgError=true` → gray icon.
|
||
For `thumbnail` type assets: fallback works via `get_thumbnail_url()` → `/api/cad/{cad_file_id}/thumbnail` (no-auth endpoint). For `still` type: no cad_file_id/product_id → no fallback → gray icon shown.
|
||
|
||
### Bug B — No Dimensions in "Product Details" Card
|
||
The `cad_mesh_attributes.dimensions_mm` block exists in the CAD File section (right sidebar), NOT in the "Product Details" card. User wants it in Product Details.
|
||
|
||
### Bug C — No Embedded 3D Viewer
|
||
"View 3D" navigates to `/cad/:id` (full page). User wants an inline viewer in the product page CAD card that auto-loads when a `gltf_geometry` asset exists.
|
||
|
||
### Bug D — GLB + Colors Error
|
||
`trimesh` is in `pyproject.toml` but the backend container was not rebuilt → `ModuleNotFoundError: No module named 'trimesh'`. Needs rebuild.
|
||
|
||
---
|
||
|
||
## Betroffene Dateien
|
||
|
||
| File | Change | Bug |
|
||
|------|--------|-----|
|
||
| `frontend/src/pages/MediaBrowser.tsx` | `useAuthBlob` hook + use in AssetCard | A |
|
||
| `backend/app/domains/rendering/tasks.py` | `publish_asset` populates product_id + cad_file_id | A |
|
||
| `frontend/src/pages/ProductDetail.tsx` | Add dimensions to Product Details card + inline viewer | B, C |
|
||
| `frontend/src/components/cad/InlineCadViewer.tsx` | New compact 3D viewer component | C |
|
||
| `backend/` (docker rebuild) | Rebuild to install trimesh | D |
|
||
|
||
---
|
||
|
||
## Tasks (in Reihenfolge)
|
||
|
||
### Task A1: Backend — publish_asset populates product_id + cad_file_id
|
||
- **Datei**: `backend/app/domains/rendering/tasks.py`
|
||
- **Was**: In `publish_asset`, after loading the OrderLine, also load `line.product_id` and the product's `cad_file_id`. Set these on the new MediaAsset. This enables the `_resolve_thumbnails_bulk` fallback and `get_thumbnail_url()` for still assets.
|
||
- **Akzeptanzkriterium**: New still assets have product_id and cad_file_id set in DB.
|
||
|
||
### Task A2: Frontend — useAuthBlob hook in MediaBrowser
|
||
- **Datei**: `frontend/src/pages/MediaBrowser.tsx`
|
||
- **Was**: Add `useAuthBlob(url)` hook that fetches the URL with Authorization header and returns a blob URL. Use it in `AssetCard` instead of `asset.download_url` for image rendering. Revoke blob URL on unmount.
|
||
- **Akzeptanzkriterium**: Still images visible in media library grid.
|
||
|
||
### Task B: Frontend — Dimensions in Product Details card
|
||
- **Datei**: `frontend/src/pages/ProductDetail.tsx`
|
||
- **Was**: In the "Product Details" card (around line 409-433), after the Notes field, add a read-only "Dimensions" row if `product.cad_mesh_attributes?.dimensions_mm` exists. Format: "X × Y × Z mm" with a Ruler icon and small "from CAD" label.
|
||
- **Akzeptanzkriterium**: Dimensions visible in Product Details card when mesh_attributes populated.
|
||
|
||
### Task C: Frontend — Inline 3D Viewer in CAD card
|
||
- **Datei**: `frontend/src/components/cad/InlineCadViewer.tsx` (new), `frontend/src/pages/ProductDetail.tsx`
|
||
- **Was**:
|
||
1. Create `InlineCadViewer` component that:
|
||
- Accepts `cadFileId: string`
|
||
- Queries `getMediaAssets({ cad_file_id, asset_types: ['gltf_geometry'] })`
|
||
- If asset found: fetches GLB with auth (axios → arraybuffer → blob URL) → renders Three.js canvas (OrbitControls, auto-fit camera)
|
||
- While loading: shows spinner
|
||
- If no asset: shows "Generate GLB" button + thumbnail fallback
|
||
2. In ProductDetail: replace the 128×128 thumbnail box with `InlineCadViewer` (make it ~300px tall)
|
||
- Move thumbnail fallback inside InlineCadViewer
|
||
- Keep "View 3D" as "View Full Screen" link below viewer
|
||
- Remove standalone "View 3D" button (or keep as secondary link)
|
||
- **Akzeptanzkriterium**: Inline 3D model visible in product page without clicking "View 3D".
|
||
|
||
### Task D: Backend rebuild — install trimesh
|
||
- **Was**: Run `docker compose up -d --build backend` to install trimesh from pyproject.toml
|
||
- **Akzeptanzkriterium**: `docker compose exec backend python3 -c "import trimesh; print('ok')"` succeeds. GLB + Colors download works.
|
||
|
||
---
|
||
|
||
## Migrations-Check
|
||
Keine DB-Migrationen nötig. `product_id` und `cad_file_id` sind bereits Spalten in `media_assets`.
|
||
|
||
## Reihenfolge-Empfehlung
|
||
A1 + A2 + B + C parallel (alle unabhängig).
|
||
D parallel (nur Docker rebuild, kein Code).
|
||
|
||
## Risiken / Offene Fragen
|
||
- `useAuthBlob` creates blob URLs per asset — 50+ assets in grid could trigger many fetches. Add `limit` or lazy load (only fetch when card is visible).
|
||
- InlineCadViewer: GLB fetch for large files may take 5-30s. Show skeleton/spinner.
|
||
- `useGLTF` from drei expects a URL string. Blob URLs work fine.
|
||
- ThreeDViewer has `onClose` required prop — InlineCadViewer should be a new simpler component.
|