# Aussendienst Voice-Agent (Backend-PoC)

Backend für eine iOS-Voice-App im Aussendienst: pro Kundenbesuch **(1)** Vorbereitung per Sprache
aus dem CRM-Stand, **(2)** ein Dokumentations-Gespräch, **(3)** deterministische Extraktion eines
**freigabepflichtigen Besuchsberichts**. Zielsystem: **CAS genesisWorld** (GGUID/Hex).

> **PoC-Grenze:** Kein CRM-Write-back. Der PoC endet beim **freigegebenen `report.json`**.
> Datenquelle sind lokale JSON-Fixtures unter [`data/`](data).

## Architektur

**Hybrid-Ansatz:** Das Live-Gespräch läuft als Speech-to-Speech (xAI Grok Voice über LiveKit);
die strukturierte Extraktion ist ein **separater, deterministischer Text-Schritt danach** – nie im
Realtime-Loop.

Kernprinzip der Extraktion – Trennung **LLM vs. deterministisch**:
- **LLM (interpretiert):** 4 Spezialisten (`aufgaben`, `verkaufschancen`, `kundenanfragen`,
  `naechste_schritte`) + Zusammenfassung. Prompts als editierbare Dateien in
  [`packages/agent/prompts/`](packages/agent/prompts).
- **Deterministisch (Code, garantiert korrekt):** Bearbeiter-Resolver (Name→GGUID, inaktive
  ausgeschlossen), Coverage-Checker (offene Agenda − adressiert → `offen_geblieben`), Assembler
  (temp_ids, Verknüpfung, Zod-Validierung).

Provider-agnostisch (Vercel AI SDK): `LLM_PROVIDER=xai|anthropic`.

## Struktur

```
packages/
  schemas/   # Zod-Schemas + TS-Typen der 4 Artefakte (Single Source of Truth)
  agent/     # Extraktions-Pipeline, Voice-Worker, Token-/Freigabe-Server
data/        # JSON-Fixtures (benutzer.json, visits/<id>/{preparation,transkript,report}.json)
```
Details je Package in dessen `CLAUDE.md`.

## Setup

```bash
pnpm install
cp "packages/agent/.env.example" "packages/agent/.env"   # dann Keys eintragen
```

`.env` (nie committen): `XAI_API_KEY` bzw. `ANTHROPIC_API_KEY` (Extraktion) sowie
`LIVEKIT_URL / LIVEKIT_API_KEY / LIVEKIT_API_SECRET` (Voice).

## Befehle

```bash
pnpm test                                                # alle Tests (Turbo)
pnpm --filter @adva/agent extract 2026-08-03_bauzentrum-nord   # Text-Extraktion (schreibt report.generated.json)
pnpm --filter @adva/agent server                         # Token- + Freigabe-Server (braucht LIVEKIT_*)
pnpm --filter @adva/agent worker                         # Voice-Worker (braucht LIVEKIT_* + XAI_API_KEY + Client)
```

## Die vier Daten-Artefakte

| Datei | Rolle |
|---|---|
| `benutzer.json` | Benutzerverzeichnis (Bearbeiter-Auflösung, `aktiv:false` ausgeschlossen) |
| `visits/<id>/preparation.json` | CRM-Stand (Input) inkl. `delta` + Geo-Koordinaten |
| `visits/<id>/transkript.json` | Gespräch (Turns) – Fixture bzw. zur Laufzeit erzeugt |
| `visits/<id>/report.json` | Besuchsbericht (Output), Golden-Referenz |

> Live-Läufe schreiben nach `*.generated.json` – die Golden-Fixtures bleiben unangetastet.

## HTTP-Endpunkte (für die iOS-App)

- `POST /token` → LiveKit-JWT. Body: `{ visitId, mode: "vorbereitung"|"dokumentation", identity }`.
- `POST /visits/:id/freigabe` → setzt `status: freigegeben` + `freigabe`. Body: `{ durch, am? }`.

## Status

Phasen 1–4 fertig (Schemas · Extraktion · Voice · Freigabe). Die PoC-Kernbehauptung ist per
Live-Lauf bewiesen. Offen: echter End-to-End-Voice-Test (LiveKit-Cloud-Creds + xAI-Guthaben +
iOS-Client) und das separate iOS-Frontend (siehe [`voice agent frontend handoff.md`](voice%20agent%20frontend%20handoff.md)).
