docs: create milestone v1.2 roadmap (5 phases)

This commit is contained in:
2026-03-16 16:44:11 -04:00
parent 3cf016aec9
commit c158d6825c
3 changed files with 155 additions and 248 deletions
+23 -23
View File
@@ -91,32 +91,32 @@ Which phases cover which requirements. Updated during roadmap creation.
| Requirement | Phase | Status |
|-------------|-------|--------|
| SCHEMA-01 | | Pending |
| SCHEMA-02 | | Pending |
| WRITE-01 | | Pending |
| WRITE-02 | | Pending |
| WRITE-03 | | Pending |
| WRITE-04 | | Pending |
| WRITE-05 | | Pending |
| WRITE-06 | | Pending |
| SYNC-01 | | Pending |
| SYNC-02 | | Pending |
| SYNC-03 | | Pending |
| SYNC-04 | | Pending |
| EDIT-01 | | Pending |
| EDIT-02 | | Pending |
| EDIT-03 | | Pending |
| EDIT-04 | | Pending |
| BATCH-01 | | Pending |
| BATCH-02 | | Pending |
| BATCH-03 | | Pending |
| BATCH-04 | | Pending |
| SCHEMA-01 | Phase 15 | Pending |
| SCHEMA-02 | Phase 15 | Pending |
| WRITE-01 | Phase 16 | Pending |
| WRITE-02 | Phase 16 | Pending |
| WRITE-03 | Phase 19 | Pending |
| WRITE-04 | Phase 16 | Pending |
| WRITE-05 | Phase 15 | Pending |
| WRITE-06 | Phase 16 | Pending |
| SYNC-01 | Phase 16 | Pending |
| SYNC-02 | Phase 16 | Pending |
| SYNC-03 | Phase 16 | Pending |
| SYNC-04 | Phase 16 | Pending |
| EDIT-01 | Phase 17 | Pending |
| EDIT-02 | Phase 17 | Pending |
| EDIT-03 | Phase 17 | Pending |
| EDIT-04 | Phase 17 | Pending |
| BATCH-01 | Phase 18 | Pending |
| BATCH-02 | Phase 18 | Pending |
| BATCH-03 | Phase 18 | Pending |
| BATCH-04 | Phase 18 | Pending |
**Coverage:**
- v1.2 requirements: 20 total
- Mapped to phases: 0
- Unmapped: 20
- Mapped to phases: 20
- Unmapped: 0
---
*Requirements defined: 2026-03-16*
*Last updated: 2026-03-16 after initial definition*
*Last updated: 2026-03-16 — traceability updated with phase mappings (Phases 15-19)*
+75 -97
View File
@@ -1,14 +1,14 @@
# Roadmap: YellowJacket
**Created:** 2026-02-27
**Last updated:** 2026-03-08
**Current milestone:** v1.1 Multi-Library Support
**Last updated:** 2026-03-16
**Current milestone:** v1.2 Tag Editing
## Milestones
-**v1.0 Consolidation** — Phases 1-8 (shipped 2026-03-05) — [archive](milestones/v1.0-ROADMAP.md)
-**v1.1 Multi-Library Support** — Phases 9-13 complete (shipped 2026-03-16)
- **Performance Optimization** — Phase 14 complete (shipped 2026-03-15)
-**v1.1 Multi-Library Support** — Phases 9-14 (shipped 2026-03-16) — [archive](milestones/v1.1-ROADMAP.md)
- 🔨 **v1.2 Tag Editing** — Phases 15-19
## Phases
@@ -26,109 +26,82 @@
</details>
### v1.1 Multi-Library Support (Phases 9-13)
<details>
<summary>✅ v1.1 Multi-Library Support (Phases 9-14) — SHIPPED 2026-03-16</summary>
- [x] **Phase 9: Scan Cancellation & Keyboard Shortcuts** — Cancellable library scans and configurable keyboard shortcuts
- [x] **Phase 10: Schema & Migration** — Libraries table, library_id FK, playlist_tracks phantom rebuild, config migration (completed 2026-03-09)
- [x] **Phase 11: Per-Library Scan Pipeline** — Scan pipeline refactored for per-library scanning with sequential coordination (completed 2026-03-09)
- [x] **Phase 12: Library CRUD & Data Integrity** — Library management API, orphan cleanup, queue/playlist lifecycle, library manager UI (completed 2026-03-15)
- [x] **Phase 13: Library Views & Phantom Tracks** — Filtered presentation across all views, search, browse, and phantom track display (completed 2026-03-16)
- [x] Phase 9: Scan Cancellation & Keyboard Shortcuts (5/5 plans) — completed 2026-03-07
- [x] Phase 10: Schema & Migration (2/2 plans) — completed 2026-03-09
- [x] Phase 11: Per-Library Scan Pipeline (3/3 plans) — completed 2026-03-09
- [x] Phase 12: Library CRUD & Data Integrity (2/2 plans) — completed 2026-03-15
- [x] Phase 13: Library Views & Phantom Tracks (2/2 plans) — completed 2026-03-16
- [x] Phase 14: Performance Optimization (4/4 plans) — completed 2026-03-15
</details>
### v1.2 Tag Editing (Phases 15-19)
- [ ] **Phase 15: Schema Migration & Write Safety** — FTS5 contentless_delete migration and atomic file write utility
- [ ] **Phase 16: Tag Writing & Database Sync** — Format-specific tag writers (MP3, FLAC, cover art) with inline DB + FTS5 update pipeline
- [ ] **Phase 17: Single Track Edit** — End-to-end single track editing: UI → file write → DB sync → view refresh
- [ ] **Phase 18: Batch Edit** — Multi-select batch editing with three-state field model, progress, and batch cover art
- [ ] **Phase 19: OGG Vorbis Tag Writing** — Custom OGG page rewriter for Vorbis Comment tag writing (stretch)
## Phase Details
### Phase 9: Scan Cancellation & Keyboard Shortcuts
**Goal:** Users can control library scans (cancel/pause/resume) and operate the entire app via keyboard
**Depends on:** Nothing (builds on v1.0 foundation)
**Requirements:** SCAN-01, SCAN-02, SCAN-03, KEY-01, KEY-02, KEY-03, KEY-04, KEY-05
### Phase 15: Schema Migration & Write Safety
**Goal:** The database and file system infrastructure supports safe, reversible tag editing — FTS5 rows can be deleted/updated and file writes never corrupt audio files
**Depends on:** Nothing (builds on v1.1 foundation)
**Requirements:** SCHEMA-01, SCHEMA-02, WRITE-05
**Success Criteria** (what must be TRUE):
1. User can click a cancel button during a library scan and the scan stops within seconds — no database corruption, no orphaned tracks
2. User can pause a running scan and resume it later without re-processing files that were already scanned
3. Default keyboard shortcuts work immediately after install — play/pause, next/prev, volume up/down, search focus, queue toggle, shuffle, repeat all respond to keys
4. User can open a settings UI, rebind any shortcut to a different key, and the new binding takes effect immediately — conflicts are warned about before saving
5. Keyboard shortcuts are context-aware — typing in a search box doesn't trigger player shortcuts (except Escape to blur)
**Plans:** 5 plans
Plans:
- [x] 09-01-PLAN.md — Backend scan control (cancel/pause/resume methods, events, metrics)
- [x] 09-02-PLAN.md — Backend shortcuts config + frontend keyboard shortcut service
- [x] 09-03-PLAN.md — Frontend scan control UI (buttons, cancel dialog)
- [x] 09-04-PLAN.md — Frontend shortcut settings UI (record-style capture, conflict detection)
- [x] 09-05-PLAN.md — Integration verification checkpoint
1. FTS5 search_index uses `contentless_delete=1` — deleting or updating a track's metadata in the DB correctly removes the old FTS5 entry without stale ghost results appearing in search
2. Existing search functionality is unaffected — all current queries, ranking, and library-filtered search continue to work identically after migration
3. The atomic write utility writes to a temp file in the same directory as the target, then renames — if the process crashes mid-write, the original file is intact and the temp file is cleaned up on next startup
4. Unit tests verify atomic write behavior: successful write, crash simulation (temp file left behind), and cross-directory rejection
**Plans:** TBD
### Phase 10: Schema & Migration
**Goal:** The database supports multiple libraries and phantom tracks — existing users upgrade seamlessly
**Depends on:** Phase 9 (builds on existing schema and scan infrastructure)
**Requirements:** DATA-01, DATA-04, LIB-04, LIB-05, LSCAN-05
### Phase 16: Tag Writing & Database Sync
**Goal:** The backend can write metadata tags and cover art to MP3 and FLAC files, then synchronize all changes to the database and search index in a single atomic operation
**Depends on:** Phase 15 (requires atomic write utility and FTS5 contentless_delete)
**Requirements:** WRITE-01, WRITE-02, WRITE-04, WRITE-06, SYNC-01, SYNC-02, SYNC-03, SYNC-04
**Success Criteria** (what must be TRUE):
1. A fresh install creates a `libraries` table and `audio_files.library_id` FK — new audio files are always associated with a library
2. An existing user's database is migrated on first launch: their single directory becomes a named library, all existing audio_files get that library_id, and everything works without any user action
3. The `playlist_tracks` table supports nullable `audio_file_id` with phantom metadata columns — the schema is ready for phantom track preservation
4. All migration operations complete atomically — a crash mid-migration leaves the database unchanged (not half-migrated)
**Plans:** 2/2 plans complete
Plans:
- [x] 10-01-PLAN.md — Schema definitions + Migration 6 (libraries table, library_id FK, phantom columns, track_metadata VIEW, backup, TOML migration)
- [x] 10-02-PLAN.md — sqlc queries for libraries + updated playlist phantom queries + migration integration tests
1. A Go function can accept a track ID and a set of changed metadata fields, write those tags to an MP3 file (ID3v2), and the tags are readable back by the existing metadata reader — round-trip correctness verified by unit tests with real audio files
2. The same function works for FLAC files (Vorbis Comments) — including files with existing padding blocks and multiple metadata blocks
3. Cover art images (JPEG/PNG) can be embedded in both MP3 and FLAC files — the embedded image is readable back and the existing cover art pipeline (extraction, thumbnails) works with the newly embedded art
4. After a tag write, the database reflects the new metadata within the same operation: artist/album/genre entities are created or relinked (never mutated in-place), orphaned entities with zero remaining references are cleaned up, and the FTS5 index is updated — no library rescan needed
5. If the currently-playing track is being edited, playback is stopped before the file write begins — the user does not experience a crash or corrupted audio stream
**Plans:** TBD
### Phase 11: Per-Library Scan Pipeline
**Goal:** Users can scan individual libraries independently with proper sequential coordination
**Depends on:** Phase 10 (requires libraries table and library_id FK)
**Requirements:** LSCAN-01, LSCAN-02, LSCAN-03, LSCAN-04
### Phase 17: Single Track Edit
**Goal:** Users can edit any track's metadata and cover art from within the app and see changes reflected everywhere immediately
**Depends on:** Phase 16 (requires tag writers and DB sync pipeline)
**Requirements:** EDIT-01, EDIT-02, EDIT-03, EDIT-04
**Success Criteria** (what must be TRUE):
1. User can trigger a scan for a specific library and only that library's directory is scannedother libraries are untouched
2. Only one library scans at a time — requesting a second scan while one is running either queues it or is rejected with clear feedback
3. Scan progress UI identifies which library is currently being scanned (library name visible in progress indicator)
4. Existing cancel and pause/resume controls work correctly for per-library scans — cancelling one library's scan doesn't affect others
**Plans:** 3/3 plans complete
Plans:
- [x] 11-01-PLAN.md — Backend scan queue coordinator, per-library scan methods, CreateAudioFile with library_id
- [x] 11-02-PLAN.md — Frontend progress UI with library name, cancel scope modal, Scan All button
- [x] 11-03-PLAN.md — App startup auto-scan wiring, legacy single-directory cleanup
1. User can right-click any track (in track list, album detail, queue, or playlist) and open a tag editor dialog — the editor is accessible from every place tracks appear
2. The editor displays all 8 editable fields (title, artist, album, genre, year, track number, disc number, composer) pre-populated with the track's current values — empty fields show as empty, not "Unknown"
3. The editor displays the track's current cover art (or a placeholder if none) with a button to select a replacement image file from disk
4. Clicking "Save" writes the changes to the audio file, updates the database and search index, and refreshes all visible views (track list, album view, artist view, genre view, queue, now-playing bar) — the user sees the new metadata everywhere without restarting or rescanning
**Plans:** TBD
### Phase 12: Library CRUD & Data Integrity
**Goal:** Users can add, rename, and remove libraries through the UI with correct data lifecycle management
**Depends on:** Phase 11 (requires per-library scanning for add-then-scan workflow)
**Requirements:** LIB-01, LIB-02, LIB-03, LIB-06, DATA-02, DATA-03, PLAY-04
### Phase 18: Batch Edit
**Goal:** Users can efficiently edit shared metadata across multiple tracks at once with clear visual feedback and safe defaults
**Depends on:** Phase 17 (requires single-track edit pipeline as foundation)
**Requirements:** BATCH-01, BATCH-02, BATCH-03, BATCH-04
**Success Criteria** (what must be TRUE):
1. User can add a new library via folder picker, give it a name, and trigger a scan — new tracks appear in the library
2. User can rename a library's display name and the change reflects everywhere immediately
3. User can remove a library — its tracks are deleted, shared artists/albums/genres used only by that library are cleaned up, but entities shared with other libraries survive intact
4. Removing a library cleans up FTS5 search index entries for that library's tracks (no stale search results)
5. Queue tracks from a removed library are cascade-deleted; the queue continues playing from the next valid track
**Plans:** 2/2 plans complete
Plans:
- [x] 12-01-PLAN.md — Backend CRUD API + orphan cleanup + queue compaction + events
- [x] 12-02-PLAN.md — Frontend library management UI in settings + sidebar cleanup
1. User can select multiple tracks (via multi-select in track list or album detail) and open a batch editor — the batch editor is accessible from the same context menu as single-track edit
2. Each field in the batch editor shows one of three states: "keep original" (mixed values, no change), "set to value" (apply this value to all selected tracks), or "clear field" (remove this value from all) — the user can see which fields differ across the selection and choose per-field what to do
3. For batch operations on 10+ tracks, a progress indicator shows how many tracks have been processed — the user is never left staring at a frozen UI wondering if the operation is working
4. User can set cover art for all selected tracks at once — the same image is embedded in every selected file
**Plans:** TBD
### Phase 13: Library Views & Phantom Tracks
**Goal:** Users experience a unified multi-library presentation with optional filtering and graceful playlist preservation
**Depends on:** Phase 12 (requires library CRUD and data integrity for full integration)
**Requirements:** VIEW-01, VIEW-02, VIEW-03, VIEW-04, PLAY-01, PLAY-02, PLAY-03
### Phase 19: OGG Vorbis Tag Writing
**Goal:** Users can edit tags on OGG Vorbis files with the same experience as MP3 and FLAC — completing full format coverage
**Depends on:** Phase 16 (requires tag writer interface and DB sync pipeline)
**Requirements:** WRITE-03
**Success Criteria** (what must be TRUE):
1. The default track list shows tracks from all libraries merged — the user sees their complete collection as one unified view
2. User can select a specific library from a filter control and all views (tracks, albums, artists, genres) show only that library's content
3. Search results respect the active library filter — searching with a library selected returns only matches from that library; with "All Libraries" selected, searches everything
4. Playlists can contain tracks from multiple libraries — adding tracks from different libraries to the same playlist works naturally
5. When a library is removed, its tracks in playlists become phantom entries — visually distinguished (greyed out / icon) with preserved title, artist, album metadata instead of disappearing
**Plans:** 2/2 plans complete
Plans:
- [x] 13-01-PLAN.md — Backend library-filtered sqlc queries + Go methods + FTS search
- [x] 13-02-PLAN.md — Frontend library filter store + dropdown UI + all view/search wiring + verification
### Phase 14: Performance Optimization
**Goal:** Scrolling, navigation, and rendering are as smooth and fast as possible — scrolling feels like a native animation, navigation is instant, no unnecessary re-renders
**Depends on:** Nothing (cross-cutting, can execute in parallel with v1.1 phases)
**Requirements:** PERF-SCROLL-01, PERF-SCROLL-02, PERF-SCROLL-03, PERF-NAV-01, PERF-NAV-02, PERF-RENDER-01, PERF-RENDER-02, PERF-DIAG-01
**Success Criteria** (what must be TRUE):
1. Scrolling in all views (tracks, albums, artists, genres, queue, playlists) is smooth at 60fps — no jank, no stuttering, no blank areas
2. Navigating between primary views (tracks, albums, artists, genres, playlists, settings) is near-instant — no component destruction/recreation, scroll positions preserved
3. Render hot paths (renderTrackRow, renderTrackItem) create zero new closures per frame — all event handling uses delegation
4. Store notifications are batched (queueMicrotask) and components only re-render when their relevant data changes
5. A profiling guide documents how to diagnose performance issues using pprof (backend) and DevTools (frontend)
**Plans:** 4/4 plans complete
Plans:
- [x] 14-01-PLAN.md — CSS containment + GPU layer promotion on all scroll containers
- [x] 14-02-PLAN.md — View caching navigation system (replace innerHTML destruction)
- [x] 14-03-PLAN.md — Render hot-path optimization (closure elimination, store granularity)
- [x] 14-04-PLAN.md — Scroll event optimization, profiling guide, performance verification checkpoint
1. A Go function can write Vorbis Comment metadata tags to OGG Vorbis files using a custom OGG page rewriter — the file remains a valid OGG stream after writing (playable by the existing player and by external players)
2. Tag writes to OGG files use the same atomic write-to-temp-then-rename pattern as MP3/FLAC — no corruption risk
3. OGG tag editing is seamlessly integrated into the single-track and batch edit UIs — the user doesn't need to know or care what format a file is; the editor just works
**Plans:** TBD
## Progress
@@ -146,9 +119,14 @@ Plans:
| 10. Schema & Migration | v1.1 | 2/2 | Complete | 2026-03-09 |
| 11. Per-Library Scan Pipeline | v1.1 | 3/3 | Complete | 2026-03-09 |
| 12. Library CRUD & Data Integrity | v1.1 | 2/2 | Complete | 2026-03-15 |
| 13. Library Views & Phantom Tracks | v1.1 | Complete | 2026-03-16 | 2026-03-16 |
| 14. Performance Optimization | Perf | 4/4 | Complete | 2026-03-15 |
| 13. Library Views & Phantom Tracks | v1.1 | 2/2 | Complete | 2026-03-16 |
| 14. Performance Optimization | v1.1 | 4/4 | Complete | 2026-03-15 |
| 15. Schema Migration & Write Safety | v1.2 | 0/? | Not started | - |
| 16. Tag Writing & Database Sync | v1.2 | 0/? | Not started | - |
| 17. Single Track Edit | v1.2 | 0/? | Not started | - |
| 18. Batch Edit | v1.2 | 0/? | Not started | - |
| 19. OGG Vorbis Tag Writing | v1.2 | 0/? | Not started | - |
---
*Roadmap created: 2026-02-27*
*Last updated: 2026-03-16 — v1.1 milestone complete (Phases 9-14 all done)*
*Last updated: 2026-03-16 — v1.2 Tag Editing milestone roadmap created (Phases 15-19)*
+57 -128
View File
@@ -2,13 +2,13 @@
gsd_state_version: 1.0
milestone: v1.2
milestone_name: Tag Editing
status: defining_requirements
last_updated: "2026-03-16T20:03:38.282Z"
status: roadmap_created
last_updated: "2026-03-16T21:00:00.000Z"
progress:
total_phases: 6
completed_phases: 6
total_plans: 18
completed_plans: 18
total_phases: 5
completed_phases: 0
total_plans: 0
completed_plans: 0
---
# YellowJacket — Project State
@@ -22,53 +22,48 @@ See: .planning/PROJECT.md (updated 2026-03-16)
## Current Position
Phase: Not started (defining requirements)
Phase: Phase 15 — Schema Migration & Write Safety (not started)
Plan: —
Status: Defining requirements for v1.2 Tag Editing
Last activity: 2026-03-16 — Milestone v1.2 started
Status: Roadmap created, ready for phase planning
Last activity: 2026-03-16 — v1.2 roadmap created (5 phases, 20 requirements mapped)
### Phase Overview
| Phase | Status |
|-------|--------|
| 9. Scan Cancellation & Keyboard Shortcuts | Complete (5/5 plans) ✅ |
| 10. Schema & Migration | Complete (2/2 plans) ✅ |
| 11. Per-Library Scan Pipeline | Complete (3/3 plans) ✅ |
| 12. Library CRUD & Data Integrity | Complete (2/2 plans) ✅ |
| 13. Library Views & Phantom Tracks | Complete (2/2 plans) ✅ |
| 14. Performance Optimization | Complete (4/4 plans) ✅ |
| 15. Schema Migration & Write Safety | Not started |
| 16. Tag Writing & Database Sync | Not started |
| 17. Single Track Edit | Not started |
| 18. Batch Edit | Not started |
| 19. OGG Vorbis Tag Writing | Not started |
### v1.2 Requirement Coverage
| Category | Requirements | Phase(s) |
|----------|-------------|----------|
| Schema & Safety | SCHEMA-01, SCHEMA-02 | Phase 15 |
| Tag Writing | WRITE-01, WRITE-02 | Phase 16 |
| Tag Writing | WRITE-03 | Phase 19 |
| Tag Writing | WRITE-04, WRITE-05, WRITE-06 | Phase 15, 16 |
| Database Sync | SYNC-01, SYNC-02, SYNC-03, SYNC-04 | Phase 16 |
| Single Track Edit | EDIT-01, EDIT-02, EDIT-03, EDIT-04 | Phase 17 |
| Batch Edit | BATCH-01, BATCH-02, BATCH-03, BATCH-04 | Phase 18 |
## Performance Metrics
**v1.0 baseline:** 8 phases, 17 plans, 34 tasks in 6 days (107 commits)
**v1.1 scope:** Phase 9 complete (5 plans), Phases 10-13 pending (20 requirements across 4 phases)
**v1.1 baseline:** 6 phases, 18 plans in 10 days (~85 commits)
**v1.2 scope:** 5 phases, 20 requirements
| Phase | Plan | Duration | Tasks | Files |
|-------|------|----------|-------|-------|
| 09-01 | scan control backend | 16 min | 2 | 5 |
| 09-02 | keyboard shortcuts config & service | 35 min | 2 | 12 |
| 09-04 | keyboard shortcuts settings UI | 5 min | 2 | 2 |
| 09-03 | scan control UI | 2 min | 1 | 3 |
| 09-05 | integration testing & verification | 3 min | 2 | 1 |
| Phase 10-01 P01 | 11 min | 2 tasks | 10 files |
| Phase 10-02 P02 | 5 min | 2 tasks | 9 files |
| Phase 11-01 P01 | 7 min | 2 tasks | 11 files |
| Phase 11-03 P03 | 10 min | 1 task | 3 files |
| Phase 11-02 P02 | 4 min | 2 tasks | 2 files |
| Phase 12-01 P01 | 6 min | 2 tasks | 6 files |
| Phase 14-02 P02 | 1 min | 1 task | 1 file |
| Phase 14-03 P03 | 4 min | 2 tasks | 5 files |
| Phase 14-01 P01 | 3 min | 2 tasks | 7 files |
| Phase 14-04 P04 | 2 min | 2 tasks | 3 files |
| Phase 12-02 P02 | 38 min | 3 tasks | 19 files |
| Phase 13 P01 | 5 min | 2 tasks | 10 files |
| Phase 13 P02 | 9 min | 1 task | 12 files |
| (v1.2 plans not yet started) | | | | |
## Accumulated Context
### Key Decisions
Decisions from v1.0 are archived in PROJECT.md Key Decisions table. Key patterns to carry forward:
Decisions from v1.0 and v1.1 are archived in PROJECT.md Key Decisions table. Key patterns to carry forward:
- Mutex-protected setter pattern (lock → write → release → callbacks)
- SAFETY comment convention for hand-crafted SQL
@@ -76,117 +71,51 @@ Decisions from v1.0 are archived in PROJECT.md Key Decisions table. Key patterns
- Design tokens via `:host` scoped CSS custom properties
- queueMicrotask coalescing for store notifications
- `.renderItem` + `.keyFunction` (not `repeat()` children) for lit-virtualizer
- Upsert-and-relink for shared entities (never mutate shared artist/album/genre rows)
- ScanHooks/RemovalHooks/RescanHooks callback patterns for cross-package coordination
### v1.1 Roadmap Decisions
### v1.2 Roadmap Decisions
| Decision | Rationale |
|----------|-----------|
| Phase 9 = Scan Cancel + Shortcuts | Quick wins, validate context cancellation and config extension patterns |
| v1.1 restructured for multi-library | Tag editing, smart playlists, gapless, MusicBrainz, layout, plugins deferred to future milestones |
| Hybrid model (library_id on audio_files only) | Physical files belong to libraries; logical entities (artists, albums, genres) are global/shared |
| Libraries in DB, not TOML | CRUD through UI shouldn't require TOML manipulation; DB is source of truth |
| SET NULL for playlist_tracks FK | Phantom tracks preserve playlist structure when library removed |
| CASCADE for queue_tracks FK | Queue is ephemeral, not user-curated like playlists |
| Sequential scanning | SQLite single-writer makes parallel scans pointless |
| Backend filtering, not frontend | Don't load 150K tracks when viewing one library |
| 4 multi-library phases (10-13) | Natural delivery boundaries: schema → scan → CRUD → views, each phase delivers verifiable capability |
### Phase 10 Decisions
| Decision | Rationale |
|----------|-----------|
| Underscore prefix `_libraries.sql` for schema ordering | Go embed.FS ReadDir sorts alphabetically; `_` < `a` ensures libraries table created before audio_files FK |
| Sentinel library id=0 in test DB | Existing tests use DEFAULT library_id=0; sentinel row satisfies FK without modifying every test |
| TOML cleanup via generic map[string]any | Preserves all config sections when removing only DirectoryPath; no dependency on full Config struct |
| sql.NullInt64 for nullable playlist_tracks.audio_file_id | Phantom tracks have NULL audio_file_id; generated sqlc code requires sql.Null types |
| COALESCE fallback chain: live → phantom → empty | Playlist queries use 3-level COALESCE so callers always get usable string values |
| is_phantom computed column via CASE WHEN | Eliminates null-checking logic in callers; simple int64 boolean (0/1) |
### Phase 11 Decisions
| Decision | Rationale |
|----------|-----------|
| Library ID threaded via importResult | Explicit data flow through scan pipeline, avoids mutating shared Library struct state |
| scanInternal returns *ScanMetrics only | Called from goroutine in scan queue, error return impractical; errors logged + accumulated in Warnings |
| Auto worker count per library path | Each library may be on different storage (SSD/HDD), auto-detect per scan |
| Backward-compatible Scan() wrapper | Keeps handleConfigUpdate and FullRescan working without changes |
| Queue-aware cancel dialog scope choice | Two-option "Cancel This Library / Cancel All" only when queuedCount > 0; single-scan keeps existing pattern |
| handleScanComplete defers reset when queue draining | Prevents premature scanning=false before next library starts |
| FullRescan uses first library from GetAllLibraries | Per-library rescan deferred to Phase 12; preserves backward compatibility for config-page "Rescan" button |
| LibraryConfigChanged handler removed entirely | Multi-library model uses CRUD API (Phase 12), not event-driven config updates |
| Scan() wrapper deleted | Only callers were handleConfigUpdate (deleted) and FullRescan (updated to scanInternal) |
### Phase 12 Decisions
| Decision | Rationale |
|----------|-----------|
| Application-level name uniqueness check (iterate GetAllLibraries) | Avoids migration 7; rename is infrequent, check is simple |
| RemovalHooks callback struct (StopPlayback + CompactQueue) | Mirrors RescanHooks pattern; breaks circular dependency between library, player, queue packages |
| querySingleInt64 helper for hand-crafted SQL aggregates | DB type has QueryContext (returns *sql.Rows) but no QueryRowContext; helper wraps scan-close cycle |
| Sentinel errors for all validation per err113 | errLibraryNameEmpty, errLibraryNameTooLong, errLibraryNameDuplicate, errLibraryPathNotExist |
| Pre-populate phantom metadata BEFORE cascade delete | Avoids lost join data — playlist_tracks need track metadata after audio_files rows are gone |
| Selectable library checkboxes for scan targeting | User selects which libraries to scan instead of scan-all-or-nothing; Set<number> model with select-all/indeterminate |
| Inline progress bar per library row | Each library row shows scan phase and percentage, replacing global-only indicator |
| Collapsible config sections with chevron dropdown | Keeps settings page organized as it grows; new config-section component |
| Library store invalidation on LibraryRemoved event | Ensures all data views refresh after library removal |
### Phase 14 Decisions
| Decision | Rationale |
|----------|-----------|
| Primary views cached, detail views ephemeral | Detail views depend on entity IDs that change; caching would show stale content |
| Inline style.display toggle over CSS class | Simpler, no specificity issues, empty string restores natural display value |
| viewCache bounded at 6 entries | One per primary view — negligible memory since data is already in store caches |
| contain: strict only on .main-panel | Has explicit dimensions (flex: 1, overflow: hidden); elsewhere use layout style to not break flex |
| will-change: transform only on scroll containers | Not on :host — avoids wasting GPU memory on non-scrolling elements |
| content-visibility: auto on album cards with contain-intrinsic-size | Prevents layout shift during scroll while skipping off-screen rendering |
| Event delegation via data-index + closest() for virtualizer items | Zero per-item closures in renderItem; all events delegated on virtualizer element |
| changeGeneration counter in library store | Simpler than typed subscriptions; skips requestUpdate on loading-only transitions |
| RAF throttle over debounce for scroll saves | Saves position once per frame during scrolling, not just after stop; prevents lost positions on quick navigation |
| Keep monkey-patch alongside overflow-anchor CSS | CSS overflow-anchor disables browser anchoring but not lit-virtualizer's internal _correctScrollError |
### Phase 13 Decisions
| Decision | Rationale |
|----------|-----------|
| IN-subquery pattern for album/artist/genre library filtering | Entities are global, tracks belong to libraries; subquery filters entity IDs by library membership |
| Empty slice return (not error) for library with no tracks | Empty library is valid state, not error condition; callers handle empty UI |
| Client-side search with filtered data source | rankTracks filters already-loaded tracks; no backend SearchTracksByLibrary call needed |
| Native select for library filter dropdown | Compact, accessible, matches top bar height; no custom component overhead |
| getAlbumsByArtistNameCached returns null when filter active | Avoids stale cross-library data; forces backend query for consistency |
| ScanHooks callback for phantom resolution | Mirrors RemovalHooks/RescanHooks pattern; avoids circular dependency between library and playlist packages |
| phantom_file_path column on playlist_tracks | Stored at removal time for post-scan matching; enables automatic phantom resolution |
| M3U8-based phantom resolution over SQL-only | Reads playlist files to match by position and file path; handles both pre-existing and new phantoms |
| 5 phases (15-19) for 20 requirements | Natural clustering: foundation → writers → single edit → batch edit → stretch OGG |
| WRITE-05 in Phase 15 (not 16) | Atomic write utility is foundational infrastructure, not format-specific |
| Cover art embed (WRITE-04) in Phase 16 | Cover art embedding is format-specific writer work, shares test infrastructure with tag writing |
| Cover art UI (EDIT-03) in Phase 17 | Cover art selection UX is part of the single-track edit dialog |
| OGG as separate Phase 19 (stretch) | Custom OGG page rewriter is MEDIUM-HIGH risk; MP3+FLAC covers vast majority of libraries |
| SYNC-04 (scan pause during edits) in Phase 16 | Scan/edit mutual exclusion is part of the write pipeline, not the UI layer |
| Phase 18 depends on Phase 17 | Batch editing is N × single with UI complexity on top; pipeline must be solid first |
| Phase 19 depends on Phase 16 (not 17) | OGG writing is a backend writer addition; UI integration is format-transparent |
### Warnings (carry forward)
- Player lock ordering (`p.mu` before `speaker.Lock()`, goroutine dispatch in beep callback) — carry forward
- Player lock ordering (`p.mu` before `speaker.Lock()`, goroutine dispatch in beep callback)
- modernc.org/libc version must match exactly when updating modernc.org/sqlite
- `@lit-labs/signals` is experimental (v0.2.0) — not blocking but noted
- Scan cancellation: skip orphan cleanup on cancelled scans — Phase 9 ✅ (implemented in 09-01)
- Volume mutations (ChangeVolume/MuteToggle) must emit events + persist state — Phase 9 ✅ (fixed in 09-05)
- ALTER TABLE ADD COLUMN requires DEFAULT for NOT NULL — create libraries table first
- Table rebuild must audit ALL CASCADE FKs (playlist_tracks AND queue_tracks)
- FTS5 contentless can't DELETE rows — stale entries accumulate after library removal; consider contentless_delete migration
- FTS5 contentless can't DELETE rows — **SCHEMA-01 fixes this** with contentless_delete migration
- Orphan cleanup must not delete shared entities across libraries (reference-counting bottom-up)
- Existing user migration must be seamless (TOML DirectoryPath to DB libraries table)
### Deferred Improvements
- **Bulk phantom matching performance** — `FindPhantomMatches` runs 3 sequential DB queries per phantom track (basename search, FTS filename, FTS keywords). With hundreds of phantoms this is O(n×3) round trips. Could batch the basename query (WHERE basename IN (...)), pre-load FTS results, or parallelize with goroutines. Not urgent now that the false-phantom bug is fixed (tracks appeared phantom due to empty library root, not actual missing files). Revisit if users import large playlists from external sources with genuinely unresolved paths.
- FLAC files require full rewrite for tag changes — atomic write-to-temp-then-rename mandatory
- Currently-playing file must be stopped before writing (WRITE-06) — Windows file locking is especially strict
- Shared entity fan-out — editing one track's artist must NOT mutate the shared artist_credit row
### Research Flags
- **Multi-library research complete** — see `.planning/research/` (STACK.md, FEATURES.md, ARCHITECTURE.md, PITFALLS.md, SUMMARY.md)
- **Phase 16:** go-flac libraries (44 stars) — verify round-trip with edge-case FLAC files early
- **Phase 19:** Custom OGG page rewriter — prototype before committing; consider dropping if too complex
- **Phase 16:** Album artist storage — not currently a separate entity; resolve during planning
### Deferred Improvements
- **Bulk phantom matching performance** — O(n×3) round trips per phantom. Revisit if large external playlist imports occur.
## Session Continuity
### Last Session
**Date:** 2026-03-16
**What happened:** Completed Plan 13-02 — library filter dropdown in top bar, all views wired to ByLibrary queries, phantom track auto-resolution via ScanHooks. Checkpoint APPROVED — all 7 requirements verified (VIEW-0104, PLAY-0103). Additional bugfixes: virtualizer event delegation race condition, phantom auto-resolution after re-scan.
**Where we stopped:** Completed 13-02-PLAN.md — Phase 13 complete (2/2 plans), v1.1 milestone complete
**Next action:** v1.1 milestone shipped — all phases (9-14) complete
**What happened:** Created v1.2 Tag Editing roadmap — 5 phases (15-19) covering all 20 requirements. Derived phases from requirement clustering: schema foundation → tag writers + DB sync → single-track UI → batch UI → OGG stretch.
**Where we stopped:** Roadmap created, ready for phase planning
**Next action:** `/gsd-plan-phase 15` — Schema Migration & Write Safety
---
*State initialized: 2026-02-27*
@@ -200,4 +129,4 @@ Decisions from v1.0 are archived in PROJECT.md Key Decisions table. Key patterns
| 19 | fix phantom playlist tracks with multi-root path resolution | 2026-03-16 | 9144ded | [19-fix-phantom-playlist-tracks](./quick/19-fix-phantom-playlist-tracks/) |
Last activity: 2026-03-16 - Completed quick task 19: fix phantom playlist tracks with multi-root path resolution
*Last updated: 2026-03-16 — Completed quick task 19*
*Last updated: 2026-03-16 — v1.2 roadmap created*