Files

182 lines
8.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```
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 (001062+)
│ └── 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]`