a70cb55d01
- workflow_builder.py: fix broken stubs, add render_order_line_still_task
(resolves step_path from DB instead of passing order_line_id as step_path)
- domains/rendering/tasks.py: add render_order_line_still_task,
export_gltf_for_order_line_task, export_blend_for_order_line_task,
generate_gltf_geometry_task (trimesh STL→GLB, no Blender needed)
- tasks/step_tasks.py: add generate_gltf_geometry_task for CadFile GLB export
- cad router: POST /{id}/generate-gltf-geometry endpoint (admin/PM)
- worker router: GET /celery-workers + POST /scale (docker compose subprocess)
- Dockerfile: pip install -e "[dev]" to enable pytest
- docker-compose.yml: docker socket + compose file mount on backend
- ThreeDViewer.tsx: mode toggle (geometry/production), wireframe, env presets,
download buttons (GLB + .blend)
- CadPreview.tsx: load gltf_geometry/gltf_production/blend_production assets
from MediaAsset table and pass URLs to ThreeDViewer
- ProductDetail.tsx: "View 3D" button → /cad/:id, "Generate GLB" button
- media router/service: cad_file_id filter on GET /api/media
- WorkerManagement.tsx: new page with worker status, queue depth, scale controls
- App.tsx + Layout.tsx: /workers route + sidebar link (admin/PM)
- tests: test_rendering_service.py, test_orders_service.py (backend)
- tests: WorkerActivity.test.tsx, WorkerManagement.test.tsx (frontend)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
366 lines
18 KiB
Markdown
366 lines
18 KiB
Markdown
# Plan: Phase N — Workflow-Pipeline, 3D-Viewer Production-Modus, Worker-Management, QC-Tests
|
|
|
|
## Kontext
|
|
|
|
Vier offene Bereiche aus dem PLAN.md müssen abgeschlossen werden:
|
|
|
|
1. **Workflow-Pipeline verdrahten**: `workflow_builder.py` enthält nur defekte Stubs. `_build_still` übergibt `order_line_id` als `step_path` an `render_still_task` → würde crashen. Der neue `still_with_exports`-Workflow (still + gltf_export + blend_export) ist nicht implementiert. Die Celery-Tasks für export_gltf/export_blend fehlen in `domains/rendering/tasks.py`.
|
|
|
|
2. **K6: 3D-Viewer Production-Modus**: `ThreeDViewer.tsx` hat keinen Mode-Toggle, Wireframe, Env-Preset oder Download-Buttons. Für Testdaten wird `POST /api/cad/{id}/generate-gltf-geometry` benötigt (trimesh STL→GLB, kein Blender nötig).
|
|
|
|
3. **L3: Worker-Management UI**: `WorkerManagement.tsx` fehlt. Backend braucht `/celery-workers` (Celery inspect) und `/scale` (docker compose subprocess). Backend-Container bekommt Docker-Socket-Mount.
|
|
|
|
4. **M: QC-Tests**: `pytest` ist im Backend-Container nicht installiert. Dockerfile: `pip install -e ".[dev]"`. Neue Service-Tests für rendering und orders domains. 2 neue Vitest-Dateien.
|
|
|
|
---
|
|
|
|
## Betroffene Dateien
|
|
|
|
| Datei | Änderung |
|
|
|-------|----------|
|
|
| `backend/app/domains/rendering/tasks.py` | 3 neue Tasks: `render_order_line_still_task`, `export_gltf_for_order_line_task`, `export_blend_for_order_line_task` |
|
|
| `backend/app/domains/rendering/workflow_builder.py` | Stubs ersetzen durch order-line-aware Tasks, `still_with_exports` hinzufügen |
|
|
| `backend/app/api/routers/cad.py` | `POST /{id}/generate-gltf-geometry` Endpoint |
|
|
| `backend/app/api/routers/worker.py` | `GET /celery-workers`, `POST /scale` Endpoints |
|
|
| `backend/Dockerfile` | `pip install -e ".[dev]"` |
|
|
| `docker-compose.yml` | Backend + Worker: Docker-Socket + Compose-File-Mount |
|
|
| `frontend/src/components/cad/ThreeDViewer.tsx` | Mode-Toggle, Wireframe, Env-Preset, Download-Buttons |
|
|
| `frontend/src/pages/WorkerManagement.tsx` | NEU: Worker-Liste, Queue-Stats, Scale-Button |
|
|
| `frontend/src/api/worker.ts` | Neue Interfaces + API-Funktionen |
|
|
| `frontend/src/App.tsx` | Route für /workers |
|
|
| `frontend/src/components/layout/Layout.tsx` | Sidebar-Link Workers |
|
|
| `backend/tests/domains/test_rendering_service.py` | NEU: ≥5 Tests für Rendering-Tasks und Workflow-Builder |
|
|
| `backend/tests/domains/test_orders_service.py` | NEU: ≥5 Tests für Orders-Endpoints |
|
|
| `frontend/src/__tests__/pages/WorkerActivity.test.tsx` | NEU: Vitest-Tests |
|
|
| `frontend/src/__tests__/pages/WorkerManagement.test.tsx` | NEU: Vitest-Tests |
|
|
|
|
---
|
|
|
|
## Tasks (in Reihenfolge)
|
|
|
|
### Task 1: Backend — Neue order-line-aware Rendering-Tasks
|
|
- **Datei**: `backend/app/domains/rendering/tasks.py`
|
|
- **Was**: Drei neue Celery-Tasks hinzufügen (UNTER den bestehenden Tasks):
|
|
|
|
**`render_order_line_still_task(order_line_id, **params)`** — Queue `thumbnail_rendering`:
|
|
- Lädt OrderLine + CadFile via sync SQLAlchemy (wie `publish_asset`)
|
|
- Setzt `render_status = 'processing'`
|
|
- Ruft `render_still()` aus `app.services.render_blender` auf
|
|
- Setzt `render_status = 'completed'`, speichert `render_log`
|
|
- Bei Fehler: `render_status = 'failed'`
|
|
- Returns dict mit `output_path`
|
|
|
|
**`export_gltf_for_order_line_task(order_line_id)`** — Queue `thumbnail_rendering`:
|
|
- Lädt OrderLine + CadFile sync
|
|
- Sucht STL-Cache (`{step_stem}_low.stl`)
|
|
- Ruft Blender subprocess mit `export_gltf.py` auf: `blender --background --python export_gltf.py -- --stl_path X --output_path Y`
|
|
- Lädt GLB nach MinIO `production-exports/{cad_file_id}/{order_line_id}.glb`
|
|
- Erstellt `MediaAsset(asset_type=gltf_production, storage_key=...)`
|
|
- Returns `storage_key`
|
|
|
|
**`export_blend_for_order_line_task(order_line_id)`** — Queue `thumbnail_rendering`:
|
|
- Analog zu export_gltf, aber mit `export_blend.py`
|
|
- MediaAsset type: `blend_production`
|
|
|
|
- **Akzeptanzkriterium**: Tasks in `domains/rendering/tasks.py` vorhanden, keine Import-Fehler
|
|
- **Abhängigkeiten**: keine
|
|
|
|
### Task 2: Backend — workflow_builder.py reparieren + still_with_exports
|
|
- **Datei**: `backend/app/domains/rendering/workflow_builder.py`
|
|
- **Was**:
|
|
|
|
- `_build_still`: Nutzt `render_order_line_still_task` statt `render_still_task`
|
|
- `_build_turntable`: Bleibt vorerst mit `render_turntable_task` (file-path-basiert, funktioniert via legacy path)
|
|
- `_build_multi_angle`: Nutzt `render_order_line_still_task` mit `camera_angle` param
|
|
- **NEU** `_build_still_with_exports(order_line_id, params)`:
|
|
```python
|
|
from celery import chain, group
|
|
return chain(
|
|
render_order_line_still_task.si(order_line_id, **params),
|
|
group(
|
|
export_gltf_for_order_line_task.si(order_line_id),
|
|
export_blend_for_order_line_task.si(order_line_id),
|
|
)
|
|
)
|
|
```
|
|
- `dispatch_workflow()`: `"still_with_exports"` zu `builders` hinzufügen
|
|
|
|
- **Akzeptanzkriterium**: `dispatch_workflow("still_with_exports", order_line_id)` löst keine Exception aus
|
|
- **Abhängigkeiten**: Task 1
|
|
|
|
### Task 3: Backend — generate-gltf-geometry Endpoint (Testdaten für K6)
|
|
- **Datei**: `backend/app/api/routers/cad.py`
|
|
- **Was**: Neuer Endpoint `POST /api/cad/{id}/generate-gltf-geometry` (require_admin_or_pm):
|
|
- Prüft ob CadFile existiert + STL-Cache vorhanden (`{step_dir}/{stem}_low.stl`)
|
|
- Queut neuen Celery-Task `generate_gltf_geometry_task.delay(str(cad_file.id))`
|
|
- Returns `{"task_id": ..., "message": "GLB generation queued"}`
|
|
|
|
Neuer Task `generate_gltf_geometry_task` in `domains/rendering/tasks.py` (Queue `thumbnail_rendering`):
|
|
- Lädt CadFile sync, findet STL-Cache
|
|
- **Nutzt trimesh** (kein Blender): `import trimesh; mesh = trimesh.load(stl_path); mesh.export(glb_path)`
|
|
→ Warum trimesh: Schnell, kein Blender nötig, läuft auf worker-Container (trimesh in pyproject.toml cad-extras)
|
|
- Lädt GLB nach MinIO `uploads/{cad_file_id}/geometry.glb`
|
|
- Erstellt/aktualisiert `MediaAsset(asset_type=gltf_geometry, storage_key=..., cad_file_id=...)`
|
|
→ `MediaAsset` braucht `cad_file_id` FK — prüfen ob vorhanden
|
|
|
|
**Wichtig**: Prüfen ob `media_assets.cad_file_id` existiert. Falls nicht: Migration 047 notwendig.
|
|
|
|
- **Akzeptanzkriterium**: `POST /api/cad/{id}/generate-gltf-geometry` gibt 202 zurück, nach Task-Ausführung existiert MediaAsset mit type=gltf_geometry
|
|
- **Abhängigkeiten**: Task 1
|
|
|
|
### Task 4: Migration 047 — media_assets.cad_file_id (wenn nötig)
|
|
- **Datei**: `backend/alembic/versions/047_media_assets_cad_file_id.py`
|
|
- **Was**: Nullable FK `cad_file_id UUID REFERENCES cad_files(id) ON DELETE SET NULL` auf `media_assets`
|
|
- **Prüfen**: `grep -n "cad_file_id" backend/app/domains/media/models.py` — falls schon vorhanden: Task überspringen
|
|
- **Akzeptanzkriterium**: `alembic upgrade head` erfolgreich
|
|
- **Abhängigkeiten**: keine
|
|
|
|
### Task 5: ThreeDViewer.tsx — Production-Modus, Wireframe, Env-Preset, Downloads
|
|
- **Datei**: `frontend/src/components/cad/ThreeDViewer.tsx`
|
|
- **Was**: Props erweitern + Toolbar-Erweiterung:
|
|
|
|
```typescript
|
|
interface ThreeDViewerProps {
|
|
cadFileId: string
|
|
onClose: () => void
|
|
productionGltfUrl?: string // wenn vorhanden: Mode-Toggle anzeigen
|
|
downloadUrls?: { glb?: string; blend?: string }
|
|
}
|
|
```
|
|
|
|
**Neuer State:**
|
|
- `mode: 'geometry' | 'production'` (default: 'geometry')
|
|
- `wireframe: boolean` (default: false)
|
|
- `envPreset: 'city' | 'studio' | 'sunset'` (default: 'city')
|
|
|
|
**Toolbar** (neu, rechts vom "Capture Angle"-Button):
|
|
- Mode-Toggle (nur wenn `productionGltfUrl` gesetzt): Button-Gruppe "Geometry | Production"
|
|
- Wireframe-Toggle: Button
|
|
- Env-Preset-Dropdown: `<select>` mit city/studio/sunset
|
|
- Download-Buttons (wenn `downloadUrls` gesetzt): Download-Icon + "GLB" + optional "BLEND"
|
|
|
|
**Canvas-Änderungen:**
|
|
- `Environment preset={envPreset}` (jetzt konfigurierbar, bisher hardcoded "city")
|
|
- `WireframeToggle`-Komponente: setzt `material.wireframe = wireframe` auf allen Mesh-Children
|
|
- Model-URL: `mode === 'production' && productionGltfUrl ? productionGltfUrl : modelUrl`
|
|
|
|
**GltfErrorBoundary**: Reset bei mode-Wechsel (key prop ändern)
|
|
|
|
- **Akzeptanzkriterium**: Mode-Toggle erscheint wenn `productionGltfUrl` vorhanden, Wireframe-Toggle schaltet um, Env-Preset ändert Beleuchtung
|
|
- **Abhängigkeiten**: keine
|
|
|
|
### Task 6: CadPreview.tsx — Production-Asset-URLs übergeben
|
|
- **Datei**: `frontend/src/pages/CadPreview.tsx`
|
|
- **Was**: Beim Öffnen des ThreeDViewers:
|
|
- `GET /api/media-assets?cad_file_id={id}&asset_type=gltf_geometry` (oder gltf_production falls vorhanden)
|
|
- Download-URLs für GLB + BLEND laden
|
|
- `<ThreeDViewer productionGltfUrl={...} downloadUrls={...} />`
|
|
- "Generate GLB" Button (admin/PM): ruft `POST /api/cad/{id}/generate-gltf-geometry` auf + Toast + Reload
|
|
- **Akzeptanzkriterium**: Vorhandene MediaAssets werden als Production-URLs übergeben
|
|
- **Abhängigkeiten**: Task 3, Task 5
|
|
|
|
### Task 7: Media-API — assets by cad_file_id Query-Parameter
|
|
- **Datei**: `backend/app/domains/media/router.py`
|
|
- **Was**: `GET /api/media-assets?cad_file_id={uuid}` — Query-Param zu `list_assets` hinzufügen (optional, nullable)
|
|
- `list_media_assets(db, cad_file_id=...)` in service.py erweitern
|
|
- **Akzeptanzkriterium**: `GET /api/media-assets?cad_file_id=abc` gibt nur Assets dieses CadFile zurück
|
|
- **Abhängigkeiten**: Task 4
|
|
|
|
### Task 8: Frontend API — media.ts + cad.ts erweitern
|
|
- **Datei**: `frontend/src/api/media.ts`, `frontend/src/api/cad.ts`
|
|
- **Was**:
|
|
- `media.ts`: `listMediaAssets(params: {cad_file_id?: string, asset_type?: string}): Promise<MediaAsset[]>`
|
|
- `cad.ts`: `generateGltfGeometry(cadFileId: string): Promise<{task_id: string}>`
|
|
- Interface `MediaAsset` um `cad_file_id?: string` ergänzen (falls noch nicht vorhanden)
|
|
- **Akzeptanzkriterium**: TypeScript-Kompilierung fehlerfrei
|
|
- **Abhängigkeiten**: Task 7
|
|
|
|
### Task 9: Backend — Worker-Management Endpoints
|
|
- **Datei**: `backend/app/api/routers/worker.py`
|
|
- **Was**: Zwei neue Endpoints (require_admin):
|
|
|
|
**`GET /api/worker/celery-workers`**:
|
|
```python
|
|
from app.tasks.celery_app import celery_app
|
|
inspect = celery_app.control.inspect()
|
|
active = inspect.active() or {}
|
|
stats = inspect.stats() or {}
|
|
# Aggregiere: worker_name, hostname, active_tasks_count, queues
|
|
```
|
|
Response: `list[CeleryWorkerInfo]` mit Feldern: `worker_name, hostname, active_tasks, status`
|
|
|
|
**`POST /api/worker/scale`** (Body: `{service: "render-worker"|"worker", count: int}`):
|
|
```python
|
|
import subprocess, shutil
|
|
compose_file = os.environ.get("COMPOSE_FILE", "/docker-compose.yml")
|
|
result = subprocess.run(
|
|
["docker", "compose", "-f", compose_file,
|
|
"up", "--scale", f"{service}={count}", "--no-deps", "-d"],
|
|
capture_output=True, text=True, timeout=60
|
|
)
|
|
```
|
|
- Erfordert Docker-Socket-Mount (docker-compose.yml Änderung, Task 10)
|
|
- Validierung: count zwischen 0 und 10, service in erlaubte Liste
|
|
|
|
- **Akzeptanzkriterium**: `GET /api/worker/celery-workers` gibt Worker-Liste zurück (leer wenn keine aktiv)
|
|
- **Abhängigkeiten**: keine
|
|
|
|
### Task 10: docker-compose.yml — Docker-Socket + Compose-File-Mount
|
|
- **Datei**: `docker-compose.yml`
|
|
- **Was**: Im `backend`-Service:
|
|
```yaml
|
|
volumes:
|
|
- ./backend:/app
|
|
- uploads:/app/uploads
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
- ./docker-compose.yml:/docker-compose.yml
|
|
environment:
|
|
- COMPOSE_FILE=/docker-compose.yml
|
|
```
|
|
Außerdem `docker-cli` im Backend-Dockerfile installieren:
|
|
```dockerfile
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
... docker.io \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
```
|
|
- **Akzeptanzkriterium**: `docker compose exec backend docker compose version` funktioniert
|
|
- **Abhängigkeiten**: Task 9
|
|
|
|
### Task 11: Frontend — WorkerManagement.tsx
|
|
- **Datei**: `frontend/src/pages/WorkerManagement.tsx` (NEU)
|
|
- **Was**: Seite mit 3 Bereichen:
|
|
|
|
**Section 1 — Worker-Status** (useQuery `['celery-workers']`, refetchInterval 15s):
|
|
- Tabelle: Worker-Name, Hostname, Aktive Tasks, Status-Dot (grün=online, grau=keine Tasks)
|
|
- Leerer Zustand: "No active workers"
|
|
|
|
**Section 2 — Queue-Tiefe** (aus `GET /api/worker/activity`, bestehend):
|
|
- Karten: `step_processing` + `thumbnail_rendering` Queue-Tiefe
|
|
- Nutzt vorhandene WorkerActivity-Daten
|
|
|
|
**Section 3 — Scale-Worker** (require admin):
|
|
- Zwei Slider/Spinner: "step-worker (worker)" 1-8, "render-worker" 1-4
|
|
- Button "Scale" → `POST /api/worker/scale`
|
|
- Warnung: "Scaling down kills active renders"
|
|
- Toast bei Erfolg/Fehler
|
|
|
|
- **Akzeptanzkriterium**: Seite lädt, Worker-Liste zeigt laufende Worker, Scale-Button sendet Request
|
|
- **Abhängigkeiten**: Task 9, Task 12
|
|
|
|
### Task 12: Frontend — worker.ts API-Client
|
|
- **Datei**: `frontend/src/api/worker.ts` (NEU oder ergänzen)
|
|
- **Was**:
|
|
```typescript
|
|
export interface CeleryWorkerInfo {
|
|
worker_name: string
|
|
hostname: string
|
|
active_tasks: number
|
|
status: 'online' | 'idle'
|
|
}
|
|
export async function getCeleryWorkers(): Promise<CeleryWorkerInfo[]>
|
|
export async function scaleWorker(service: string, count: number): Promise<void>
|
|
```
|
|
- **Akzeptanzkriterium**: TypeScript kompiliert
|
|
- **Abhängigkeiten**: Task 9
|
|
|
|
### Task 13: Frontend — Route + Sidebar-Link für WorkerManagement
|
|
- **Datei**: `frontend/src/App.tsx`, `frontend/src/components/layout/Layout.tsx`
|
|
- **Was**:
|
|
- App.tsx: Route `/workers` → `<WorkerManagement />`
|
|
- Layout.tsx: Sidebar-Link "Workers" mit `Server`-Icon (admin only)
|
|
- **Akzeptanzkriterium**: `/workers` erreichbar, Link erscheint für Admins
|
|
- **Abhängigkeiten**: Task 11
|
|
|
|
### Task 14: Dockerfile — pytest installieren
|
|
- **Datei**: `backend/Dockerfile`
|
|
- **Was**: `pip install --no-cache-dir -e .` → `pip install --no-cache-dir -e ".[dev]"`
|
|
- **Akzeptanzkriterium**: `docker compose exec backend pytest --version` gibt Versionsnummer aus (nach Rebuild)
|
|
- **Abhängigkeiten**: keine
|
|
|
|
### Task 15: Backend-Tests — test_rendering_service.py
|
|
- **Datei**: `backend/tests/domains/test_rendering_service.py` (NEU)
|
|
- **Was**: ≥5 Tests:
|
|
1. `test_dispatch_workflow_unknown_type_raises` — ValueError bei unbekanntem Typ
|
|
2. `test_dispatch_workflow_still_builds_chain` — `_build_still` gibt Celery-Chain zurück (ohne apply_async)
|
|
3. `test_dispatch_workflow_still_with_exports_builds_chain` — group in chain
|
|
4. `test_publish_asset_creates_media_asset(db, admin_user)` — async, erstellt MediaAsset
|
|
5. `test_publish_asset_nonexistent_order_line_returns_none` — graceful None
|
|
6. (Bonus) `test_legacy_dispatch_queues_task(monkeypatch)` — mock_celery, prüft Task wurde eingereicht
|
|
- **Akzeptanzkriterium**: `pytest tests/domains/test_rendering_service.py` → alles grün
|
|
- **Abhängigkeiten**: Task 14
|
|
|
|
### Task 16: Backend-Tests — test_orders_service.py
|
|
- **Datei**: `backend/tests/domains/test_orders_service.py` (NEU)
|
|
- **Was**: ≥5 Tests gegen `GET/POST /api/orders` und Orders-Service-Funktionen:
|
|
1. `test_create_order_returns_201(client, auth_headers)` — POST /api/orders
|
|
2. `test_list_orders_empty(client, auth_headers)` — leere Liste zurück
|
|
3. `test_get_order_404_for_unknown_id(client, auth_headers)` — 404 bei unbekannter ID
|
|
4. `test_order_submit_status_change(client, auth_headers)` — Submit ändert Status
|
|
5. `test_order_requires_auth(client)` — 401 ohne Token
|
|
- **Akzeptanzkriterium**: `pytest tests/domains/test_orders_service.py` → alles grün
|
|
- **Abhängigkeiten**: Task 14
|
|
|
|
### Task 17: Frontend-Tests — WorkerActivity.test.tsx + WorkerManagement.test.tsx
|
|
- **Datei**: `frontend/src/__tests__/pages/WorkerActivity.test.tsx` (NEU), `WorkerManagement.test.tsx` (NEU)
|
|
- **Was**:
|
|
- WorkerActivity: Test render + "No recent activity" leerer Zustand, Mock-API-Response
|
|
- WorkerManagement: Test render Header "Worker Management", Scale-Button vorhanden
|
|
- Nutzen MSW handlers aus `mocks/`
|
|
- **Akzeptanzkriterium**: `npm run test` → 0 Failures (≥5 Tests total neu)
|
|
- **Abhängigkeiten**: Task 11
|
|
|
|
---
|
|
|
|
## Migrations-Check
|
|
|
|
| Migration | Beschreibung | Notwendig? |
|
|
|-----------|-------------|------------|
|
|
| 047 | `media_assets.cad_file_id FK` | **Prüfen**: `grep cad_file_id backend/app/domains/media/models.py` — wenn fehlt → ja |
|
|
|
|
Vor Implementierung prüfen: `cat backend/app/domains/media/models.py | grep cad_file_id`
|
|
|
|
---
|
|
|
|
## Reihenfolge-Empfehlung
|
|
|
|
```
|
|
Parallel-Gruppe 1 (keine gegenseitigen Abhängigkeiten):
|
|
Task 1 (neue Celery-Tasks)
|
|
Task 4 (Migration 047 prüfen + ggf. erstellen)
|
|
Task 5 (ThreeDViewer Props)
|
|
Task 9 (Worker-Endpoints Backend)
|
|
Task 14 (Dockerfile pytest)
|
|
|
|
Nach Gruppe 1:
|
|
Task 2 (workflow_builder reparieren) — braucht Task 1
|
|
Task 3 (generate-gltf-geometry Endpoint) — braucht Task 1 + 4
|
|
Task 10 (docker-compose Mount) — braucht Task 9
|
|
Task 12 (worker.ts API) — braucht Task 9
|
|
|
|
Nach Gruppe 2:
|
|
Task 6 (CadPreview anpassen) — braucht Task 3, 5
|
|
Task 7 (media router cad_file_id param) — braucht Task 4
|
|
Task 8 (frontend API) — braucht Task 7
|
|
Task 11 (WorkerManagement.tsx) — braucht Task 9, 12
|
|
|
|
Nach Gruppe 3:
|
|
Task 13 (Route + Sidebar) — braucht Task 11
|
|
Task 15 (test_rendering_service.py) — braucht Task 14
|
|
Task 16 (test_orders_service.py) — braucht Task 14
|
|
Task 17 (frontend tests) — braucht Task 11
|
|
```
|
|
|
|
---
|
|
|
|
## Risiken / Offene Fragen
|
|
|
|
1. **media_assets.cad_file_id**: Muss vor Implementierung geprüft werden. Wenn schon vorhanden → Migration 047 entfällt.
|
|
|
|
2. **trimesh auf render-worker**: `trimesh` ist in `pyproject.toml` als optionale `cad`-Dependency gelistet (`trimesh>=4.2.0`). Der worker-Container muss sie installiert haben. Im render-worker Dockerfile prüfen: `pip install trimesh`.
|
|
|
|
3. **docker compose in Backend-Container**: Das scale-Feature setzt voraus, dass `docker.io` + compose-Plugin im Backend-Image installiert sind. Build-Zeit steigt ~30MB. Alternativ: Nur die Celery-Worker-Ansicht implementieren, Scale als Hinweis-Text mit dem CLI-Befehl.
|
|
|
|
4. **render_order_line_still_task vs. legacy render_order_line_task**: Beide tun ähnliches. Langfristig sollte `step_tasks.render_order_line_task` durch den neuen Task ersetzt werden. Für jetzt: Neuer Task läuft parallel, Legacy bleibt erhalten (backward-compat).
|
|
|
|
5. **Celery inspect Timeout**: `celery_app.control.inspect(timeout=2)` kann hängen wenn kein Worker läuft. Timeout setzen + leere Liste zurückgeben.
|