Files
WhispAssist/docs/05-roadmap.md
T

238 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 05 — Roadmap
Eight phases, each a shippable increment. Every task carries an ID and the requirement(s) it
satisfies; every phase has **acceptance criteria** that gate "done" (verified by the tests in
`06-test-strategy.md`). Phases are ordered so each builds on a working previous one. Suggested
effort labels: **S** ≤1 day, **M** a few days, **L** ~1–2 weeks (team-dependent, indicative only).
Legend: `[T1.2]` = task; → FR/NFR satisfied.
---
## Phase 1 — Foundation: capture + CPU transcription
**Goal:** a window where you click Record, system audio is captured to disk, and plain transcript
text streams in on CPU.
- `[T1.1]` Scaffold Tauri 2 + Svelte project; window, build, dev loop. **M** → ADR-0001/0002
- `[T1.2]` `audio`: WASAPI loopback capture thread (polling), PCM ring buffer, WAV writer. **L** → FR-CAP-1/2
- `[T1.3]` Recording lifecycle commands + `recording://state` events; start/stop/pause/resume. **M** → FR-CAP-3
- `[T1.4]` Recording indicator: in-app banner + tray icon. **S** → FR-CAP-4
- `[T1.5]` `transcription`: integrate `whisper-rs` CPU; load small model; window+overlap feeder. **L** → FR-TRX-1, NFR-MNT-4
- `[T1.6]` Stream interim/final segments → `transcript://segment`; minimal transcript view. **M** → FR-TRX-2
- `[T1.7]` Idle discipline: no threads/timers when not recording; model unloaded when idle. **S** → NFR-RES-1
- `[T1.8]` "Record this meeting" toggle (default OFF) + mid-meeting `set_recording_retention`; "saving" indicator. **S** → FR-REC-1/3
- `[T1.9]` Consent notice + one-time acknowledgment before first retained recording. **S** → FR-REC-2
**Acceptance:** Record a 5-min meeting; transcript appears live within a few seconds of speech on a
CPU-only laptop; stopping leaves the app idle with near-zero CPU. With "Record" ON, a playable
`audio.wav` remains; with it OFF (default), no audio file remains after finalize. The consent notice
appears before the first retained recording and must be acknowledged once. (Tests: P1 suite.)
---
## Phase 2 — Storage, notes, persistence, recovery
**Goal:** meetings are saved, listable, editable as Markdown, exportable, and survive a crash.
- `[T2.1]` `storage`: SQLite schema + migrations; meeting folder layout; transactional writes. **L** → FR-STORE-1
- `[T2.2]` Persist `transcript.json` + metadata on stop; status lifecycle. **M** → FR-STORE-1
- `[T2.3]` Meetings list (create/open/delete) UI + commands. **M** → FR-STORE-5
- `[T2.4]` `notes`: assemble Markdown (speaker-tagged) from segments; render + raw side-by-side. **M** → FR-NOTE-1/6
- `[T2.5]` Markdown editor with toolbar (headings/bold/italic/lists/checkboxes); `update_notes`. **M** → FR-NOTE-2
- `[T2.6]` Export single meeting to `.md` and bundle (audio+transcript+notes). **M** → FR-NOTE-3, FR-STORE-3
- `[T2.10]` Finalize path honors retention: delete working WAV only **after** transcript finalized; set `recorded`/`audio_path` (FR-REC-4). **S** → FR-REC-1/4
- `[T2.7]` Auto-save notes/transcript at intervals. **S** → FR-REL-2
- `[T2.8]` Startup recover-scan: audio-without-transcript → `recovering`; re-run flow. **M** → FR-REL-1, NFR-REL-3
- `[T2.9]` Storage settings: base directory + retention policy (size/age) + background enforcement. **M** → FR-STORE-2
**Acceptance:** Kill the app mid-meeting; on relaunch the meeting is recoverable from audio and
transcription can be regenerated. Notes edit + `.md` export round-trip. Retention deletes the
oldest meeting when the cap is exceeded and never touches a recording in progress. (Tests: P2 suite.)
---
## Phase 3 — Hardware acceleration + model management
**Goal:** detect and use NPU/GPU; switch models; show the active backend; batch re-transcribe.
- `[T3.1]` `hardware`: enumerate CPU/GPU (DXGI) + NPU (ONNX/Windows ML); rank backends. **L** → FR-HW-1
- `[T3.2]` Backend selection (auto order + manual override); construct matching Transcriber. **M** → FR-HW-2
- `[T3.3]` whisper.cpp accelerated builds behind Cargo features (CUDA/Vulkan); CPU always builds. **L** → FR-TRX-5, NFR-MNT-4
- `[T3.4]` NPU path: `ort` + DirectML Whisper-ONNX `Transcriber` (same trait/output). **L** → FR-TRX-5, ADR-0004
- `[T3.5]` Graceful fallback NPU→GPU→CPU on failure; `hardware://changed` notice. **M** → FR-HW-4, NFR-REL-2
- `[T3.6]` Show active backend, model size, est. RTF in Settings + recording bar. **S** → FR-HW-3
- `[T3.7]` Model management UI: choose Whisper size; download/remove with progress. **M** → FR-MODEL-1
- `[T3.8]` Batch re-transcription with a larger model post-meeting. **M** → FR-TRX-3
- `[T3.9]` "Low overhead" preset (CPU + small model + no realtime summary + reduced indexing). **S** → NFR-RES-3, NFR-PERF-3
**Acceptance:** On a machine with a supported GPU/NPU, the active backend is detected and shown,
and transcription is measurably faster than the CPU baseline; forcing a backend failure falls back
cleanly to CPU without aborting. Output segments are equivalent across backends. (Tests: P3 suite.)
---
## Phase 4 — Speaker diarization & naming
**Goal:** segments get speaker labels; users name/merge speakers during and after meetings.
- `[T4.1]` `diarization`: integrate `sherpa-onnx` (segmentation+embedding+clustering) via FFI. **L** → FR-SPK-1, ADR-0005
- `[T4.2]` Align speaker spans to transcript segments by timestamp overlap. **M** → FR-SPK-1
- `[T4.3]` Live provisional speaker turns from cheap segmentation during recording. **M** → FR-SPK-2
- `[T4.4]` In-session naming: name a speaker → applies to past & future segments. **M** → FR-SPK-2
- `[T4.5]` Post-meeting review screen: rename + **merge** over-split speakers. **M** → FR-SPK-3
- `[T4.6]` Persist speaker→name mapping; apply at render/export (non-destructive). **S** → FR-SPK-5
- `[T4.7]` Diarization models in model-management; download/select. **S** → FR-MODEL-1
**Acceptance:** A two-person recording yields ≥2 speakers; naming a speaker relabels all their
segments live; merging two IDs into one updates notes and export; renaming never rewrites segment
speaker IDs in storage. (Tests: P4 suite.)
---
## Phase 5 — Local LLM integration
**Goal:** configure a local LLM and get summaries, decisions, and editable action items.
- `[T5.1]` `llm`: Ollama client (`/api/tags`, `/api/chat` streaming) behind `LlmProvider`. **M** → FR-LLM-1, ADR-0007
- `[T5.2]` Provider settings: Ollama | custom endpoint | off; `llm_status` + reachability. **M** → FR-LLM-1
- `[T5.3]` Local-endpoint guard + "data leaves WA" banner for remote/proxy endpoints. **S** → FR-LLM-6, FR-SEC-1
- `[T5.4]` Prompt assembly: transcript + metadata + optional template → summary/decisions/actions. **M** → FR-LLM-2
- `[T5.5]` Stream tokens to summary panel (`llm://token`/`done`); persist `summary.json`. **M** → FR-LLM-4
- `[T5.6]` Parse action items into editable list; confirm → `action_items` rows. **M** → FR-LLM-3
- `[T5.7]` Guided provider install + hardware-aware model suggestions when none detected. **M** → FR-LLM-5
**Acceptance:** With Ollama running, a finished meeting produces a streamed summary plus a list of
action items the user can edit and confirm; with the LLM off or unreachable, capture/transcription/
notes still work and the UI degrades gracefully. (Tests: P5 suite.)
---
## Phase 6 — Calendar & Outlook .pst integration
**Goal:** import `.pst` events/attendees, attach recordings to events, suggest speaker names.
- `[T6.1]` `calendar`: `.pst` reader (`outlook-pst`; libpff fallback) → events + attendees. **L** → FR-CAL-1, ADR-0008
- `[T6.2]` `import_pst` command with optional password; progress events; persist events/participants. **M** → FR-CAL-1
- `[T6.3]` Calendar/meetings view: upcoming/recent; attach a recording to an event. **M** → FR-CAL-2
- `[T6.4]` Pre-meeting context panel: title, organizer, participants. **S** → FR-CAL-3
- `[T6.5]` Participant-aware naming: attendee dropdown in speaker UI + "add new name". **M** → FR-SPK-4
- `[T6.6]` Link recording ↔ historical `.pst` event; continuity of named speakers. **M** → FR-CAL-4
**Acceptance:** Importing a sample `.pst` yields events with attendees; selecting an event prefills
the speaker-naming dropdown; PST parse failure is non-fatal and surfaced clearly. (Tests: P6 suite.)
---
## Phase 7 — UX polish, themes, accessibility, privacy panel
**Goal:** the modern, fast, themeable, accessible experience.
- `[T7.1]` Final three-pane layout (list · transcript/notes · summary/actions/participants). **M** → FR-UX-1
- `[T7.2]` Light/dark themes following system + override; tokens/contrast pass. **M** → FR-UX-2
- `[T7.3]` Live waveform/level meter; device-change resilience. **M** → FR-CAP-5/6
- `[T7.4]` Keyboard shortcuts (record start/stop, view toggles, template apply). **S** → FR-UX-3
- `[T7.5]` Screen-reader labels, focus order, ARIA; contrast audit. **M** → FR-UX-4
- `[T7.6]` Privacy panel: active backend + LLM endpoint + local-only confirmation; `privacy_self_check`. **M** → FR-SEC-2
- `[T7.7]` Startup/perf pass: cold start < ~2 s, lazy-load models, idle audit. **M** → NFR-PERF-4, NFR-RES-1
**Acceptance:** Themes switch with the OS and override; keyboard-only operation works for core
flows; a contrast/screen-reader audit passes; the privacy panel accurately reflects egress; cold
start meets target. (Tests: P7 suite.)
---
## Phase 8 — Advanced features
**Goal:** templates, search/tagging, reminders, richer export, encryption.
- `[T8.1]` Note templates by meeting type (sections per type); apply on creation. **M** → FR-NOTE-5
- `[T8.2]` Full-text search (FTS5) across transcripts + notes. **M** → FR-SEARCH-1
- `[T8.3]` Tagging + list filters (date/tag/participant). **M** → FR-SEARCH-2
- `[T8.4]` PDF/Word export via local conversion. **M** → FR-NOTE-4
- `[T8.5]` Bulk export by date range/tag. **S** → FR-STORE-4
- `[T8.6]` Local reminders / OS notifications for action items. **M** → FR-CAL-5
- `[T8.7]` Multi-language transcription + UI localization scaffold. **M** → FR-TRX-4
- `[T8.8]` Optional at-rest encryption + password-protected vault. **L** → FR-SEC-3
- `[T8.9]` (Later) Microsoft Graph calendar source behind `CalendarSource` (opt-in, consented). **L** → FR-CAL-6
**Acceptance:** Search returns relevant meetings; templates structure new notes; PDF/Word exports
render correctly offline; reminders fire locally; encryption (when enabled) protects the storage
root and unlocks with the vault password. (Tests: P8 suite.)
---
## Phase 9 — Remote sync / upload
**Goal:** optionally upload meeting artifacts to user-configured destinations — off by default,
self-hostable first. (ADR-0010.) Can begin in parallel after Phase 2 since it only needs the
storage/file layer; OAuth sub-phase is independent of the WebDAV one.
### 9a — Core + WebDAV primary set (Nextcloud, ownCloud, Cloudreve, Seafile, Synology)
- `[T9.1]` `sync` module: `SyncTarget`/`SyncManager` traits; `sync_targets`/`sync_jobs` schema (migration 0002). **M** → FR-SYNC-1
- `[T9.2]` `WebDavTarget`: PUT/MKCOL/PROPFIND; per-provider base paths; chunked upload for large files. **L** → FR-SYNC-2
- `[T9.3]` Target config UI + `add/update/remove/list_sync_targets`; per-target artifact + trigger selection. **M** → FR-SYNC-2/3
- `[T9.4]` `test_sync_target` (reachability + auth) with provider-specific setup hints (e.g. enable SeafDAV). **M** → FR-SYNC-4
- `[T9.5]` Durable queue: enqueue on finalize / "Upload now"; backoff retry; SHA-256 skip-if-unchanged; `sync://job` events. **L** → FR-SYNC-5
- `[T9.6]` Credentials in OS credential store (`keyring`); never in settings/DB. **M** → FR-SYNC-6, NFR-SEC-4
- `[T9.7]` TLS enforcement; refuse plaintext http except explicit per-target LAN opt-in. **S** → FR-SYNC-7
- `[T9.8]` Sync state + target labeling in UI (self-hosted vs third-party); wire into privacy panel + `privacy_self_check`. **M** → FR-SYNC-8, FR-SEC-2
### 9b — Secondary OAuth targets (OneDrive, Dropbox, Box)
- `[T9.9]` OAuth 2.0 PKCE with loopback redirect; token storage in credential store; `begin_oauth_link`. **L** → FR-SYNC-9
- `[T9.10]` `OneDriveTarget` (MS Graph), `DropboxTarget`, `BoxTarget`: upload + resumable sessions behind `SyncTarget`. **L** → FR-SYNC-9
- `[T9.11]` Third-party "data leaves your device" banner + explicit enable acknowledgment. **S** → FR-SYNC-8
### 9c — Optional
- `[T9.12]` Client-side encryption before upload (uses the Phase 8 vault): destination holds only ciphertext. **M** → FR-SYNC-10
**Acceptance:** With sync disabled (default), the egress allowlist contains no sync hosts and nothing
uploads. After adding and enabling a WebDAV target (tested against a real Nextcloud/Seafile or an
`rclone serve webdav` instance), finishing a meeting uploads the selected artifacts to the correct
remote path; interrupting the network leaves a `failed` job that retries and completes; an unchanged
re-upload is skipped. Credentials never appear in `settings.json`/`wa.db`. Third-party targets show
the leaves-your-device banner. (Tests: P9 suite.)
---
## Phase 10 — External AI & coding-agent integration
**Goal:** optionally use hosted AI for summaries, and hand a meeting off to the user's coding agent
to "get started right away." (ADR-0011.) All off by default. Needs Phase 5 (LLM) for distillation;
otherwise independent.
### 10a — Cloud summary providers (Layer 1)
- `[T10.1]` Extend `LlmProvider` with `OpenAiCompatProvider` (`/v1/chat/completions`) and `AnthropicProvider` (`/v1/messages`). **M** → FR-AI-1
- `[T10.2]` `set_llm_provider`; API keys in OS credential store; host added to egress allowlist; third-party banner. **M** → FR-AI-2, FR-SEC-1
- `[T10.3]` Per-use provider selection + active-provider display. **S** → FR-AI-3
### 10b — WhispAssist as an MCP server + feature briefs (Layer 2, the primary handoff)
- `[T10.4]` `mcp` module on `rmcp`: loopback MCP server, **off by default**, token-gated; Streamable HTTP (`/mcp`) + stdio adapter. **L** → FR-MCP-1/6, NFR-SEC-5
- `[T10.5]` Tools-first surface: `list_recent_meetings`, `get_transcript`, `get_action_items`, `get_feature_brief`. **M** → FR-MCP-2
- `[T10.6]` `FeatureBriefBuilder`: distill transcript → structured brief; `create/list/get_feature_brief`; persist to `briefs/`. **L** → FR-MCP-4
- `[T10.7]` Scope control (`none|selected|all`, recordings excluded by default) + `set_brief_exposed`. **M** → FR-MCP-3
- `[T10.8]` Disclosure UI ("connected agents may forward data") + `mcp_access_log` audit. **M** → FR-MCP-5
- `[T10.9]` Privacy panel + `privacy_self_check` show MCP state and confirm it adds no egress. **S** → FR-MCP-7, FR-SEC-2
### 10c — Push & task-tracker handoff (Layer 3, later)
- `[T10.10]` `AgentRunner`: spawn `claude -p` / `codex exec` / `opencode run` / `copilot` headless against a repo; stream output. **L** → FR-AGENT-1
- `[T10.11]` `IssueTracker`: create a GitHub issue from a brief; optional assign-to-Copilot-cloud. **M** → FR-AGENT-2
**Acceptance:** With everything off (default), no AI host is on the allowlist and no MCP port is
open. Enabling a hosted provider routes a summary to it and shows the third-party banner. Enabling
the MCP server lets a local agent (e.g. Claude Code) call `get_feature_brief` and receive a usable
spec; the access is logged; WA opens no outbound socket for it (egress test unchanged). Recordings
are never served unless explicitly allowed. (Tests: P10 suite.)
---
## Cross-cutting (every phase)
- Privacy invariant FR-SEC-1 verified continuously: the CI network test asserts egress stays within
the settings-derived allowlist (LLM + enabled sync hosts + model downloads). See `06-test-strategy.md`.
- `cargo fmt`/`clippy -D warnings` + Prettier/ESLint clean.
- Update `docs/` whenever a contract or behavior changes (CLAUDE.md rule).
## Dependency graph (high level)
```
P1 ─► P2 ─► P3 ─► P4 ─► P5 ─► P10 (AI/MCP; 10a/10b need P5's LLM)
│ └► P6 ─► P7 ─► P8
└► P9 (sync; needs only P2's storage layer — can run in parallel)
P5 and P6 can proceed in parallel after P4; P7 needs P3–P6 features to polish; P8 last.
P9 needs only P2; 9b (OAuth) is independent of 9a (WebDAV); 9c needs P8's vault.
P10 needs P5; 10b (MCP) is the priority; 10c (push/issue) is later and optional.
```
## Suggested first milestone (thin vertical slice)
T1.1 → T1.2 → T1.5 → T1.6 → T2.1 → T2.2 → T2.4 gives a usable "record → live transcript → saved
Markdown notes" loop — the smallest thing worth dogfooding.