# Architektur-Pivot: Tauri + Rust-Backend (2026-07-01) ## Entscheidung **Alte Welt:** Browser-CAD (React/Vite + WebGL/three.js) **Neue Welt:** Desktop Tauri-App (React/Vite Frontend + Rust-Backend + **wgpu 3D-Rendering**) **Grund:** Komplexe Möbel mit vielen Polygonen (100k+) + mehrere parallele rechenintensive Ops → WebGL/three.js wird zum Bottleneck. **wgpu** (low-level GPU-API auf Vulkan/Metal/DX12) + Rust-Compute skaliert native. **Scope:** Desktop-only Release (Milestone 1). WASM-Fallback für Browser später wenn gebraucht. --- ## Post-Migration Stack ### Frontend (React/Vite — Komponenten + State, unverändert) ``` src/ App.tsx ← Shell-Komponente compute/index.ts ← Compute-Boundary (neu) model/types.ts ← Semantisches Modell commands/ ← Befehlssystem panels/ ← UI-Panels plan/PlanView.tsx ← 2D-SVG-Rendering viewport/Viewport3D.tsx ← three.js 3D-Display ui/ ← Topbar, Dialogs, etc. state/ ← Redux-Slices (project, selection, view, layout) ... ``` **Rolle:** User-Input-Handling, 2D/3D-Darstellung (Display-Layer), State-Management. ### Backend (Rust/Tauri — neu) ``` src-tauri/ src/ main.rs ← Tauri window + invoke-handler registration geometry.rs ← compute_joins(), kernel2d(), etc. parsers/ dwg.rs ← DXF/DWG-Geometrie-Parsing dxf.rs sia/ room_detection.rs ← detectRooms() (SIA-416) ... Cargo.toml ← Dependencies (serde, tauri, …) ``` **Rolle:** Rechenintensive Ops, Geometrie-Kernel, Parsing, SIA-Raumerkennung. ### IPC: Tauri invoke (async, serde) ```typescript // Frontend ruft Rust auf const result = await invoke('compute_joins', { walls, joints }); // Rust bearbeitet + serialisiert Ergebnis #[tauri::command] async fn compute_joins(input: JoinInput) -> Result { geometry::compute_joins(input).map_err(|e| e.to_string()) } ``` --- ## Compute-Boundary (Key Design) **Neue Datei:** `src/compute/index.ts` — einziger Eingang für rechenintensive Ops. ```typescript // Beispiel-Schnittstellen export async function computeJoins(walls: Wall[], joints: Array<[number, number]>): Promise { … } export async function computeKernel2D(op: 'offset'|'trim', geom: Polyline, …): Promise { … } export async function detectRooms(…): Promise { … } export async function parseShapeFromDwg(…): Promise { … } ``` **Hinter der Boundary:** 1. Versuche Tauri invoke zu Rust (`#[tauri::command]`) 2. Fallback auf lokale TS-Impl wenn Rust nicht verfügbar (während Migration) **Effekt:** Aufrufort im Code bleibt stabil; Caller sieht nicht, ob Op schon in Rust ist oder noch TS. **Migrationsfluss:** ``` 1. TS-Impl existiert (z.B. src/model/joins.ts) 2. Neue Op in Compute-Boundary mit Invoke+Fallback 3. Parallel: Rust-Impl in src-tauri/src/geometry.rs 4. Tests: Rust-Output == TS-Output (Parität) 5. TS-Impl bleibt (Fallback, wird nicht entfernt bis Rust stable) 6. Eventuell: TS-Impl löschen wenn Rust bewährt ``` --- ## Dev-Workflow (post-Tauri) ### Development ```bash # Terminal 1: Vite dev-server npm run dev # localhost:5173 # Terminal 2: Tauri dev npm run tauri:dev # öffnet Tauri-Fenster, zeigt auf localhost:5173 # Rust hot-reload + TS hot-reload gleichzeitig ``` **Voraussetzungen:** - Node.js + npm (wie heute) - Rust + Cargo (neu) - Tauri CLI: `npm install -D @tauri-apps/cli` ### Build ```bash # Single command npm run tauri:build # Erzeugt: # - Windows: src-tauri/target/release/cad.exe # - macOS: src-tauri/target/release/bundle/macos/cad.app # - Linux: src-tauri/target/release/bundle/deb/cad_*.deb (oder Flatpak) ``` ### Testing ```bash # Rust-Unit-Tests cargo test # in src-tauri/ # TS-Tests (unverändert) npm run test # Integration-Test: App starten + Aktion prüfen npm run tauri:dev # manuell testen oder Puppeteer-Probe erweitern ``` --- ## GPU-Strategy (für später) **Milestone 1 (jetzt):** CPU-Ops in Rust (kernel2d, joins, parsing, SIA). **Milestone 2 (später):** GPU-Compute via wgpu - Tauri + wgpu Renderer (optional, nicht erforderlich) - ODER drei.js bleibt, Rust handelt CPU-Ops, three.js handelt Display - GPU-Heavy-Ops (z.B. große Boolean-Operationen) können in wgpu laufen, aber MVP braucht das nicht **Aktueller Plan:** three.js bleibt für 3D-Display (skaliert ausreichend für Möbel-Geometrie mit Instancing + LOD). --- ## Migration Strategy: Ops nach Priorisierung **Phase 1 (aktuell — Tauri-Shell + Proof-of-Concept):** - [ ] `computeJoins` (Wand-Eckverbindungen) → Rust - Gründe: klein, häufig, zeigt invoke-Flow **Phase 2 (nächst):** - [ ] `kernel2d` (Offset/Trim/Extend/Fillet) → Rust - Gründe: Rechenlast ⭐⭐, Frequenz hoch - [ ] DXF/DWG-Parser → Rust (Geometrie-Extraktion) - Gründe: Rechenlast ⭐⭐, Frequenz mittel (Import-Dialog) **Phase 3 (später):** - [ ] `detectRooms` (SIA-416 Raumerkennung) → Rust - Gründe: Rechenlast ⭐, async-freundlich - [ ] `booleanOps` (Union/Differenz/Schnitt) → Rust - Gründe: Rechenlast ⭐⭐, Frequenz gering (ad-hoc) --- ## Folgen für bestehenden Code ### Was ändert sich NICHT - `src/model/types.ts` — semantisches Modell bleibt in TS (Frontend kennt es) - `src/state/` — Redux-Store unverändert - `src/ui/` — Komponenten unverändert - `src/plan/PlanView.tsx` — SVG-Rendering unverändert - `src/viewport/Viewport3D.tsx` — three.js-Rendering unverändert - `src/commands/` — Befehlssystem unverändert ### Was ändert sich - **Neue `src/compute/index.ts`** — alle rechenintensiven Ops laufen durch hier - **Neue `src-tauri/`** — Rust-Backend - **Vite-Config:** Tauri plugin hinzufügen - **Package.json:** tauri scripts hinzufügen - **Build-Prozess:** `npm run tauri:build` statt `npm run build` ### Was wird migriert (schrittweise) - `src/model/joins.ts` → `src-tauri/src/geometry.rs` (Phase 1) - `src/geometry/kernel2d.ts` → `src-tauri/src/geometry.rs` (Phase 2) - `src/io/{dxfParser, dwgParser}.ts` → `src-tauri/src/parsers/` (Phase 2) - `src/geometry/{roomArea, roomBoundary}.ts` → `src-tauri/src/sia/room_detection.rs` (Phase 3) - `src/editors/booleanOps.ts` → `src-tauri/src/geometry.rs` (Phase 3) **Wichtig:** TS-Versionen bleiben als Fallback (nicht gelöscht). --- ## Distribution (später) ### Desktop Binaries (post-Tauri) - **Windows:** `.exe` (standalone executable) - **macOS:** `.app` bundle (code-signed) - **Linux:** `.deb` package ODER **Flatpak** (preferred) - Flatpak = moderne WebKitGTK6 immer dabei, unabhängig von Distro-Alter ### Browser (wenn gebraucht) - **WASM-Fallback** für `src/compute/` Ops (Rust → WASM via wasm-bindgen) - Later-phase feature, nicht Milestone 1 --- ## Technische Details ### Serialisierung (TS ↔ Rust) **serde + serde_json** für Geometrie-Typen: ```rust // Rust #[derive(Serialize, Deserialize)] pub struct Vec2 { pub x: f64, pub y: f64 } #[derive(Serialize, Deserialize)] pub struct Wall { pub id: String, pub start: Vec2, pub end: Vec2, // … } ``` ```typescript // TS (type-safe invoke) interface Vec2 { x: number; y: number } interface Wall { id: string; start: Vec2; end: Vec2; /* … */ } await invoke('compute_joins', { walls: Wall[] }) ``` ### Tauri Security (default) - Invoke-Handler sind Rust-side validiert - Whitelist-Makro (`#[tauri::command]`) registered nur explizit erlaubte Functions - CORS/CSP Policy default secure - Keine arbitrary-Script-Execution (native app) --- ## Abhängigkeiten (neu post-Tauri) ### Frontend (npm) - Bestehende: react, vite, three.js, redux, etc. - Neu: `@tauri-apps/api` (JS-SDK für invoke) - Optional später: `@tauri-apps/cli` dev-dependency (bereits in package.json) ### Backend (Cargo) ```toml [dependencies] tauri = { version = "2", features = ["webkit2gtk-6.0"] } # GTK4 serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" # später: wgpu, delaunator, opencascade-sys, etc. ``` ### System - Rust 1.70+ - GTK4 dev libraries (Linux only, auto-handled by Tauri) - Xcode Command Line Tools (macOS, auto-checked) --- ## Next Steps (Koordination) **Aufgabe für nächste Phase:** → Siehe `docs/design/tauri-migration-plan.md` (Schritt-für-Schritt, vier parallele Agents) **HANDOVER.md:** wird aktualisiert nach Tauri-Shell stabil. --- ## FAQ **Q: Läuft die App noch im Browser?** A: Nein (Milestone 1). Desktop-only. WASM-Fallback für Browser später wenn gebraucht. **Q: Was passiert mit dem existing TS-Code?** A: Bleibt unverändert (außer neue Compute-Boundary). TS-Implementierungen = Fallback bis Rust stabil. **Q: Muss ich Rust können um das Projekt zu verstehen?** A: Nein. Frontend bleibt React/TS. Rust ist "blackbox" hinter invoke. Aber bei Rust-Bugs muss man rein. **Q: Wann ist Tauri-Shell fertig?** A: Nach den vier Agents (Schritt 1–4 in tauri-migration-plan.md), ~1–2 Wochen. **Q: Kann ich lokal testen?** A: Ja, `npm run tauri:dev` öffnet lokale App. Alles wie heute, nur Rust hinten dran.