8.6 KiB
HartOMat
Ziel
Automatisiertes Render-System für HartOMat-Produktbilder. Kunden (intern) laden Excel-Auftragslisten hoch, das System extrahiert Produktdaten, verknüpft STEP-CAD-Dateien, rendert Thumbnails und Animationen über Blender (Cycles/EEVEE), und liefert fertige PNG/MP4-Ausgaben.
Tech Stack
- Backend: Python 3.11, FastAPI (async), SQLAlchemy 2 (async), Alembic, Celery, Pydantic v2
- Frontend: React 18, TypeScript, Vite, Tailwind CSS, lucide-react
- Datenbank: PostgreSQL 16
- Queue/Cache: Redis 7 (Celery Broker + Backend)
- Storage: MinIO (S3-kompatibel)
- Renderer: Blender 5.0.1 (headless, Cycles GPU)
- CAD Parsing: OCC (cadquery/OCP) für STEP-Parsing, GMSH 4.15 für Tessellierung
- USD: usd-core (pxr) für kanonische Szenen-Exporte
- Deployment: Docker Compose (8 Services)
Services (docker-compose.yml)
| Service | Port | Funktion |
|---|---|---|
postgres |
5432 | Primärdatenbank |
redis |
6379 | Celery Broker |
minio |
9000/9001 | S3-kompatibler Object Store (MediaAssets) |
backend |
8888 | FastAPI App (uvicorn) |
worker |
– | Celery Worker, Queue: step_processing, concurrency=8 |
render-worker |
– | Celery Worker, Queue: asset_pipeline, concurrency=1 (Blender) |
beat |
– | Celery Beat (Scheduler) |
frontend |
5173 | React/Vite Dev Server |
Starten / Stoppen
# Alle Services starten
docker compose up -d
# Logs einzelner Services
docker compose logs -f backend
docker compose logs -f worker
docker compose logs -f render-worker
# Neubauen nach Codeänderungen (Backend/Worker)
docker compose up -d --build backend worker render-worker beat
# Frontend-Änderungen: Hot-Reload aktiv, kein Rebuild nötig
Standard-Zugangsdaten (Entwicklung)
- Admin: admin@hartomat.com / Admin1234!
- Backend API: http://localhost:8888/docs
- Frontend: http://localhost:5173
Projektstruktur
project-root/
├── backend/
│ ├── app/
│ │ ├── api/routers/ # FastAPI Router (admin, cad, orders, products, ...)
│ │ ├── core/ # Middleware, pipeline_logger, process_steps, tenant_context
│ │ ├── domains/ # Domain-driven modules (orders, media, pipeline, rendering, tenants, ...)
│ │ │ └── pipeline/tasks/ # Active Celery task implementations
│ │ ├── models/ # SQLAlchemy ORM-Modelle
│ │ ├── services/ # Business-Logik (step_processor, render_blender, material_service, ...)
│ │ ├── tasks/ # Compatibility shim only (step_tasks.py, 23 lines) — do NOT add logic here
│ │ └── utils/ # Auth, Seeding
│ ├── alembic/versions/ # DB-Migrationen (001–062+)
│ └── start.sh # Entrypoint: migrate → seed → uvicorn
├── render-worker/
│ ├── scripts/ # Blender/OCC/GMSH subprocess scripts
│ │ ├── blender_render.py # Entry point (68 lines), delegates to _blender_*.py submodules
│ │ ├── export_step_to_gltf.py # OCC/GMSH STEP → GLB tessellation
│ │ ├── export_step_to_usd.py # OCC STEP → USD canonical scene
│ │ ├── import_usd.py # Blender: USD import + primvar restoration
│ │ ├── still_render.py # Blender still render
│ │ └── turntable_render.py # Blender turntable animation
│ └── Dockerfile
├── frontend/src/
│ ├── api/ # API-Client-Funktionen (axios-basiert)
│ ├── components/ # Wiederverwendbare UI-Komponenten
│ └── pages/ # Seitenkomponenten
└── docker-compose.yml
Coding-Standards
- Sprache im Code: Englisch (Variablen, Kommentare, Commits)
- Commits: Conventional Commits (
feat:,fix:,refactor:,docs:) - Python: async/await durchgehend im Backend, sync-Wrapper für Celery-Tasks
- TypeScript: Interfaces für alle API-Responses in
frontend/src/api/*.ts - Keine Tests: Aktuell kein automatisiertes Test-Suite vorhanden
Datenbank-Migrationen
# Neue Migration erstellen
docker compose exec backend alembic revision --autogenerate -m "beschreibung"
# Migrationen anwenden
docker compose exec backend alembic upgrade head
# Status prüfen
docker compose exec backend alembic current
Celery Task-Queues
| Queue | Worker | Concurrency | Tasks |
|---|---|---|---|
step_processing |
worker |
8 | process_step_file, render_order_line_task, dispatch_order_line_render |
asset_pipeline |
render-worker |
1 | render_step_thumbnail, regenerate_thumbnail, generate_gltf_geometry_task, generate_usd_master_task |
ai_validation |
worker |
8 | Azure AI Validierung |
Wichtig: asset_pipeline läuft mit concurrency=1, weil Blender single-threaded ist. Mehr parallele Tasks führen zu Abstürzen.
Task-Location: Aktive Implementierungen in backend/app/domains/pipeline/tasks/. backend/app/tasks/step_tasks.py ist ein 23-Zeilen Compatibility-Shim — dort keine Logik hinzufügen.
STEP-Processing-Pipeline
- Upload: STEP-Datei hochladen →
CadFile-Record erstellt →process_step_fileTask eingereiht - Metadata (
process_step_fileaufstep_processing):- STEP-Objekte extrahieren (OCC/cadquery, ~0.1s)
parsed_objectsin DB speichern- Status:
processing→ queutrender_step_thumbnail
- Thumbnail (
render_step_thumbnailaufasset_pipeline):- OCC/GMSH Tessellierung → GLB
- Blender Render → Thumbnail PNG
- Status:
completedoderfailed - Materialien auto-populated
- USD Export (
generate_usd_master_taskaufasset_pipeline):- OCC XCAF → USD mit Hierarchie, Materialien, Primvars
- Blender Cycles Render konsumiert USD direkt
- Still/Turntable Render (
render_order_line_taskaufstep_processing→ dispatches toasset_pipeline):- Konsumiert
usd_masterMediaAsset (nicht GLB) - Blender Cycles GPU → PNG/MP4
- Konsumiert
Material-Alias-System
- Materialien werden per STEP-Part-Name auf HartOMat-Bibliotheksmaterialien (
HARTOMAT_...) gemappt - Lookup-Reihenfolge: Alias-Tabelle zuerst, dann exakter
Material.name-Match, dann Pass-through - Alias-Seeding: Admin → "Seed Aliases" oder via
POST /api/materials/seed-aliases
Rollen
| Rolle | Berechtigungen |
|---|---|
global_admin |
Vollzugriff, Admin-Panel, alle Einstellungen, plattformweite Operationen |
tenant_admin |
Mandant verwalten, Nutzer im eigenen Mandant |
project_manager |
Aufträge, Analytics, Render-Trigger |
client |
Eigene Aufträge anlegen und einsehen |
Auth Guards: require_global_admin (platform-level), require_pm_or_above (admin/PM), get_current_user + manual check.
Wichtige API-Endpoints
POST /api/uploads/excel— Excel-Auftragsliste importierenPOST /api/orders/{id}/submit— Auftrag einreichenPOST /api/orders/{id}/dispatch-renders— Alle Render-Zeilen dispatchenGET /api/cad/{id}/thumbnail— Thumbnail (kein Auth, UUID opaque)POST /api/cad/{id}/generate-gltf-geometry— Geometry GLB Export triggernPOST /api/cad/{id}/generate-usd-master— USD Master Export triggernGET /api/cad/{id}/scene-manifest— Part-Keys mit Material-ZuweisungenPOST /api/admin/settings/regenerate-thumbnails— Alle Thumbnails neu rendernPOST /api/admin/settings/process-unprocessed— Unverarbeitete STEP-Dateien queuenGET /api/worker/activity— Letzte 30 STEP-Verarbeitungen (Status, Timing)
Bekannte Eigenheiten
- Backend-Port 8888 (nicht 8000 — war belegt)
- Tailwind CSS-Variablen:
bg-surfaceetc. funktionieren nicht mit/ opacity-Syntax wenn CSS-Variable einen Hex-Wert enthält. Stattdessenstyle={{ backgroundColor: 'var(--color-bg-surface)' }}verwenden. - Blender mm→m: STEP-Dateien sind in mm, Blender intern in m. Alle Import-Scripts skalieren mit
0.001. - USD Koordinaten: OCC Z-up → USD Y-up Transformation via Matrix auf
/Root/AssemblyXform. settings_persistence: Admin-Einstellungen werden via direktem SQL-UPDATE gespeichert (nicht ORM-Mutation), da SQLAlchemy bei key-value-Stores keine Mutation trackt.- Prim-Namen: USD Prim-Namen dürfen nicht mit Ziffern beginnen.
p_-Prefix wird automatisch für Teile wie439505389gesetzt.
Learnings-Pflicht
Nach jedem gelösten Problem oder jeder wichtigen Entscheidung:
→ Trag das Learning in LEARNINGS.md ein (Format: Datum | Kategorie | Problem → Lösung)
→ Commitiere LEARNINGS.md zusammen mit dem Fix: docs: learning erfasst - [kurzbeschreibung]