# Tauri-Migration + Compute-Boundary — Aufgabe für nächste Instanz

**Entscheidung (fix, 2026-07-01):** Browser-CAD → **Desktop Tauri-App mit Rust-Backend + wgpu-Rendering.**

**Grund:** komplexe Möbel mit vielen Polygonen (100k+) + mehrere parallele rechenintensive Ops → WebGL/three.js wird zum Blocker. **wgpu** (low-level GPU-API) + Rust-Compute skaliert native.

**Scope:** Desktop-only Release (Milestone 1). WASM-Fallback für Browser später wenn gebraucht.

**Rendering-Engine:** three.js → **wgpu** (Milestone 2)

---

## Aufgabe: Shell aufsetzen + Compute-Boundary + erste Op migrieren

### Schritt 0 — Compute-Boundary (TS-Kontrakt)

**Neu:** `src/compute/index.ts` — die einzige Stelle, durch die alle rechenintensiven Ops laufen.

```typescript
// src/compute/index.ts — einheitliche Schnittstelle
export async function computeKernel2D(op: 'offset'|'trim', …): Promise<Polyline[]> { … }
export async function detectRooms(…): Promise<Room[]> { … }
export async function computeJoins(…): Promise<JoinInfo[]> { … }  // ← erste Op
export async function parseShapeFromDwg(…): Promise<DwgGeometry> { … }
```

**Hinter der Boundary:**
- Erst Tauri-invoke zu Rust `#[tauri::command]`
- Fallback auf lokale TS-Impl (bleibt unberührt, bis Rust stabil)
- `catch(err) → console.warn('Rust failed, using TS fallback'); return tsImpl(…)`

**Effekt:** Aufrufort im Code bleibt stabil; Caller sieht nicht, ob Op schon in Rust ist oder noch TS.

---

### Schritt 1 — Tauri-Shell aufsetzen

**Struktur:**
```
repo/
  src-tauri/              ← neue Rust-Seite (Tauri-Konvention)
    src/
      main.rs             ← Tauri window + invoke handlers
      geometry.rs         ← compute_joins() + weitere Ops später
      ...
    Cargo.toml
  src/                    ← React/TS (unverändert)
    compute/
      index.ts            ← Compute-Boundary
    ...
  vite.config.ts          ← Tauri plugin integrieren
  package.json            ← tauri scripts
```

**Setup:**
1. `cargo init --name cad-tauri src-tauri` (oder `src-tauri` manuell anlegen)
2. `Cargo.toml`: Tauri v2 einbinden mit Feature `webkit2gtk-6.0` (GTK4)
   ```toml
   [dependencies]
   tauri = { version = "2", features = ["webkit2gtk-6.0"] }
   serde = { version = "1.0", features = ["derive"] }
   serde_json = "1.0"
   ```
3. `src-tauri/src/main.rs`: Minimal-Fenster, invoke-Handler registrieren
   ```rust
   #[tauri::command]
   async fn compute_joins(input: JoinInput) -> Result<JoinOutput, String> {
       // Rust-Impl
       geometry::compute_joins(input).map_err(|e| e.to_string())
   }

   #[cfg_attr(mobile, tauri::mobile_entry_point)]
   pub fn run() {
       tauri::Builder::default()
           .invoke_handler(tauri::generate_handler![compute_joins])
           .run(tauri::generate_context!())
           .expect("error while running tauri application");
   }
   ```
4. `vite.config.ts`: Tauri plugin + dev-server-Integration
   ```typescript
   import { defineConfig } from 'vite'
   import react from '@vitejs/plugin-react'
   export default defineConfig({
     plugins: [react()],
     server: { port: 5173 }  // Tauri dev zeigt hier drauf
   })
   ```
5. `package.json`: Tauri scripts hinzufügen
   ```json
   "scripts": {
     "tauri": "tauri",
     "tauri:dev": "tauri dev",
     "tauri:build": "tauri build"
   }
   ```

---

### Schritt 2 — Erste Op migrieren: `computeJoins` (Wand-Eckverbindungen)

**Warum `computeJoins` zuerst?**
- Läuft häufig (bei jedem Wall-Edit)
- Klein und fokussiert (~50 Zeilen Kernlogik)
- Proof-of-Concept für Tauri-invoke-Flow
- Danach `kernel2d` parallel hochfahren

**Rust-Impl:** `src-tauri/src/geometry.rs`

```rust
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct Vec2 { pub x: f64, pub y: f64 }

#[derive(Serialize, Deserialize)]
pub struct WallJoinInput {
    pub walls: Vec<Wall>,
    pub joints: Vec<(usize, usize)>,  // wall indices
}

#[derive(Serialize, Deserialize)]
pub struct JoinInfo { /* … */ }

pub fn compute_joins(input: WallJoinInput) -> Result<Vec<JoinInfo>, Box<dyn std::error::Error>> {
    // Port der Logik aus src/model/joins.ts
    // L-Ecken, T-Stösse, +-Kreuzungen
    Ok(vec![])  // Placeholder
}
```

**TS-Fallback bleibt:** `src/model/joins.ts` (LS vor Rust-Port)

**Compute-Boundary:** `src/compute/index.ts`
```typescript
export async function computeJoins(walls: Wall[], joints: Array<[number, number]>): Promise<JoinInfo[]> {
  try {
    return await invoke<JoinInfo[]>('compute_joins', { walls, joints });
  } catch (err) {
    console.warn('Rust compute_joins failed, using TS fallback:', err);
    return joinsTS(walls, joints);  // Fallback
  }
}
```

---

### Schritt 3 — Migrations-Parität testen

**Test-Fixtures:**
- Aus `src/model/sampleProject.ts` exportieren: Wand-Arrays mit bekannten L/T/±-Konfigurationen
- Rust-Unit-Tests: gleiche Fixtures → gleiche JoinInfo-Outputs
- Vergleich: `actual == expected`

**Beispiel (Rust):**
```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_l_corner() {
        let input = WallJoinInput { /* L-shaped walls */ };
        let result = compute_joins(input).unwrap();
        assert_eq!(result[0].kind, JoinKind::LCorner);
    }
}
```

---

### Schritt 4 — Vite/Tauri-Integration

**Dev-Workflow:**
```bash
npm run tauri:dev
# → Vite dev-server (localhost:5173) lädt React-App
# → Tauri-window zeigt auf :5173
# → invoke() ruft Rust-Commands auf
```

**Build-Workflow:**
```bash
npm run build  # Vite → dist/
npm run tauri:build  # Tauri packt dist/ + Rust-Binary
```

---

## Deliverable (Proof-of-Concept)

**Git-Stand nach dieser Aufgabe:**

- [ ] `src-tauri/` Verzeichnis mit `Cargo.toml` + `src/main.rs` + `src/geometry.rs`
- [ ] `Cargo.toml` buildet sauber (`cargo check` 0 Fehler)
- [ ] `src/compute/index.ts` mit `computeJoins()` Schnittstelle (invoke + TS-fallback)
- [ ] Rust `compute_joins()` implementiert, Tests pass (`cargo test`)
- [ ] `package.json` `tauri` scripts hinzugefügt
- [ ] **App läuft:** `npm run tauri:dev` → Tauri-Fenster öffnet, Wand-Edit triggert Rust-Op, Output identisch TS-Version
- [ ] **Trace-Scan sauber** (kein TS/Rust-Code übrig, beide Impl. aktiv)
- [ ] HANDOVER.md aktualisiert: `computeJoins` migriert, nächste Ops in Queue

**Verification:**
```bash
# Build-Check
cargo check  # 0 Fehler

# Rust-Tests
cargo test

# App end-to-end
npm run tauri:dev
# → Wand zeichnen + editieren → computeJoins() über Rust aufgerufen
# → Plan + 3D aktualisiert wie vorher
```

---

## Nächste Ops (Priorisierung)

Nach `computeJoins` stabil:

1. **`kernel2d`** (Offset/Trim/Extend) — großer Hebel, läuft häufig
2. **DXF/DWG-Parser** (Geometrie) — heavy, aber niedrige Frequenz
3. **`detectRooms`** (SIA-Raumerkennung) — async, kann auf Hintergrund ziehen
4. **`booleanOps`** (Union/Differenz/Schnitt) — Kandidat für später

---

## Offene Punkte (NICHT jetzt)

- **GPU-Compute (wgpu):** Erst nach CPU-Ops stabil (kernel2d, joins, parsing)
- **WASM-Fallback:** Nur wenn Browser-Support nötig wird
- **Flatpak-Distribution:** Nach Tauri-Shell stable + erste Ops migriert

---

## Referenzen

- Tauri v2 Docs: https://tauri.app/v1/guides/getting-started/prerequisites
- Serde: https://serde.rs/
- CONVENTIONS.md: Identifiers englisch, UI-Text via `t()`, …
- Commit-Regel: kein AI-Attribution im Repo
