# Backend bei Mittwald hosten (Test-/Dauerbetrieb)

Stand: 2026-08-10 · Ziel: das **Backend** vom lokalen Rechner (ngrok) auf eine **Mittwald-Subdomain**
legen, damit das iPhone Berichte schnell und stabil lädt.

## Kurz-Fazit

**Ja, machbar – auch OHNE mStudio**, über die klassische **Agenturverwaltung / das Kundencenter**.
Gehostet wird nur das **Backend**, nicht die iOS-App.

- **Voraussetzung:** Add-on **„Node.js App"** über den **Softwaremanager im Kundencenter** buchen
  (~11 € netto/Monat, in jedem Tarif hinzubuchbar). HTTPS/Let's-Encrypt für die Subdomain inklusive
  (wichtig für iOS/ATS). mStudio oder die `mw`-CLI sind **nicht** nötig – Einrichtung läuft per **SSH**
  mit `mwservicectl` + `.mwservice.yaml`.
- **Was das Problem löst:** Die Langsamkeit kommt vom ngrok-Tunnel durch deine schwache
  Upload-Bandbreite. Auf Mittwald läuft das Backend direkt am Server → weg.
- **Produktion ohne tsx:** Es gibt jetzt einen **echten Build** (esbuild-Bundle → `node dist/…`), sodass
  in Produktion **kein tsx** mehr läuft. Verifiziert (der gebundelte Server bedient /health, /visits,
  /preparation korrekt).

## Was läuft wo

Zwei Node-Prozesse (beide gebündelt, gestartet mit **plain `node`**):

| Prozess | Start (Produktion) | Inbound? | Zweck |
|---|---|---|---|
| **HTTP-Server** | `node dist/server/http.mjs` | **Ja** → Subdomain | Token · Visits · Report · Anhang · Benutzer · Write-back. Damit spricht das iPhone. |
| **Voice-Worker** | `node dist/voice/worker.mjs start` | Nein (nur outbound) | LiveKit-Agents-Worker; verbindet sich **raus** zu LiveKit Cloud + LLM-APIs. |

- **Minimum gegen die Langsamkeit:** nur den **HTTP-Server** hochziehen (Voice läuft über LiveKit
  Cloud, nicht über deine Bandbreite).
- **„Always on":** beide Prozesse (zwei `mwservice`-Services **oder** PM2 in einem Service).

## Produktions-Build (kein tsx mehr)

Neu im Repo (`packages/agent`):
- `pnpm --filter @adva/agent build` → **esbuild** bündelt zu `dist/server/http.mjs` +
  `dist/voice/worker.mjs`. `@adva/schemas` wird eingebettet, echte npm-Deps bleiben external
  (aus `node_modules` zur Laufzeit). Start: `node dist/server/http.mjs` bzw.
  `node dist/voice/worker.mjs start` (Skripte `start:server` / `start:worker`).
- Dev bleibt unverändert (`pnpm … run server`/`worker` via tsx).

> Warum Bundle statt `tsc`: Das Projekt nutzt `moduleResolution: "Bundler"`; `@adva/schemas` zeigt auf
> TS-Quelle. Der Bundle-Weg braucht daher **keine** Umstellung der Package-Exports und lässt den
> Dev-Workflow unangetastet. Die Bundles liegen bewusst auf `dist/{server,voice}/` (gleiche Tiefe wie
> `src/{server,voice}/`), damit die relativen Prompt-/Daten-Pfade weiter stimmen (getestet).

## Schritt für Schritt (klassischer Weg, ohne mStudio)

### 1) Add-on + Node-Version
- Kundencenter → **Softwaremanager** → Add-on **„Node.js App"** buchen.
- Node-Version **22 LTS** (≥ 20 reicht; lokal lief 24).

### 2) Code auf den Space
Per SSH ins `html`-Verzeichnis, App-Ordner anlegen, Code holen:
```bash
cd ~/html/<APP-ORDNER>
git clone <repo> .            # oder per SFTP/rsync hochladen
corepack enable && corepack prepare pnpm@9.15.9 --activate
pnpm install                  # installiert auch esbuild (Build) + Runtime-Deps
pnpm --filter @adva/agent build   # erzeugt dist/server/http.mjs + dist/voice/worker.mjs
```

### 3) Secrets als `.env`
`~/html/<APP-ORDNER>/packages/agent/.env` (dotenv lädt es; **nie committen**):
```
LLM_PROVIDER=anthropic
LLM_MODEL=claude-sonnet-5
ANTHROPIC_API_KEY=...
XAI_API_KEY=...
LIVEKIT_URL=...
LIVEKIT_API_KEY=...
LIVEKIT_API_SECRET=...
VOICE_MODEL=grok-voice-fast-1.0
VOICE_NAME=carina
VOICE_IDLE_TIMEOUT_S=120
```

### 4) HTTP-Server als Service
Vorlage: [`deploy/mwservice.server.yaml`](../deploy/mwservice.server.yaml) → als `.mwservice.yaml`
nach `packages/agent/` kopieren (oder `mwservicectl create` interaktiv, Werte übernehmen). Der Server
hört automatisch auf `process.env.PORT`, das Mittwald setzt und auf die Subdomain mappt.
```bash
cd ~/html/<APP-ORDNER>/packages/agent
mwservicectl enable && mwservicectl start
mwservicectl status
```

### 5) Subdomain
Kundencenter → **Domains** → Subdomain anlegen (z. B. `advademo.<domain>.de`) und **auf das
App-Verzeichnis** zeigen lassen. HTTPS aktiviert Mittwald automatisch.

### 6) (Optional) Voice-Worker
Zwei Wege:
- **Zweiter Service:** [`deploy/mwservice.worker.yaml`](../deploy/mwservice.worker.yaml) in ein
  eigenes Service-Verzeichnis als `.mwservice.yaml`, dann `mwservicectl enable && start`.
- **PM2 (beide in einem Service):** [`deploy/ecosystem.config.cjs`](../deploy/ecosystem.config.cjs),
  Entrypoint `pm2 start deploy/ecosystem.config.cjs --no-daemon`.

### 7) iOS-App auf die Subdomain
`ADVA_BASE_URL` auf `https://<subdomain>` setzen (Info.plist / xcodegen `info:`), **ohne** Port. Neu
bauen. ATS ist zufrieden (echtes HTTPS).

### 8) Testen
```bash
curl https://<subdomain>/health     # -> { "data": { "ok": true } }
curl https://<subdomain>/visits      # -> Besuchsliste
```

## Stolpersteine / Caveats

- **Zwei Prozesse:** Ein Service = ein Entrypoint → zwei Services **oder** PM2 (Schritt 6).
- **Native Module des Workers:** `@livekit/rtc-node` (+ ggf. silero) bringen native Linux-Binaries.
  Nach dem Build einmal `node dist/voice/worker.mjs start` laufen lassen und prüfen, ob er ohne
  Binary-/Modell-Fehler startet. (Der HTTP-Server hat diese Abhängigkeit nicht – er lief im Test sauber.)
- **Runtime-Deps müssen da sein:** Das Bundle referenziert npm-Deps extern → `node_modules` muss auf
  dem Server vorhanden sein (`pnpm install`). tsx/esbuild/vitest sind nur Build-/Dev-Deps.
- **Kein Auto-Restart** nach Code-Änderung: `pnpm … build` erneut, dann `mwservicectl restart` (bzw. PM2 reload).
- **Persistenz:** Anhänge/`report.generated.json` unter `data/…` – App-Verzeichnis ist persistent.
  Bei Bedarf `DATA_DIR` (absoluter Pfad) in der `.mwservice.yaml`/`.env` setzen.

## Quellen
- [mittwald Developer – Node.js Workloads](https://developer.mittwald.de/docs/v2/platform/workloads/nodejs/)
- [mittwald FAQ – Node.js App einrichten (klassisch, Kundencenter)](https://www.mittwald.de/faq/tipps-und-tricks/node-js/node-js-app-einrichtung)
- [mittwald Developer – Node.js/Container Migration](https://developer.mittwald.de/docs/v2/guides/apps/nodejs-container-migration/)
