kaizen-app/README.md
Bruno Deanoz 44c17b6f9f feat: wire chat to the real Kaizen backend (in-app login + streaming)
Replaces the Phase-0 fakeReply mock with the real v1 API. Deployment-agnostic:
one binary, one Authorization: Bearer contract, server-URL field switches between
the official instance and any self-host.

- auth/LoginScreen: server-URL + email + password -> POST /api/v1/auth/token
- net/SecureStore: kzn_ token in EncryptedSharedPreferences (KeyStore AES-256-GCM)
- net/SessionViewModel: snapshot-state login/logout routing, restores on launch
- net/KaizenApi: POST /api/v1/chat streaming + GET /api/v1/me for the default model
- net/StreamConsumer: Kotlin port of lib/chat/stream-consumer.ts (JVM-unit-tested)
- deps: okhttp, kotlinx-serialization, security-crypto; INTERNET permission

Code-complete; not yet built/run on device (no Android SDK on the dev Mac).
2026-06-19 01:04:55 +02:00

46 lines
2.3 KiB
Markdown

# Kaizen — Android
Native Android-App für Kaizen (Jetpack Compose + Kotlin). Kein WebView, kein Tauri.
## Phase 1 — echtes Backend (aktiv)
Der Feel-Prototyp redet jetzt mit dem **echten Kaizen-Backend** — echte, gestreamte
Antworten statt `fakeReply`. Die App ist **deployment-agnostisch**: ein Binary, das auf
die offizielle Instanz ODER jeden Self-Host zeigt, über einen einheitlichen
`Authorization: Bearer`-Contract. SaaS vs. Self-Host ist nur „welche Base-URL".
Drin:
- **In-App-Login** (`auth/LoginScreen.kt`): Server-URL (Default = offizielle Instanz,
editierbar = die „offiziell/Self-Host"-Adresse) + E-Mail + Passwort →
`POST {baseUrl}/api/v1/auth/token``kzn_`-Token. Kein Token-Copy-Paste.
- **Sichere Token-Ablage** (`net/SecureStore.kt`): `EncryptedSharedPreferences`
(AES-256-GCM, Schlüssel im Android-KeyStore/StrongBox) — der Token liegt nie im
Klartext, auch nicht auf gerooteten Geräten.
- **Modell vom Server** (`net/SessionViewModel.kt`): nach dem Login holt die App per
`GET /api/v1/me` das vom Nutzer unter `/settings/models` gewählte Default-Modell —
kein hartgecodetes Modell.
- **Echtes Streaming** (`net/KaizenApi.kt` + `net/StreamConsumer.kt`): `POST /api/v1/chat`,
liest den `text/plain`-Chunked-Stream inkrementell und strippt die Sentinels
(Port von `lib/chat/stream-consumer.ts` aus dem Backend, JVM-unit-getestet).
- Design + Haptik + Orb unverändert — **nur die Datenquelle hat sich geändert**.
Bewusst **noch nicht** drin (siehe `LATER.md`): Conversation-History vom Server,
Passkey-Login nativ, Bild/Video, Biometric-Lock, WebSocket-Streaming.
## Bauen & laufen
> **Wichtig:** Auf dem **echten S25 Ultra** laufen lassen, nicht im Emulator —
> der Emulator kann keine echte Haptik, und genau die wollen wir fühlen.
1. Projekt in Android Studio öffnen, **Gradle syncen** (neue Deps: OkHttp,
kotlinx-serialization, security-crypto + INTERNET-Permission).
2. S25 Ultra per **Wireless Debugging** oder USB verbinden.
3. Run ▶ auf das Gerät → Login-Screen erscheint. Server-URL prüfen, einloggen.
`DEFAULT_BASE_URL` (`net/ServerConfig.kt`) ist die vorausgefüllte Instanz-Adresse —
bei Domainwechsel hier anpassen.
## Der Test
Eine Woche nutzen. Geht der Finger anfangen hierher statt zu Gemini → wir bauen voll
aus (History, Passkey, Medien = Phase 2). Wenn nicht → wir wissen billig, woran's liegt.