- Rename milestone from 'Features & Extensibility' to 'Multi-Library Support' - Replace old phases 10-14 (TAG/SMRT/GAP/MB/LAYOUT/PLUG) with 20 multi-library requirements (LIB/LSCAN/VIEW/PLAY/DATA) - Move deferred features to Future Requirements - Update research files with multi-library research (Stack, Features, Architecture, Pitfalls) - Architecture: hybrid model (library_id on audio_files only), libraries in DB, sequential scanning, phantom tracks
63 lines
2.5 KiB
Markdown
63 lines
2.5 KiB
Markdown
# Stack Research: Multi-Library Support
|
|
|
|
**Researched:** 2026-03-08
|
|
**Confidence:** HIGH
|
|
|
|
## Summary
|
|
|
|
Zero new Go packages needed. The existing stack handles everything required for multi-library support.
|
|
|
|
## Existing Stack (No Changes)
|
|
|
|
| Component | Package | Version | Role in Multi-Library |
|
|
|-----------|---------|---------|----------------------|
|
|
| Database | modernc.org/sqlite | v1.46.1 | ALTER TABLE, new tables, migration 6 |
|
|
| Query Gen | sqlc | v1.30.0 | New query files for libraries CRUD + filtered queries |
|
|
| Config | BurntSushi/toml | v1.6.0 | Migration source (DirectoryPath to DB) |
|
|
| Desktop | Wails | v2.10.2 | Binding patterns for library CRUD |
|
|
| Frontend | Lit | 3.2.1 | Reactive controllers for library state |
|
|
| Audio | gopxl/beep | v2 | No changes needed |
|
|
|
|
## Do NOT Add
|
|
|
|
- No ORM or query builder (fights existing sqlc architecture)
|
|
- No migration framework (goose, golang-migrate) — PRAGMA user_version works well with 5 existing migrations
|
|
- No UUID package — INTEGER PRIMARY KEY is the pattern
|
|
|
|
## SQLite Migration Patterns
|
|
|
|
### Adding library_id to audio_files
|
|
|
|
```sql
|
|
ALTER TABLE audio_files ADD COLUMN library_id INTEGER NOT NULL DEFAULT 0;
|
|
CREATE INDEX IF NOT EXISTS idx_audio_files_library_id ON audio_files(library_id);
|
|
```
|
|
|
|
SQLite limitation: `ALTER TABLE ADD COLUMN` cannot add FK constraints. Enforce at application level.
|
|
|
|
### track_metadata VIEW
|
|
|
|
Must DROP VIEW + CREATE VIEW (SQLite doesn't support ALTER VIEW). Add `af.library_id` to SELECT list. Follows migration 5 pattern exactly.
|
|
|
|
### playlist_tracks Table Rebuild
|
|
|
|
Change `ON DELETE CASCADE` to `ON DELETE SET NULL` on `audio_file_id`. Requires full table rebuild (migration 5 pattern: PRAGMA foreign_keys OFF -> create _new -> copy -> drop -> rename -> PRAGMA foreign_keys ON).
|
|
|
|
## sqlc Query Patterns
|
|
|
|
- Create `sql/queries/libraries.sql` for CRUD
|
|
- Create `ByLibrary` variants of key queries (GetAllTracksWithFullMetadataByLibrary, GetAllAlbumsWithDetailsByLibrary, etc.)
|
|
- Separate queries preferred over dynamic WHERE (cleaner types, better query plans)
|
|
- Hand-crafted FTS5 queries get `AND tm.library_id = ?` filter
|
|
|
|
## Frontend Patterns
|
|
|
|
- `LibraryStore` gains `selectedLibraryId` state (null = all libraries)
|
|
- Backend filtering (not frontend) — don't load 150K tracks when viewing one library
|
|
- Persist selection in localStorage
|
|
- `invalidate()` on library switch triggers refetch
|
|
|
|
## Config Migration
|
|
|
|
Libraries stored in SQLite (not TOML). Config `[Library].DirectoryPath` read once during migration, then deprecated. All library management through DB-backed methods.
|