chore: Archive all pending OpenSpec proposals
Force archive the following proposals: - add-audio-device-selector (complete) - add-embedded-backend-packaging (19/26 tasks) - add-flexible-deployment-options (20/21 tasks) New specs created: - audio-device-management (7 requirements) - embedded-backend (8 requirements) Updated specs: - transcription (+2 requirements for model download progress) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
133
openspec/specs/audio-device-management/spec.md
Normal file
133
openspec/specs/audio-device-management/spec.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# audio-device-management Specification
|
||||
|
||||
## Purpose
|
||||
TBD - created by archiving change add-audio-device-selector. Update Purpose after archive.
|
||||
## Requirements
|
||||
### Requirement: Audio Device Enumeration
|
||||
The frontend SHALL enumerate and display all available audio input devices.
|
||||
|
||||
#### Scenario: List available devices
|
||||
- **WHEN** user opens meeting detail page
|
||||
- **THEN** system SHALL enumerate all audio input devices
|
||||
- **AND** display them in a dropdown selector
|
||||
- **AND** exclude virtual/system devices like "Stereo Mix"
|
||||
|
||||
#### Scenario: Refresh device list
|
||||
- **WHEN** user clicks refresh button or device is connected/disconnected
|
||||
- **THEN** system SHALL re-enumerate devices
|
||||
- **AND** update dropdown options
|
||||
- **AND** preserve current selection if still available
|
||||
|
||||
#### Scenario: Device label display
|
||||
- **WHEN** devices are listed
|
||||
- **THEN** each device SHALL display its friendly name (label)
|
||||
- **AND** indicate if it's the system default device
|
||||
|
||||
### Requirement: Manual Device Selection
|
||||
The frontend SHALL allow users to manually select their preferred audio input device.
|
||||
|
||||
#### Scenario: Select device from dropdown
|
||||
- **WHEN** user selects a device from dropdown
|
||||
- **THEN** system SHALL update selected device state
|
||||
- **AND** start volume monitoring on new device
|
||||
- **AND** save selection to localStorage
|
||||
|
||||
#### Scenario: Load saved preference
|
||||
- **WHEN** meeting detail page loads
|
||||
- **THEN** system SHALL check localStorage for saved device preference
|
||||
- **AND** if saved device is available, auto-select it
|
||||
- **AND** if saved device unavailable, fall back to system default
|
||||
|
||||
#### Scenario: Selected device unavailable
|
||||
- **WHEN** previously selected device is no longer available
|
||||
- **THEN** system SHALL show warning message
|
||||
- **AND** fall back to system default device
|
||||
- **AND** prompt user to select new device
|
||||
|
||||
### Requirement: Real-time Volume Indicator
|
||||
The frontend SHALL display real-time audio input level from the selected microphone.
|
||||
|
||||
#### Scenario: Display volume meter
|
||||
- **WHEN** a device is selected
|
||||
- **THEN** system SHALL show animated volume meter
|
||||
- **AND** update meter at least 10 times per second
|
||||
- **AND** display level as percentage (0-100%)
|
||||
|
||||
#### Scenario: Volume meter accuracy
|
||||
- **WHEN** user speaks into microphone
|
||||
- **THEN** volume meter SHALL reflect actual audio amplitude
|
||||
- **AND** peak levels SHALL be visually distinct
|
||||
|
||||
#### Scenario: Muted or silent input
|
||||
- **WHEN** no audio input detected for 3 seconds
|
||||
- **THEN** volume meter SHALL show minimal/zero level
|
||||
- **AND** optionally show "No input detected" hint
|
||||
|
||||
### Requirement: Audio Test Recording
|
||||
The frontend SHALL allow users to record a short test audio clip.
|
||||
|
||||
#### Scenario: Start test recording
|
||||
- **WHEN** user clicks "Test Recording" button
|
||||
- **THEN** system SHALL start recording from selected device
|
||||
- **AND** button SHALL change to "Stop" with countdown timer
|
||||
- **AND** recording SHALL auto-stop after 5 seconds
|
||||
|
||||
#### Scenario: Stop test recording
|
||||
- **WHEN** recording reaches 5 seconds or user clicks stop
|
||||
- **THEN** recording SHALL stop
|
||||
- **AND** audio blob SHALL be stored in memory
|
||||
- **AND** "Play Test" button SHALL become enabled
|
||||
|
||||
#### Scenario: Recording indicator
|
||||
- **WHEN** test recording is in progress
|
||||
- **THEN** UI SHALL show recording indicator (pulsing dot)
|
||||
- **AND** remaining time SHALL be displayed
|
||||
|
||||
### Requirement: Test Audio Playback
|
||||
The frontend SHALL allow users to play back their test recording.
|
||||
|
||||
#### Scenario: Play test recording
|
||||
- **WHEN** user clicks "Play Test" button
|
||||
- **THEN** system SHALL play the recorded audio through default output
|
||||
- **AND** button SHALL change to indicate playing state
|
||||
- **AND** playback SHALL stop at end of recording
|
||||
|
||||
#### Scenario: No test recording available
|
||||
- **WHEN** no test recording has been made
|
||||
- **THEN** "Play Test" button SHALL be disabled
|
||||
- **AND** tooltip SHALL indicate "Record a test first"
|
||||
|
||||
### Requirement: Integration with Main Recording
|
||||
The main recording function SHALL use the user-selected audio device.
|
||||
|
||||
#### Scenario: Use selected device for recording
|
||||
- **WHEN** user starts main recording
|
||||
- **THEN** system SHALL use the device selected in audio settings panel
|
||||
- **AND** if no device selected, use auto-selection logic
|
||||
|
||||
#### Scenario: Device changed during recording
|
||||
- **WHEN** user changes device selection while recording
|
||||
- **THEN** change SHALL NOT affect current recording
|
||||
- **AND** new selection SHALL apply to next recording session
|
||||
|
||||
### Requirement: Audio Settings Panel UI
|
||||
The frontend SHALL display audio settings in a collapsible panel.
|
||||
|
||||
#### Scenario: Panel visibility
|
||||
- **WHEN** meeting detail page loads
|
||||
- **THEN** audio settings panel SHALL be visible but collapsible
|
||||
- **AND** panel state (expanded/collapsed) SHALL be saved
|
||||
|
||||
#### Scenario: Panel layout
|
||||
- **WHEN** panel is expanded
|
||||
- **THEN** it SHALL display:
|
||||
- Device dropdown selector
|
||||
- Volume meter visualization
|
||||
- Test recording button
|
||||
- Play test button
|
||||
- Status indicator
|
||||
|
||||
#### Scenario: Compact mode
|
||||
- **WHEN** panel is collapsed
|
||||
- **THEN** it SHALL show only selected device name and expand button
|
||||
|
||||
130
openspec/specs/embedded-backend/spec.md
Normal file
130
openspec/specs/embedded-backend/spec.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# embedded-backend Specification
|
||||
|
||||
## Purpose
|
||||
TBD - created by archiving change add-embedded-backend-packaging. Update Purpose after archive.
|
||||
## Requirements
|
||||
### Requirement: Embedded Backend Packaging
|
||||
The FastAPI backend SHALL be packaged as a standalone executable using PyInstaller for all-in-one deployment.
|
||||
|
||||
#### Scenario: Backend executable creation
|
||||
- **WHEN** build script runs with embedded backend flag
|
||||
- **THEN** PyInstaller SHALL create `backend/dist/backend/backend.exe` containing FastAPI, uvicorn, and all dependencies
|
||||
|
||||
#### Scenario: Backend executable startup
|
||||
- **WHEN** backend executable is launched
|
||||
- **THEN** it SHALL read configuration from `config.json` in the same directory
|
||||
- **AND** start uvicorn server on configured host and port
|
||||
|
||||
### Requirement: Electron Backend Sidecar Management
|
||||
The Electron main process SHALL manage the embedded backend as a sidecar process.
|
||||
|
||||
#### Scenario: Start backend on app launch
|
||||
- **WHEN** Electron app launches with `backend.embedded: true` in config
|
||||
- **THEN** main process SHALL spawn backend executable as child process
|
||||
- **AND** pass configuration via environment variables
|
||||
|
||||
#### Scenario: Skip backend when disabled
|
||||
- **WHEN** Electron app launches with `backend.embedded: false` in config
|
||||
- **THEN** main process SHALL NOT spawn backend executable
|
||||
- **AND** frontend SHALL connect to remote backend via `apiBaseUrl`
|
||||
|
||||
#### Scenario: Terminate backend on app close
|
||||
- **WHEN** user closes Electron app
|
||||
- **THEN** main process SHALL send SIGTERM to backend process
|
||||
- **AND** force kill after 5 seconds if still running
|
||||
|
||||
### Requirement: Backend Health Check
|
||||
The Electron main process SHALL verify backend readiness before showing the main window.
|
||||
|
||||
#### Scenario: Health check success
|
||||
- **WHEN** backend `/api/health` returns HTTP 200
|
||||
- **THEN** main process SHALL proceed to create main window
|
||||
- **AND** set `backendReady` state to true
|
||||
|
||||
#### Scenario: Health check timeout
|
||||
- **WHEN** backend does not respond within 30 seconds (30 attempts, 1s interval)
|
||||
- **THEN** main process SHALL display error dialog
|
||||
- **AND** log detailed error for debugging
|
||||
|
||||
#### Scenario: Health check polling
|
||||
- **WHEN** health check attempt fails
|
||||
- **THEN** main process SHALL retry after 1 second
|
||||
- **AND** log attempt number for debugging
|
||||
|
||||
### Requirement: Unified Configuration Schema
|
||||
All configuration for frontend, backend, and whisper SHALL be in a single `config.json` file.
|
||||
|
||||
#### Scenario: Backend configuration loading
|
||||
- **WHEN** backend sidecar starts
|
||||
- **THEN** it SHALL read database type from `config.json` backend.database.type section
|
||||
- **AND** read SQLite path from `config.json` backend.database.sqlitePath section (if SQLite mode)
|
||||
- **AND** read database credentials from `config.json` backend.database section (if MySQL mode)
|
||||
- **AND** read API keys from `config.json` backend.externalApis section
|
||||
- **AND** read auth settings from `config.json` backend.auth section
|
||||
|
||||
#### Scenario: Configuration priority
|
||||
- **WHEN** both environment variable and config.json value exist
|
||||
- **THEN** environment variable SHALL take precedence
|
||||
|
||||
#### Scenario: Default values
|
||||
- **WHEN** configuration value is not specified
|
||||
- **THEN** system SHALL use sensible defaults (host: 127.0.0.1, port: 8000, database.type: mysql)
|
||||
|
||||
### Requirement: Backend Status API
|
||||
The Electron app SHALL expose backend status to the renderer process.
|
||||
|
||||
#### Scenario: Get backend status
|
||||
- **WHEN** renderer calls `window.electronAPI.getBackendStatus()`
|
||||
- **THEN** it SHALL return object with `ready` boolean and `url` string
|
||||
|
||||
#### Scenario: Backend status in UI
|
||||
- **WHEN** backend is starting
|
||||
- **THEN** UI MAY display loading indicator
|
||||
|
||||
### Requirement: Backward Compatibility
|
||||
The embedded backend feature SHALL NOT break existing separate-deployment mode.
|
||||
|
||||
#### Scenario: Separate deployment unchanged
|
||||
- **WHEN** `backend.embedded` is false or undefined
|
||||
- **THEN** system SHALL behave exactly as before this change
|
||||
- **AND** frontend connects to `apiBaseUrl` without spawning local backend
|
||||
|
||||
#### Scenario: Existing scripts work
|
||||
- **WHEN** user runs `./start.sh start` or `./scripts/setup-backend.sh`
|
||||
- **THEN** backend SHALL start normally as standalone server
|
||||
|
||||
### Requirement: SQLite Database Support
|
||||
The backend SHALL support SQLite as an alternative to MySQL for offline/standalone deployments.
|
||||
|
||||
#### Scenario: SQLite mode initialization
|
||||
- **WHEN** `database.type` is set to `"sqlite"` in config.json
|
||||
- **THEN** backend SHALL create SQLite database at `database.sqlitePath`
|
||||
- **AND** initialize all required tables using SQLite-compatible syntax
|
||||
|
||||
#### Scenario: MySQL mode initialization
|
||||
- **WHEN** `database.type` is set to `"mysql"` or not specified in config.json
|
||||
- **THEN** backend SHALL connect to MySQL using credentials from `database` section
|
||||
- **AND** behave exactly as before this change
|
||||
|
||||
#### Scenario: SQLite thread safety
|
||||
- **WHEN** multiple concurrent requests access SQLite database
|
||||
- **THEN** backend SHALL use thread lock to serialize database operations
|
||||
- **AND** use `check_same_thread=False` for SQLite connection
|
||||
|
||||
#### Scenario: SQLite data persistence
|
||||
- **WHEN** app is closed and reopened
|
||||
- **THEN** all meeting data SHALL persist in SQLite file
|
||||
- **AND** be accessible on next launch
|
||||
|
||||
### Requirement: Portable Extraction Path Configuration
|
||||
The portable Windows build SHALL extract to a predictable folder name.
|
||||
|
||||
#### Scenario: Fixed extraction folder
|
||||
- **WHEN** portable executable starts
|
||||
- **THEN** it SHALL extract to `%TEMP%\Meeting-Assistant` instead of random UUID folder
|
||||
|
||||
#### Scenario: Windows Defender consistency
|
||||
- **WHEN** user launches portable executable multiple times
|
||||
- **THEN** Windows Defender SHALL NOT prompt for permission each time
|
||||
- **BECAUSE** extraction path is consistent across launches
|
||||
|
||||
@@ -175,3 +175,42 @@ The system SHALL support both real-time local transcription and file-based cloud
|
||||
- **WHEN** transcription completes from either source
|
||||
- **THEN** result SHALL be displayed in the same transcript area in meeting detail page
|
||||
|
||||
### Requirement: Model Download Progress Display
|
||||
The sidecar SHALL report Whisper model download progress to enable UI feedback.
|
||||
|
||||
#### Scenario: Emit download start
|
||||
- **WHEN** Whisper model download begins
|
||||
- **THEN** sidecar SHALL emit JSON to stdout: `{"status": "downloading_model", "model": "<size>", "progress": 0, "total_mb": <size>}`
|
||||
|
||||
#### Scenario: Emit download progress
|
||||
- **WHEN** download progress updates
|
||||
- **THEN** sidecar SHALL emit JSON: `{"status": "downloading_model", "progress": <percent>, "downloaded_mb": <current>, "total_mb": <total>}`
|
||||
- **AND** progress updates SHALL occur at least every 5% or every 5 seconds
|
||||
|
||||
#### Scenario: Emit download complete
|
||||
- **WHEN** model download completes
|
||||
- **THEN** sidecar SHALL emit JSON: `{"status": "model_downloaded", "model": "<size>"}`
|
||||
- **AND** proceed to model loading
|
||||
|
||||
#### Scenario: Skip download for cached model
|
||||
- **WHEN** model already exists in huggingface cache
|
||||
- **THEN** sidecar SHALL NOT emit download progress messages
|
||||
- **AND** proceed directly to loading
|
||||
|
||||
### Requirement: Frontend Model Download Progress Display
|
||||
The Electron frontend SHALL display model download progress to users.
|
||||
|
||||
#### Scenario: Show download progress in transcript panel
|
||||
- **WHEN** sidecar emits download progress
|
||||
- **THEN** whisper status element SHALL display download percentage and size
|
||||
- **AND** format: "Downloading: XX% (YYY MB / ZZZ MB)"
|
||||
|
||||
#### Scenario: Show download complete
|
||||
- **WHEN** sidecar emits model_downloaded status
|
||||
- **THEN** whisper status element SHALL briefly show "Model downloaded"
|
||||
- **AND** transition to loading state
|
||||
|
||||
#### Scenario: Forward progress events via IPC
|
||||
- **WHEN** main process receives download progress from sidecar
|
||||
- **THEN** it SHALL forward to renderer via `model-download-progress` IPC channel
|
||||
|
||||
|
||||
Reference in New Issue
Block a user