ECHO Next Native Worker Ready Architecture
Library Core v0.1 is deliberately native-worker-ready. TypeScript owns orchestration, SQLite, IPC validation, pagination APIs, scan jobs, and UI-facing business rules. Heavy work is called through stable worker interfaces so Rust or C++ can replace the first TS implementation without changing Renderer, IPC, or the SQLite schema.
Worker Boundary
Section titled “Worker Boundary”Stable interfaces live under src/main/library/workers/:
MetadataReader.read(filePath) -> MetadataResultCoverExtractor.extract(filePath, options) -> CoverResultFileScanner.scanFolder(folderPath, options) -> AsyncIterable<ScannedFile>
Current implementations:
TsMetadataReader:music-metadata, embedded tags first, filename/folder fallback only for missing fieldsTsCoverExtractor: TS+sharp v0.2 cover worker; embedded cover, same-folder cover/front/folder image, generated default, cached paths on disk, and real resize outputTsFileScanner: recursive file enumeration and stat only
Future implementations can be swapped in as:
RustMetadataWorkerRustCoverWorkerRustFileScanner
LibraryService and ScanJobQueue depend on the interfaces, not on TS concrete classes. Renderer and preload never know which worker implementation is active.
Stable Return Shapes
Section titled “Stable Return Shapes”MetadataResult includes:
- normalized metadata fields
fieldSources- embedded cover bytes when available for the cover worker
warningserrorsstatus
CoverResult includes:
sourcethumbPathalbumPathlargePathoriginalRefsourceHashmimeTypewarningserrors
ScannedFile includes:
pathsizeBytesmtimeMs
These shapes are the contract a native worker must preserve. Raw parser details may exist inside the worker result for diagnostics, but Renderer list APIs do not receive them.
Rust/C++ Priority
Section titled “Rust/C++ Priority”Priority order for native work:
CoverWorker: highest priority only if TS+sharp v0.2 fails measured cover-generation targets.MetadataWorker: second priority; tag parsing can become expensive on large libraries.FileScanner: only Rust/C++ if 3000/10000 track pressure tests show TS directory walking is a bottleneck.
Audio output is already moving in the same direction through echo-audio-host.
Service Boundary
Section titled “Service Boundary”TypeScript service layer:
- creates scan jobs
- checks incremental cache keys
- schedules worker calls with concurrency limits
- writes SQLite in transactions
- persists album and artist indexes
- exposes paginated IPC-safe results
Worker layer:
- reads tags
- extracts/caches covers; current TS+sharp v0.2 uses
sharpfor resize while TypeScript owns priority and cache scheduling - enumerates files and stat data
IPC:
- validates input
- calls
LibraryService - does not run SQL, parse metadata, extract covers, or scan folders
Renderer:
- calls typed preload methods
- renders paginated tracks/albums/folders/status
- does not group albums, generate covers, scan files, or hold the full library in memory
Performance Budget
Section titled “Performance Budget”Targets for Phase 1 and Phase 1.5 validation:
- app startup must not scan the whole library
getTracksfirst page target: under 200 msgetAlbumsfirst page target: under 300 ms- unchanged scan skip rate should approach 100%
- cover thumbnails are generated during scan, not while UI scrolls
- album wall reads persisted
albumsrows after restart getTracksandgetAlbumsnever return full cover binary/base64- scan jobs run in the background and remain cancellable
- metadata and cover workers use concurrency limits
- large libraries must not leave CPU near 50% because an album wall is rendering
Phase 1.5 Validation
Section titled “Phase 1.5 Validation”Phase 1.5 Native Worker & Performance Validation:
- use Phase 1.1
library.getDiagnostics(), smoke tests, andnpm run benchmark:libraryresults before committing to native worker work - build a Go/C#/Rust
CoverWorkeronly if cover extraction/cache generation is the measured bottleneck - evaluate Rust
MetadataWorker - run 3000 and 10000 track pressure tests and 3000 and 10000 album-wall pressure tests
- record CPU, memory, total scan time, metadata time, cover time, and album wall load time
- decide from measurements whether
FileScannerneeds Rust/C++ - verify worker replacement does not change Renderer, IPC, SQLite schema, or list payloads
Native CoverWorker decision indicators:
- generating 1000 album thumbs keeps CPU above 50% for a long stretch
- generating 3000 or 10000 covers has unacceptable memory peaks
- Electron
sharppackaging or native rebuilds are unstable - cover cache hits remain slow after
thumb.webpandalbum.webpexist