Files
yellowjacket/.planning/research/PITFALLS.md
T
yonlu cdf8bff01a docs: restructure v1.1 milestone for multi-library support
- 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
2026-03-08 11:54:37 -04:00

101 lines
4.3 KiB
Markdown

# Pitfalls Research: Multi-Library Support
**Researched:** 2026-03-08
**Confidence:** HIGH
## Critical Pitfalls
### P1: SQLite ALTER TABLE ADD COLUMN with NOT NULL Requires DEFAULT
SQLite requires NOT NULL columns added via ALTER TABLE to have a default. Create `libraries` table and insert default library BEFORE adding `library_id` to `audio_files`. Use `DEFAULT {id}` where id is the auto-created library's ID.
**Phase:** Schema & Migration
### P2: Table Rebuild for CASCADE to SET NULL Must Audit ALL Tables
Both `playlist_tracks` AND `queue_tracks` have `ON DELETE CASCADE` on `audio_file_id`. Decision: playlist_tracks -> SET NULL (phantom support), queue_tracks -> keep CASCADE (queue is ephemeral). Must explicitly document this choice.
**Phase:** Schema & Migration
### P3: FTS5 Contentless Table Cannot Delete Individual Rows
After removing a library with 10K tracks, 10K stale FTS5 entries remain. Current JOIN filtering handles this, but FTS5 scoring is affected. Consider migrating to `contentless_delete=1` (SQLite 3.43.0+). Alternative: full rebuild after library removal.
**Phase:** Schema & Migration
### P4: Orphan Cleanup Through Entity Graph Is Complex
Reference-counting deletes must handle shared entities. Two libraries with same artist — removing one must not delete the artist if the other still references it. Use `NOT IN (SELECT ...)` or `LEFT JOIN ... WHERE ... IS NULL` pattern. Single transaction required.
**Phase:** Backend API / Library CRUD
### P5: Existing User Migration Must Be Seamless
First launch after update: migration 6 reads TOML DirectoryPath, creates library row, backfills audio_files.library_id. Test on real user database snapshot, not just fresh DB.
**Phase:** Schema & Migration
## Moderate Pitfalls
### P6: Frontend Memory Pressure with Multiple Large Libraries
`libraryStore.eagerFetch()` loads ALL data. 150K tracks x ~500 bytes = 75MB. Use backend filtering (pass library_id to queries). When "All Libraries" is selected, this is unavoidable for now — pagination is a future optimization.
**Phase:** Frontend
### P7: Scan Coordination — No Concurrent Scans
Single `scanActive` bool, single entity cache, single writer SQLite. Enforce one-scan-at-a-time globally with scan coordinator. Track which library is scanning for UI display.
**Phase:** Backend Scan Pipeline
### P8: Phantom Track Resolution with Multiple Library Roots
`LibraryDirProvider` returns single string. M3U8 path resolution checks one root. With multi-library, try all library roots for phantom resolution. Store phantom_file_path as absolute path to avoid ambiguity.
**Phase:** Frontend / Playlist Integration
### P9: Queue and Now-Playing During Library Removal
If currently playing track belongs to removed library: stop playback, advance to next non-removed track. Check queue and player state before proceeding with removal.
**Phase:** Backend API / Library CRUD
### P10: Cross-Library Entity Deduplication
Same artist in two libraries -> one `artists` row (UNIQUE constraint handles this). Removing one library's audio_files must NOT delete shared artist. Reference-counting cleanup handles this correctly.
**Phase:** Backend API / Library CRUD
## Minor Pitfalls
### P11: Config Migration — TOML to DB Split Creates Two Sources of Truth
Move ALL library-related config to DB. TOML only for app-level settings (theme, shortcuts, window). TOML `[Library]` section is migration source only.
**Phase:** Schema & Migration
### P12: Library Filter State Interacting with Everything
Single filter state in libraryStore. All data-fetching functions accept the filter. Trigger invalidate+refetch on filter change.
**Phase:** Frontend
### P13: Scan-While-Remove Race Condition
Before removing a library, cancel any active scan on it and wait for completion. Serialize scan and remove operations.
**Phase:** Backend API
### P14: Cover Art Files Not Library-Scoped
Cover art stored by content hash (shared). Removing a library: only delete cover_art DB rows that are truly orphaned (no remaining release_groups reference them). Then delete corresponding files.
**Phase:** Backend API
### P15: Testing Gaps
Create "two-library fixture" test helper. Test: add two libraries with overlapping artists -> remove one -> verify other is intact. Test migration on pre-multi-library DB snapshot.
**Phase:** All phases (accompanying tests)