Update Pixel Watch 2 testing status
The project plan has been updated to reflect the successful testing of the Pixel Watch 2 hardware. The plan now includes details about ADB-over-WiFi pairing and testing against a local development server. It also mentions the successful manual verification of the end-to-end flow on the real device. Further testing, including LTE mode, doze mode, and long-term foreground service behavior, is still pending.
This commit is contained in:
+8
-6
@@ -117,7 +117,7 @@ UI-unabhängige Tests laufen auf der JVM (keine Emulator-Runtime). Importe von `
|
|||||||
|
|
||||||
#### 1a. Pixel Watch App (Wear OS / Kotlin) — primäres Entwicklungsziel
|
#### 1a. Pixel Watch App (Wear OS / Kotlin) — primäres Entwicklungsziel
|
||||||
|
|
||||||
**Ist-Stand (2026-04-23):** Vertikaler PoC end-to-end lauffähig auf Wear-OS-34-AVD. Record-Button → 5 s MediaRecorder (MPEG-4/AAC-LC 16 kHz 64 kbps mono) → Multipart-`POST /api/upload` mit `X-API-Key` → Server schreibt `.m4a`, Whisper transkribiert, Ollama klassifiziert, `document.md` entsteht. Manuell verifiziert mit "Hallo, hallo" → korrekte Transkription + `oneliner.kind = empty` (Silence-Rule). Architektur-Unbekannte aus der vertikalen Scheibe (Audio-Codec-Kompatibilität, Cleartext-HTTP-Policy, Emulator-Mic, Wire-Vertrag) sind **gemessen**, nicht mehr spekulativ. Der PoC hat aber **bewusst** nicht: Fallliste, Marker-Dateien, `unsynced/`-Queue, Foreground Service, Retry-Backoff, Oneliner-Polling, Bluetooth-Headset, Neu/Fortsetzen-Flow — diese Features bleiben laut Plan zu bauen.
|
**Ist-Stand (2026-04-23):** Vertikaler PoC end-to-end lauffähig auf Wear-OS-34-AVD **und auf realer Pixel Watch 2** (Wear OS 5, ADB-over-WiFi-Pairing). Record-Button → 5 s MediaRecorder (MPEG-4/AAC-LC 16 kHz 64 kbps mono) → Multipart-`POST /api/upload` mit `X-API-Key` → Server schreibt `.m4a`, Whisper transkribiert, Ollama klassifiziert, `document.md` entsteht. Manuell verifiziert mit "Hallo, hallo" → korrekte Transkription + `oneliner.kind = empty` (Silence-Rule). Architektur-Unbekannte aus der vertikalen Scheibe (Audio-Codec-Kompatibilität, Cleartext-HTTP-Policy, Emulator-Mic, Wire-Vertrag) sind **gemessen**, nicht mehr spekulativ. Toolchain unterstützt beide Targets parallel: `build.gradle.kts` liest Gradle-CLI-Property `-Pdoctate.serverUrl=…` vor `local.properties` (damit Emulator auf `10.0.2.2:3000` und Watch auf `http://<laptop-lan-ip>:3000` ohne Dateitausch wechseln); `network_security_config.xml` whitelistet die LAN-IP zusätzlich zu `10.0.2.2` für Cleartext (Produktions-HTTPS bleibt via `base-config` gesperrt); `run.sh` hat ein `watch`/`emulator`-Target-Prefix plus `connect`/`devices`-Subkommandos und cacht die zuletzt gepairte Watch-Serial in `.watch_serial`. Der PoC hat aber **bewusst** nicht: Fallliste, Marker-Dateien, `unsynced/`-Queue, Foreground Service, Retry-Backoff, Oneliner-Polling, Bluetooth-Headset, Neu/Fortsetzen-Flow — diese Features bleiben laut Plan zu bauen.
|
||||||
|
|
||||||
**Funktion:**
|
**Funktion:**
|
||||||
- Audioaufnahme direkt auf der Watch (MediaRecorder, AAC/m4a)
|
- Audioaufnahme direkt auf der Watch (MediaRecorder, AAC/m4a)
|
||||||
@@ -317,7 +317,7 @@ Wenn Watch und Handy gekoppelt sind (klassisches Wear-OS-Pairing), *könnten* be
|
|||||||
|
|
||||||
#### 1c. Desktop-Clients (Linux / Windows) — erster nativer Client
|
#### 1c. Desktop-Clients (Linux / Windows) — erster nativer Client
|
||||||
|
|
||||||
**Ist-Stand:** Der Linux-Desktop-Client ist gebaut und funktioniert (`client-desktop/`). Er ist der **erste echte native Client überhaupt** — wurde vor der Watch-App gebaut, weil der Nutzer noch keine Pixel-Watch-Hardware hat und ein realer Client für API-Ergonomie-Tests (Retry, Content-Types, Auth-Fehlerpfade) nötig war.
|
**Ist-Stand:** Der Linux-Desktop-Client ist gebaut und funktioniert (`client-desktop/`). Er ist der **erste echte native Client überhaupt** — wurde vor der Watch-App gebaut, weil zu dem Zeitpunkt noch keine Pixel-Watch-Hardware verfügbar war und ein realer Client für API-Ergonomie-Tests (Retry, Content-Types, Auth-Fehlerpfade) nötig war. (Pixel Watch 2 Hardware eingetroffen am 2026-04-23.)
|
||||||
|
|
||||||
**Features (MVP):**
|
**Features (MVP):**
|
||||||
- Config-Panel beim Erststart (Server-URL + API-Key, TOML unter `~/.config/doctate/client.toml`)
|
- Config-Panel beim Erststart (Server-URL + API-Key, TOML unter `~/.config/doctate/client.toml`)
|
||||||
@@ -1156,6 +1156,7 @@ wiremock = "0.6"
|
|||||||
- [x] Fall-Übersicht: `GET /web/cases/{case_id}` rendert `case_page.html` mit Oneliner + Aktionen + inline-gerendertem Dokument (via `pulldown-cmark`); IDOR-geschützt via Session-Slug.
|
- [x] Fall-Übersicht: `GET /web/cases/{case_id}` rendert `case_page.html` mit Oneliner + Aktionen + inline-gerendertem Dokument (via `pulldown-cmark`); IDOR-geschützt via Session-Slug.
|
||||||
- [x] Einzel-Transkripte: `GET /web/cases/{case_id}/recordings` rendert `case_recordings.html` (ein Eintrag pro Aufnahme, Audio-Link pro Transkript).
|
- [x] Einzel-Transkripte: `GET /web/cases/{case_id}/recordings` rendert `case_recordings.html` (ein Eintrag pro Aufnahme, Audio-Link pro Transkript).
|
||||||
- [x] Audio-Streaming: `GET /web/audio/{user}/{case_id}/{filename}` (Cookie-Auth, Arzt eigene Dateien oder Admin) — HTTP-Range-Requests, `Accept-Ranges: bytes`, 206 Partial Content, Duration-Sidecar `{ts}.duration.txt` für HTML5-Player mit Seeking
|
- [x] Audio-Streaming: `GET /web/audio/{user}/{case_id}/{filename}` (Cookie-Auth, Arzt eigene Dateien oder Admin) — HTTP-Range-Requests, `Accept-Ranges: bytes`, 206 Partial Content, Duration-Sidecar `{ts}.duration.txt` für HTML5-Player mit Seeking
|
||||||
|
- [ ] Replay-Gain-Normalisierung für Wiedergabe (nicht destruktiv) — verschiedene Erfassungsgeräte liefern stark unterschiedliche Pegel (Watch `MIC` ~-38 dB mean, Desktop ~-27 dB mean). PoC am 2026-04-23 erfolgreich, aber nicht committed; Re-Implementierung steht aus. Erprobte Architektur: pro `.m4a` ein `<stem>.loudness.json`-Sidecar mit statischem `gain_db` (aus `ffmpeg -af volumedetect`, Ziel −16 dB mean, Peak-Cap −1 dB). Lazy-Backfill im bestehenden `scan_recordings`-JoinSet analog zum Duration-Sidecar. Browser appliziert den Gain über Web Audio API `GainNode` (kein Disk-Rewrite, Original + Whisper unberührt). Kombiniert mit `AudioSource.VOICE_RECOGNITION` auf der Watch (besseres SNR, siehe 5b). Verworfene Alternativen: `ffmpeg loudnorm` (pumpt + Artefakte), fixes `volume=+XdB` (client-abhängig). Kern-Einsicht: SNR > Loudness an der Source, solange Post-Gain verfügbar ist.
|
||||||
- [x] Fall analysieren — Button in der Fall-Übersicht
|
- [x] Fall analysieren — Button in der Fall-Übersicht
|
||||||
- [x] Bulk-Aktionen (alle markierten analysieren / löschen) über `POST /web/cases/bulk` — **admin-only** (`AuthenticatedUser::is_admin()` auf `role == "admin"`, Check am Entry-Handler).
|
- [x] Bulk-Aktionen (alle markierten analysieren / löschen) über `POST /web/cases/bulk` — **admin-only** (`AuthenticatedUser::is_admin()` auf `role == "admin"`, Check am Entry-Handler).
|
||||||
- [x] Purge-Closed (`POST /web/cases/purge-closed`, `confirm=yes` Pflicht) — **admin-only**, entfernt geschlossene Fälle hart, emittiert `CaseEventKind::CasePurged` pro entferntem Case.
|
- [x] Purge-Closed (`POST /web/cases/purge-closed`, `confirm=yes` Pflicht) — **admin-only**, entfernt geschlossene Fälle hart, emittiert `CaseEventKind::CasePurged` pro entferntem Case.
|
||||||
@@ -1180,7 +1181,7 @@ wiremock = "0.6"
|
|||||||
|
|
||||||
**Hinweis:** Ein früher Proof-of-Concept (minimale Aufnahme + Upload auf echter Pixel Watch) sollte parallel zu Phase 2–3 stattfinden, um Wear-OS-spezifische Einschränkungen (Doze-Mode, Foreground-Service-Limits, Battery-Optimization) frühzeitig aufzudecken.
|
**Hinweis:** Ein früher Proof-of-Concept (minimale Aufnahme + Upload auf echter Pixel Watch) sollte parallel zu Phase 2–3 stattfinden, um Wear-OS-spezifische Einschränkungen (Doze-Mode, Foreground-Service-Limits, Battery-Optimization) frühzeitig aufzudecken.
|
||||||
|
|
||||||
**Stand-in, solange keine Hardware:** `scripts/dictate.sh` simuliert den Client-Flow via ffmpeg-PulseAudio-Aufnahme + Upload gegen den laufenden Server (Modi: neuer Fall / aktuellen Fall fortsetzen / refresh). State in `/tmp/doctate-current-case`. So lassen sich Transkription und Oneliner ohne native Clients testen.
|
**Schneller Server-Test ohne Client:** `scripts/dictate.sh` simuliert den Client-Flow via ffmpeg-PulseAudio-Aufnahme + Upload gegen den laufenden Server (Modi: neuer Fall / aktuellen Fall fortsetzen / refresh). State in `/tmp/doctate-current-case`. Ursprünglich als Hardware-Stand-in entstanden; bleibt nützlich für Iterationen am Server, die keinen Watch-/Desktop-Build-Zyklus rechtfertigen.
|
||||||
|
|
||||||
#### 5a — Gemeinsame Code-Basis (vor jeder UI-Arbeit)
|
#### 5a — Gemeinsame Code-Basis (vor jeder UI-Arbeit)
|
||||||
- [ ] Gradle-Multi-Modul-Projekt aufsetzen (`:core-domain`, `:core-audio`, `:core-sync`, `:core-http`, `:core-storage`, `:app-wear`, `:app-mobile` als Platzhalter) — PoC (2026-04-23) läuft vorerst paket-basiert in einem `:app`-Modul; Split wird spätestens beim Start der Handy-App fällig (siehe Abweichungen → Client-Architektur).
|
- [ ] Gradle-Multi-Modul-Projekt aufsetzen (`:core-domain`, `:core-audio`, `:core-sync`, `:core-http`, `:core-storage`, `:app-wear`, `:app-mobile` als Platzhalter) — PoC (2026-04-23) läuft vorerst paket-basiert in einem `:app`-Modul; Split wird spätestens beim Start der Handy-App fällig (siehe Abweichungen → Client-Architektur).
|
||||||
@@ -1194,6 +1195,7 @@ wiremock = "0.6"
|
|||||||
- [ ] Vertikale Fallliste (Neu ganz oben, heutige Fälle darunter)
|
- [ ] Vertikale Fallliste (Neu ganz oben, heutige Fälle darunter)
|
||||||
- [ ] Nach Stop: Screen bleibt auf aktuellem Fall (→ "Fortsetzen" direkt sichtbar)
|
- [ ] Nach Stop: Screen bleibt auf aktuellem Fall (→ "Fortsetzen" direkt sichtbar)
|
||||||
- [x] MediaRecorder-Integration via `:core-audio` — in `audio/AudioRecorder.kt` (MPEG-4/AAC-LC, 16 kHz mono, 64 kbps, `context.cacheDir`). Landet bei künftigem Multi-Modul-Split in `:core-audio`.
|
- [x] MediaRecorder-Integration via `:core-audio` — in `audio/AudioRecorder.kt` (MPEG-4/AAC-LC, 16 kHz mono, 64 kbps, `context.cacheDir`). Landet bei künftigem Multi-Modul-Split in `:core-audio`.
|
||||||
|
- [ ] `AudioSource.MIC` → `VOICE_RECOGNITION` umstellen — Wear-OS-DSP (Noise-Suppression, AGC) liefert saubereres Signal bei niedrigerem Rohpegel. Geht nur zusammen mit serverseitigem Replay-Gain (siehe Phase 4), weil VR allein ~9 dB leiser ist als MIC. PoC am 2026-04-23 bestätigt: VR + Replay-Gain klingt deutlich besser als MIC + Replay-Gain (letzteres verstärkt auch Rauschen mit).
|
||||||
- [ ] Bluetooth-Headset Erkennung + Indikator
|
- [ ] Bluetooth-Headset Erkennung + Indikator
|
||||||
- [~] case_id (UUIDv4) Generierung: Neu → neue case_id, Fortsetzen → bestehende — PoC erzeugt `CaseId.new()` pro Aufnahme (`domain/CaseId.kt`). Neu/Fortsetzen-Dualität fehlt, weil keine Fallliste-UI existiert.
|
- [~] case_id (UUIDv4) Generierung: Neu → neue case_id, Fortsetzen → bestehende — PoC erzeugt `CaseId.new()` pro Aufnahme (`domain/CaseId.kt`). Neu/Fortsetzen-Dualität fehlt, weil keine Fallliste-UI existiert.
|
||||||
- [~] Persistente Speicherung im lokalen Dateisystem (UTC-Timestamps in Dateinamen) — PoC speichert in `cacheDir` und **löscht nach Upload**; Datei lebt also nur während der laufenden Pipeline. `unsynced/`-Pattern (überlebt Neustarts) fehlt.
|
- [~] Persistente Speicherung im lokalen Dateisystem (UTC-Timestamps in Dateinamen) — PoC speichert in `cacheDir` und **löscht nach Upload**; Datei lebt also nur während der laufenden Pipeline. `unsynced/`-Pattern (überlebt Neustarts) fehlt.
|
||||||
@@ -1208,7 +1210,7 @@ wiremock = "0.6"
|
|||||||
- [ ] (optional) Speicherplatz-Warnung bei >500 MB ungesyncten Daten
|
- [ ] (optional) Speicherplatz-Warnung bei >500 MB ungesyncten Daten
|
||||||
- [ ] Stop → direkt in Sync-Queue, ✓-Feedback, Screen bleibt auf aktuellem Fall
|
- [ ] Stop → direkt in Sync-Queue, ✓-Feedback, Screen bleibt auf aktuellem Fall
|
||||||
- [ ] Oneliner-Polling (alle paar Sekunden für den sichtbaren Fall, bis Oneliner empfangen)
|
- [ ] Oneliner-Polling (alle paar Sekunden für den sichtbaren Fall, bis Oneliner empfangen)
|
||||||
- [~] Emulator-Tests + Pixel Watch Hardware-Test — vertikaler PoC im Emulator manuell verifiziert (Aufnahme → Upload → Whisper → Ollama → `document.md`). Instrumented MockWebServer-Test (`UploadClientTest`) hängt auf Wear-OS-34-AVD (siehe Abweichungen). Hardware-Test steht aus.
|
- [~] Emulator-Tests + Pixel Watch Hardware-Test — vertikaler PoC im Emulator **und auf realer Pixel Watch 2** (ADB-over-WiFi, LAN-Dev-Server) manuell verifiziert (Aufnahme → Upload → Whisper → Ollama → `document.md`). Instrumented MockWebServer-Test (`UploadClientTest`) hängt auf Wear-OS-34-AVD (siehe Abweichungen). Vollständige Feldtests (LTE-Modus, Akku-Lauf, Doze-Modus, Langzeit-Foreground-Service) stehen weiter aus.
|
||||||
|
|
||||||
#### 5c — Android-Handy-App (nach Watch-Abschluss)
|
#### 5c — Android-Handy-App (nach Watch-Abschluss)
|
||||||
- [ ] `:app-mobile`-Modul auf bestehende `:core-*`-Basis aufsetzen
|
- [ ] `:app-mobile`-Modul auf bestehende `:core-*`-Basis aufsetzen
|
||||||
@@ -1244,10 +1246,10 @@ wiremock = "0.6"
|
|||||||
- [x] Invariante gewahrt: jeder Client = weiterer HTTP-Client, kein Server-Code-Ausbau nötig
|
- [x] Invariante gewahrt: jeder Client = weiterer HTTP-Client, kein Server-Code-Ausbau nötig
|
||||||
|
|
||||||
### Phase 6 — Integration & Testing
|
### Phase 6 — Integration & Testing
|
||||||
- [ ] End-to-End Test (Watch → Server → Webinterface)
|
- [~] End-to-End Test (Watch → Server → Webinterface) — PoC-Pfad auf realer Pixel Watch 2 (2026-04-23, ADB-over-WiFi, LAN-Server) einmalig durchgelaufen; automatisierter Testlauf steht aus.
|
||||||
- [~] End-to-End Test (Linux-Desktop → Server → Webinterface inkl. Oneliner-Poll-Refresh und Magic-Link-Handoff in den Browser) — im Alltagsbetrieb validiert, aber kein dedizierter automatisierter E2E-Testlauf
|
- [~] End-to-End Test (Linux-Desktop → Server → Webinterface inkl. Oneliner-Poll-Refresh und Magic-Link-Handoff in den Browser) — im Alltagsbetrieb validiert, aber kein dedizierter automatisierter E2E-Testlauf
|
||||||
- [~] SSE Live-Updates testen — Unit-Tests im `events`-Modul (Capacity, Lagged, Subscriber-Fanout), `server/tests/sse_integration.rs` + `server/tests/sse_cleanup_test.rs` (Connection-Pool-Leak)
|
- [~] SSE Live-Updates testen — Unit-Tests im `events`-Modul (Capacity, Lagged, Subscriber-Fanout), `server/tests/sse_integration.rs` + `server/tests/sse_cleanup_test.rs` (Connection-Pool-Leak)
|
||||||
- [ ] Pixel Watch Hardware-Test
|
- [~] Pixel Watch Hardware-Test — erster Hardware-Lauf am 2026-04-23 erfolgreich (Pairing, Install, Aufnahme, Upload, Transkript). Ausstehend: LTE-Modus, Doze-Modus, Langzeit-Foreground-Service.
|
||||||
- [ ] LTE-Modus testen
|
- [ ] LTE-Modus testen
|
||||||
- [ ] Bluetooth-Headset testen
|
- [ ] Bluetooth-Headset testen
|
||||||
- [ ] Sync-Service testen (Netzwerkausfall, Neustart, Doze)
|
- [ ] Sync-Service testen (Netzwerkausfall, Neustart, Doze)
|
||||||
|
|||||||
Reference in New Issue
Block a user