voice-server/PROJECT_ROADMAP.json
Cal Corum a34aec06f1 Initial commit: Voice server with Piper TTS
A local HTTP service that accepts text via POST and speaks it through
system speakers using Piper TTS neural voice synthesis.

Features:
- POST /notify - Queue text for TTS playback
- GET /health - Health check with TTS/audio/queue status
- GET /voices - List installed voice models
- Async queue processing (no overlapping audio)
- Non-blocking audio via sounddevice
- 73 tests covering API contract

Tech stack:
- FastAPI + Uvicorn
- Piper TTS (neural voices, offline)
- sounddevice (PortAudio)
- Pydantic for validation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-19 00:18:12 -06:00

1013 lines
34 KiB
JSON

{
"project": {
"name": "voice-server",
"description": "Local HTTP service for text-to-speech playback",
"version": "1.0.0",
"created": "2025-12-18",
"last_updated": "2025-12-18"
},
"methodology": {
"approach": "hybrid-tdd",
"description": "TDD for API contracts, validation, and queue logic. Implementation-first for hardware integrations.",
"tdd_components": [
"request_validation",
"queue_behavior",
"error_responses",
"health_check_logic"
],
"implementation_first_components": [
"piper_tts_integration",
"sounddevice_playback",
"end_to_end_flow"
]
},
"phases": [
{
"id": "phase_1",
"name": "Core Infrastructure",
"description": "Project setup, FastAPI skeleton, and configuration management",
"estimated_days": "1-2"
},
{
"id": "phase_2",
"name": "TTS Integration",
"description": "Piper TTS setup, voice model management, and parameter support",
"estimated_days": "1-2"
},
{
"id": "phase_3",
"name": "Audio Playback",
"description": "sounddevice integration and audio error handling",
"estimated_days": "1"
},
{
"id": "phase_4",
"name": "Queue Management",
"description": "Async queue implementation and request processing pipeline",
"estimated_days": "1"
},
{
"id": "phase_5",
"name": "Error Handling",
"description": "Exception handlers, logging infrastructure, and health monitoring",
"estimated_days": "1"
},
{
"id": "phase_6",
"name": "Testing",
"description": "Unit tests, integration tests, performance tests, and system tests",
"estimated_days": "1-2"
},
{
"id": "phase_7",
"name": "Documentation & Deployment",
"description": "README, systemd service, and production hardening",
"estimated_days": "1"
}
],
"tasks": [
{
"id": "1.1.1",
"phase": "phase_1",
"name": "Initialize project directory",
"description": "Create project directory structure at /mnt/NV2/Development/voice-server with app/, tests/, models/ subdirectories",
"dependencies": [],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Directory already exists from PRD creation"
},
{
"id": "1.1.2",
"phase": "phase_1",
"name": "Create Python virtual environment",
"description": "Initialize virtual environment using uv (uv venv)",
"dependencies": ["1.1.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use uv as per user preference"
},
{
"id": "1.1.3",
"phase": "phase_1",
"name": "Install core dependencies",
"description": "Install fastapi, uvicorn[standard], piper-tts, sounddevice, numpy, pydantic, python-dotenv",
"dependencies": ["1.1.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Also install pytest, pytest-asyncio, httpx for testing"
},
{
"id": "1.1.4",
"phase": "phase_1",
"name": "Create pyproject.toml",
"description": "Create pyproject.toml with pinned dependency versions and project metadata",
"dependencies": ["1.1.3"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use uv's native pyproject.toml support instead of requirements.txt"
},
{
"id": "1.1.5",
"phase": "phase_1",
"name": "Create environment configuration",
"description": "Create .env.example with all configurable environment variables",
"dependencies": ["1.1.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Include HOST, PORT, QUEUE_SIZE, LOG_LEVEL, MODEL_DIR, DEFAULT_VOICE"
},
{
"id": "1.1.6",
"phase": "phase_1",
"name": "Initialize git repository",
"description": "Initialize git repo with .gitignore for Python, IDEs, .env, voice models, __pycache__",
"dependencies": ["1.1.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Add models/*.onnx and models/*.json to .gitignore (large files)"
},
{
"id": "1.2.1",
"phase": "phase_1",
"name": "Write tests for Pydantic request/response models",
"description": "TDD: Write tests for NotifyRequest, NotifyResponse, HealthResponse, ErrorResponse models with validation rules",
"dependencies": ["1.1.4"],
"completed": false,
"tested": false,
"test_approach": "tdd",
"notes": "Test message length limits (1-10000), rate range (50-400), voice pattern validation"
},
{
"id": "1.2.2",
"phase": "phase_1",
"name": "Implement Pydantic models",
"description": "Create app/models.py with NotifyRequest, NotifyResponse, HealthResponse, ErrorResponse models",
"dependencies": ["1.2.1"],
"completed": false,
"tested": true,
"test_approach": "tdd",
"notes": "Implementation to make tests from 1.2.1 pass"
},
{
"id": "1.2.3",
"phase": "phase_1",
"name": "Create FastAPI application skeleton",
"description": "Create app/main.py with FastAPI app, lifespan handler, and CORS middleware",
"dependencies": ["1.2.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use lifespan context manager (not deprecated on_event)"
},
{
"id": "1.2.4",
"phase": "phase_1",
"name": "Write tests for /notify endpoint contract",
"description": "TDD: Write tests for POST /notify - valid requests return 202, invalid return 422, missing fields return 400",
"dependencies": ["1.2.3"],
"completed": false,
"tested": false,
"test_approach": "tdd",
"notes": "Use httpx.AsyncClient for async endpoint testing"
},
{
"id": "1.2.5",
"phase": "phase_1",
"name": "Implement /notify endpoint skeleton",
"description": "Create POST /notify endpoint that validates request and returns 202 (queue integration later)",
"dependencies": ["1.2.4"],
"completed": false,
"tested": true,
"test_approach": "tdd",
"notes": "Initially just validate and return success; queue integration in phase 4"
},
{
"id": "1.2.6",
"phase": "phase_1",
"name": "Write tests for /health endpoint",
"description": "TDD: Write tests for GET /health - returns status, uptime, queue info structure",
"dependencies": ["1.2.3"],
"completed": false,
"tested": false,
"test_approach": "tdd",
"notes": "Test both healthy and unhealthy response structures"
},
{
"id": "1.2.7",
"phase": "phase_1",
"name": "Implement /health endpoint skeleton",
"description": "Create GET /health endpoint returning basic health status",
"dependencies": ["1.2.6"],
"completed": false,
"tested": true,
"test_approach": "tdd",
"notes": "Full health checks (TTS, audio) added in phase 5"
},
{
"id": "1.2.8",
"phase": "phase_1",
"name": "Implement /voices endpoint skeleton",
"description": "Create GET /voices endpoint returning list of available voice models",
"dependencies": ["1.2.3"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Initially return empty list; populate after TTS integration"
},
{
"id": "1.2.9",
"phase": "phase_1",
"name": "Configure JSON logging middleware",
"description": "Add structured JSON logging for all requests with timestamp, request_id, path, status_code",
"dependencies": ["1.2.3"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use Python's logging with JSON formatter"
},
{
"id": "1.2.10",
"phase": "phase_1",
"name": "Verify server startup",
"description": "Test server starts successfully with uvicorn app.main:app --reload",
"dependencies": ["1.2.5", "1.2.7", "1.2.8"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Verify /docs (Swagger UI) is accessible"
},
{
"id": "1.3.1",
"phase": "phase_1",
"name": "Write tests for configuration loading",
"description": "TDD: Write tests for config loading from env vars with defaults, validation of values",
"dependencies": ["1.1.5"],
"completed": false,
"tested": false,
"test_approach": "tdd",
"notes": "Test default values, env var override, invalid value handling"
},
{
"id": "1.3.2",
"phase": "phase_1",
"name": "Implement configuration module",
"description": "Create app/config.py with Settings class using pydantic-settings for env var loading",
"dependencies": ["1.3.1"],
"completed": false,
"tested": true,
"test_approach": "tdd",
"notes": "Include host, port, queue_size, log_level, model_dir, default_voice settings"
},
{
"id": "1.3.3",
"phase": "phase_1",
"name": "Add CLI argument parsing",
"description": "Add CLI argument support for --host, --port, --log-level to override env vars",
"dependencies": ["1.3.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use argparse or typer; CLI args take precedence over env vars"
},
{
"id": "2.1.1",
"phase": "phase_2",
"name": "Create TTS engine module structure",
"description": "Create app/tts_engine.py with TTSEngine abstract base and PiperTTSEngine class skeleton",
"dependencies": ["1.2.10"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Abstract base allows for future TTS engine swapping"
},
{
"id": "2.1.2",
"phase": "phase_2",
"name": "Download default voice model",
"description": "Download en_US-lessac-medium.onnx and .json to models/ directory",
"dependencies": ["1.1.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Can use piper --download-dir or manual download from GitHub releases"
},
{
"id": "2.1.3",
"phase": "phase_2",
"name": "Implement Piper TTS voice loading",
"description": "Implement PiperTTSEngine.load_voice() to load .onnx model with caching",
"dependencies": ["2.1.1", "2.1.2"],
"completed": false,
"tested": false,
"test_approach": "implementation_first",
"notes": "Cache loaded models in memory to avoid reload on each request"
},
{
"id": "2.1.4",
"phase": "phase_2",
"name": "Implement text-to-audio synthesis",
"description": "Implement PiperTTSEngine.synthesize() returning NumPy array of audio samples",
"dependencies": ["2.1.3"],
"completed": false,
"tested": false,
"test_approach": "implementation_first",
"notes": "Return float32 NumPy array compatible with sounddevice"
},
{
"id": "2.1.5",
"phase": "phase_2",
"name": "Write integration tests for TTS synthesis",
"description": "Write tests verifying TTS generates valid audio array for sample text",
"dependencies": ["2.1.4"],
"completed": false,
"tested": false,
"test_approach": "implementation_first",
"notes": "Test output is non-empty NumPy array with expected sample rate"
},
{
"id": "2.1.6",
"phase": "phase_2",
"name": "Measure TTS latency benchmarks",
"description": "Benchmark TTS generation time for various text lengths (10, 100, 500, 1000, 5000 chars)",
"dependencies": ["2.1.5"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Document results for performance baseline"
},
{
"id": "2.2.1",
"phase": "phase_2",
"name": "Create models directory structure",
"description": "Create models/ directory for voice model storage with README explaining model installation",
"dependencies": ["1.1.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Include instructions for downloading additional voices"
},
{
"id": "2.2.2",
"phase": "phase_2",
"name": "Implement voice model discovery",
"description": "Implement function to scan models/ directory and return available voice models",
"dependencies": ["2.2.1", "2.1.3"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Parse .json config files for model metadata (language, quality)"
},
{
"id": "2.2.3",
"phase": "phase_2",
"name": "Implement /voices endpoint fully",
"description": "Update /voices endpoint to return discovered models with metadata",
"dependencies": ["2.2.2", "1.2.8"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Include name, language, quality, size_mb, installed status"
},
{
"id": "2.2.4",
"phase": "phase_2",
"name": "Add voice validation to /notify",
"description": "Validate requested voice exists before queuing; return 422 if not found",
"dependencies": ["2.2.2", "1.2.5"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Provide helpful error message listing available voices"
},
{
"id": "2.3.1",
"phase": "phase_2",
"name": "Implement speech rate adjustment",
"description": "Add rate parameter support to TTS synthesis (50-400 WPM range)",
"dependencies": ["2.1.4"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Check if Piper supports rate adjustment natively or needs post-processing"
},
{
"id": "2.3.2",
"phase": "phase_2",
"name": "Test rate adjustment across range",
"description": "Test TTS output at rate=50, 100, 170 (default), 300, 400 WPM",
"dependencies": ["2.3.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Verify audio sounds correct at extremes"
},
{
"id": "2.3.3",
"phase": "phase_2",
"name": "Implement voice_enabled flag",
"description": "Add voice_enabled parameter to skip TTS for debugging/testing",
"dependencies": ["2.1.4"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "When false, skip TTS and audio playback but still process request"
},
{
"id": "3.1.1",
"phase": "phase_3",
"name": "Create audio player module",
"description": "Create app/audio_player.py with AudioPlayer class skeleton",
"dependencies": ["1.2.10"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use sounddevice for non-blocking playback"
},
{
"id": "3.1.2",
"phase": "phase_3",
"name": "Implement audio device verification",
"description": "Implement verify_audio_devices() to check for available output devices at startup",
"dependencies": ["3.1.1"],
"completed": false,
"tested": false,
"test_approach": "implementation_first",
"notes": "Use sd.query_devices() to enumerate devices"
},
{
"id": "3.1.3",
"phase": "phase_3",
"name": "Implement non-blocking playback",
"description": "Implement AudioPlayer.play() using sd.play() for non-blocking audio output",
"dependencies": ["3.1.2"],
"completed": false,
"tested": false,
"test_approach": "implementation_first",
"notes": "sd.play() returns immediately; audio plays in background thread"
},
{
"id": "3.1.4",
"phase": "phase_3",
"name": "Implement async wait method",
"description": "Implement AudioPlayer.wait_async() for async-friendly waiting on playback completion",
"dependencies": ["3.1.3"],
"completed": false,
"tested": false,
"test_approach": "implementation_first",
"notes": "Poll sd.get_stream().active with asyncio.sleep()"
},
{
"id": "3.1.5",
"phase": "phase_3",
"name": "Test audio playback with sample data",
"description": "Test AudioPlayer with synthesized sine wave to verify audio output works",
"dependencies": ["3.1.4"],
"completed": false,
"tested": false,
"test_approach": "implementation_first",
"notes": "Use numpy to generate test tone; verify sound is heard"
},
{
"id": "3.1.6",
"phase": "phase_3",
"name": "Verify non-blocking behavior",
"description": "Test that play() returns immediately and server can handle requests during playback",
"dependencies": ["3.1.5"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Send request, verify 202 returned before audio finishes"
},
{
"id": "3.2.1",
"phase": "phase_3",
"name": "Implement retry logic for device failures",
"description": "Implement RobustAudioPlayer with automatic retry on sd.PortAudioError",
"dependencies": ["3.1.4"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Retry up to 3 times with 0.5s delay between attempts"
},
{
"id": "3.2.2",
"phase": "phase_3",
"name": "Handle device disconnection",
"description": "Gracefully handle audio device disconnection during playback",
"dependencies": ["3.2.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Log error, skip playback, continue processing queue"
},
{
"id": "3.2.3",
"phase": "phase_3",
"name": "Implement audio diagnostics",
"description": "Implement get_audio_diagnostics() for health check reporting",
"dependencies": ["3.1.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Return device count, default output name, sample rate"
},
{
"id": "3.2.4",
"phase": "phase_3",
"name": "Add audio error logging",
"description": "Add detailed logging for all audio errors with device context",
"dependencies": ["3.2.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Include device name, error type, retry count in logs"
},
{
"id": "4.1.1",
"phase": "phase_4",
"name": "Write tests for queue behavior",
"description": "TDD: Write tests for queue enqueue, dequeue, overflow, ordering (FIFO)",
"dependencies": ["1.2.10"],
"completed": false,
"tested": false,
"test_approach": "tdd",
"notes": "Test max size enforcement, QueueFullError raising"
},
{
"id": "4.1.2",
"phase": "phase_4",
"name": "Create queue manager module",
"description": "Create app/queue_manager.py with TTSQueue class using asyncio.Queue",
"dependencies": ["4.1.1"],
"completed": false,
"tested": true,
"test_approach": "tdd",
"notes": "Implement to pass tests from 4.1.1"
},
{
"id": "4.1.3",
"phase": "phase_4",
"name": "Implement queue enqueue with timeout",
"description": "Implement TTSQueue.enqueue() with 1s timeout, raising QueueFullError on timeout",
"dependencies": ["4.1.2"],
"completed": false,
"tested": true,
"test_approach": "tdd",
"notes": "Return queue position on success"
},
{
"id": "4.1.4",
"phase": "phase_4",
"name": "Implement queue metrics",
"description": "Add stats tracking: processed count, error count, current size",
"dependencies": ["4.1.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Expose via TTSQueue.stats property"
},
{
"id": "4.1.5",
"phase": "phase_4",
"name": "Implement graceful queue shutdown",
"description": "Implement TTSQueue.shutdown() to wait for current item, reject new items",
"dependencies": ["4.1.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Called during application shutdown via lifespan"
},
{
"id": "4.2.1",
"phase": "phase_4",
"name": "Implement background queue processor",
"description": "Create async background task to process queue items sequentially",
"dependencies": ["4.1.2", "2.1.4", "3.1.4"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Generate TTS, play audio, wait for completion, then next item"
},
{
"id": "4.2.2",
"phase": "phase_4",
"name": "Integrate queue with /notify endpoint",
"description": "Update /notify to enqueue validated requests to TTSQueue",
"dependencies": ["4.2.1", "1.2.5"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Return queue_position in response"
},
{
"id": "4.2.3",
"phase": "phase_4",
"name": "Add request timeout handling",
"description": "Add 60s timeout for individual request processing in queue worker",
"dependencies": ["4.2.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Cancel TTS generation if exceeds timeout; log and continue"
},
{
"id": "4.2.4",
"phase": "phase_4",
"name": "Implement CPU-bound TTS in thread pool",
"description": "Run TTS synthesis in thread pool executor to avoid blocking event loop",
"dependencies": ["4.2.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use loop.run_in_executor() for TTS generation"
},
{
"id": "4.2.5",
"phase": "phase_4",
"name": "Test queue with concurrent requests",
"description": "Test sending 20+ concurrent requests and verify sequential playback",
"dependencies": ["4.2.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "All requests should be processed in order received"
},
{
"id": "4.3.1",
"phase": "phase_4",
"name": "Add queue status to /health",
"description": "Update /health to include queue size, capacity, utilization percentage",
"dependencies": ["4.1.4", "1.2.7"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Include processed and error counts"
},
{
"id": "4.3.2",
"phase": "phase_4",
"name": "Add queue event logging",
"description": "Log queue events: enqueue, process start, process complete, errors",
"dependencies": ["4.2.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Include request_id for correlation"
},
{
"id": "4.3.3",
"phase": "phase_4",
"name": "Test queue overflow scenarios",
"description": "Test behavior when queue reaches max size; verify 503 returned",
"dependencies": ["4.2.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Fill queue with slow requests, send additional request"
},
{
"id": "5.1.1",
"phase": "phase_5",
"name": "Write tests for error responses",
"description": "TDD: Write tests for all error response formats (400, 422, 500, 503)",
"dependencies": ["1.2.2"],
"completed": false,
"tested": false,
"test_approach": "tdd",
"notes": "Verify error response structure matches API spec"
},
{
"id": "5.1.2",
"phase": "phase_5",
"name": "Create custom exception classes",
"description": "Create app/exceptions.py with QueueFullError, TTSEngineError, AudioPlaybackError",
"dependencies": ["5.1.1"],
"completed": false,
"tested": true,
"test_approach": "tdd",
"notes": "Include error codes and details for each exception type"
},
{
"id": "5.1.3",
"phase": "phase_5",
"name": "Implement exception handlers",
"description": "Add FastAPI exception handlers for each custom exception type",
"dependencies": ["5.1.2"],
"completed": false,
"tested": true,
"test_approach": "tdd",
"notes": "Map exceptions to appropriate HTTP status codes"
},
{
"id": "5.1.4",
"phase": "phase_5",
"name": "Implement generic exception handler",
"description": "Add catch-all exception handler for unexpected errors (500)",
"dependencies": ["5.1.3"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Log full traceback but return sanitized error to client"
},
{
"id": "5.2.1",
"phase": "phase_5",
"name": "Configure structured JSON logging",
"description": "Set up logging with JSON formatter including timestamp, level, message, context",
"dependencies": ["1.2.9"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use python-json-logger or custom formatter"
},
{
"id": "5.2.2",
"phase": "phase_5",
"name": "Implement rotating file handler",
"description": "Configure RotatingFileHandler with 10MB max size, 5 backups",
"dependencies": ["5.2.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Write to voice-server.log in project directory"
},
{
"id": "5.2.3",
"phase": "phase_5",
"name": "Add request ID tracking",
"description": "Generate unique request_id for each request; include in all related logs",
"dependencies": ["5.2.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use UUID4; add to response headers for client correlation"
},
{
"id": "5.2.4",
"phase": "phase_5",
"name": "Test log rotation",
"description": "Verify log files rotate correctly when size limit reached",
"dependencies": ["5.2.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Generate enough log entries to trigger rotation"
},
{
"id": "5.3.1",
"phase": "phase_5",
"name": "Implement comprehensive /health endpoint",
"description": "Update /health with TTS engine, audio system, queue, and system resource checks",
"dependencies": ["4.3.1", "3.2.3"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Return 200 if all healthy, 503 if any component unhealthy"
},
{
"id": "5.3.2",
"phase": "phase_5",
"name": "Add TTS engine health check",
"description": "Test TTS engine can synthesize short test phrase",
"dependencies": ["2.1.4"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use minimal text to minimize overhead"
},
{
"id": "5.3.3",
"phase": "phase_5",
"name": "Add system resource monitoring",
"description": "Include CPU and memory usage in health check response",
"dependencies": ["5.3.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use psutil for system metrics"
},
{
"id": "5.3.4",
"phase": "phase_5",
"name": "Test health endpoint under load",
"description": "Verify /health responds correctly while queue is processing",
"dependencies": ["5.3.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Health check should not block or be blocked by TTS processing"
},
{
"id": "6.1.1",
"phase": "phase_6",
"name": "Set up pytest infrastructure",
"description": "Create tests/ directory with conftest.py, pytest.ini, test fixtures",
"dependencies": ["1.1.4"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Include async fixtures for FastAPI testing"
},
{
"id": "6.1.2",
"phase": "phase_6",
"name": "Write remaining unit tests",
"description": "Complete any missing unit tests to achieve 80%+ coverage",
"dependencies": ["6.1.1", "5.1.3"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use pytest-cov for coverage reporting"
},
{
"id": "6.2.1",
"phase": "phase_6",
"name": "Write end-to-end integration tests",
"description": "Test complete request flow from HTTP request to audio playback",
"dependencies": ["4.2.5"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "May need to mock audio output for CI environments"
},
{
"id": "6.2.2",
"phase": "phase_6",
"name": "Write error scenario tests",
"description": "Test TTS failure, audio failure, queue overflow scenarios end-to-end",
"dependencies": ["6.2.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Use dependency injection to simulate failures"
},
{
"id": "6.3.1",
"phase": "phase_6",
"name": "Create load testing script",
"description": "Create load test using locust or wrk for performance benchmarking",
"dependencies": ["4.2.5"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Target: 50+ req/s, <50ms API response time"
},
{
"id": "6.3.2",
"phase": "phase_6",
"name": "Measure performance benchmarks",
"description": "Record p50, p95, p99 latency; TTS generation time; memory usage",
"dependencies": ["6.3.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Document baseline performance for future comparison"
},
{
"id": "6.4.1",
"phase": "phase_6",
"name": "Test on target environment",
"description": "Run full test suite on Nobara/Fedora 42 with real audio hardware",
"dependencies": ["6.2.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Test with both PulseAudio and ALSA if possible"
},
{
"id": "6.4.2",
"phase": "phase_6",
"name": "Test long-running stability",
"description": "Run server for 24+ hours with periodic requests; check for memory leaks",
"dependencies": ["6.4.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Monitor memory usage over time"
},
{
"id": "7.1.1",
"phase": "phase_7",
"name": "Create comprehensive README",
"description": "Write README.md with overview, installation, configuration, usage, API docs, troubleshooting",
"dependencies": ["6.4.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Include example curl commands and Python client code"
},
{
"id": "7.1.2",
"phase": "phase_7",
"name": "Document voice model installation",
"description": "Create guide for downloading and installing additional Piper voice models",
"dependencies": ["2.2.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Link to Piper voice model repository"
},
{
"id": "7.1.3",
"phase": "phase_7",
"name": "Create example client scripts",
"description": "Create examples/ directory with curl, Python, and JavaScript client examples",
"dependencies": ["7.1.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Include async Python example using httpx"
},
{
"id": "7.2.1",
"phase": "phase_7",
"name": "Create systemd service file",
"description": "Create voice-server.service for systemd deployment",
"dependencies": ["6.4.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Include restart on failure, proper user/group, working directory"
},
{
"id": "7.2.2",
"phase": "phase_7",
"name": "Test systemd service",
"description": "Test service installation, start, stop, restart, and auto-restart on failure",
"dependencies": ["7.2.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Document installation steps in README"
},
{
"id": "7.2.3",
"phase": "phase_7",
"name": "Create deployment script",
"description": "Create deploy.sh script for automated deployment",
"dependencies": ["7.2.1"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Include venv setup, dependency install, service restart"
},
{
"id": "7.3.1",
"phase": "phase_7",
"name": "Configure production logging",
"description": "Set up production log levels (INFO default, DEBUG disabled)",
"dependencies": ["5.2.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Configurable via LOG_LEVEL environment variable"
},
{
"id": "7.3.2",
"phase": "phase_7",
"name": "Implement graceful shutdown",
"description": "Handle SIGTERM/SIGINT for graceful shutdown with queue draining",
"dependencies": ["4.1.5"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Wait for current playback to complete before exit"
},
{
"id": "7.3.3",
"phase": "phase_7",
"name": "Security audit",
"description": "Review input sanitization, resource limits, error message exposure",
"dependencies": ["6.2.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Verify no internal details leaked in error responses"
},
{
"id": "7.3.4",
"phase": "phase_7",
"name": "Performance tuning",
"description": "Tune queue size, worker count, timeouts based on benchmark results",
"dependencies": ["6.3.2"],
"completed": false,
"tested": false,
"test_approach": null,
"notes": "Document recommended settings for different use cases"
}
],
"summary": {
"total_tasks": 78,
"tdd_tasks": 12,
"implementation_first_tasks": 8,
"phases": 7,
"estimated_days": "4-7"
}
}