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).
46 lines
2.3 KiB
Markdown
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.
|