# 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 ```bash # 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 ``` hartomat/ ├── 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 ```bash # 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 1. **Upload**: STEP-Datei hochladen → `CadFile`-Record erstellt → `process_step_file` Task eingereiht 2. **Metadata** (`process_step_file` auf `step_processing`): - STEP-Objekte extrahieren (OCC/cadquery, ~0.1s) - `parsed_objects` in DB speichern - Status: `processing` → queut `render_step_thumbnail` 3. **Thumbnail** (`render_step_thumbnail` auf `asset_pipeline`): - OCC/GMSH Tessellierung → GLB - Blender Render → Thumbnail PNG - Status: `completed` oder `failed` - Materialien auto-populated 4. **USD Export** (`generate_usd_master_task` auf `asset_pipeline`): - OCC XCAF → USD mit Hierarchie, Materialien, Primvars - Blender Cycles Render konsumiert USD direkt 5. **Still/Turntable Render** (`render_order_line_task` auf `step_processing` → dispatches to `asset_pipeline`): - Konsumiert `usd_master` MediaAsset (nicht GLB) - Blender Cycles GPU → PNG/MP4 ## 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 importieren - `POST /api/orders/{id}/submit` — Auftrag einreichen - `POST /api/orders/{id}/dispatch-renders` — Alle Render-Zeilen dispatchen - `GET /api/cad/{id}/thumbnail` — Thumbnail (kein Auth, UUID opaque) - `POST /api/cad/{id}/generate-gltf-geometry` — Geometry GLB Export triggern - `POST /api/cad/{id}/generate-usd-master` — USD Master Export triggern - `GET /api/cad/{id}/scene-manifest` — Part-Keys mit Material-Zuweisungen - `POST /api/admin/settings/regenerate-thumbnails` — Alle Thumbnails neu rendern - `POST /api/admin/settings/process-unprocessed` — Unverarbeitete STEP-Dateien queuen - `GET /api/worker/activity` — Letzte 30 STEP-Verarbeitungen (Status, Timing) ## Bekannte Eigenheiten - **Backend-Port 8888** (nicht 8000 — war belegt) - **Tailwind CSS-Variablen**: `bg-surface` etc. funktionieren nicht mit `/ opacity`-Syntax wenn CSS-Variable einen Hex-Wert enthält. Stattdessen `style={{ 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/Assembly` Xform. - **`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 wie `439505389` gesetzt. ## 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]`