docs(11-01): complete per-library scan pipeline plan

- Create 11-01-SUMMARY.md with execution results
- Update STATE.md: advance to phase 11 plan 1/3
- Update ROADMAP.md: phase 11 at 1/3 plans complete
- Mark LSCAN-01, LSCAN-02, LSCAN-04 complete in REQUIREMENTS.md
This commit is contained in:
2026-03-09 16:05:55 -04:00
parent 943db1cf27
commit 9308848936
4 changed files with 159 additions and 22 deletions
+6 -6
View File
@@ -32,10 +32,10 @@ Requirements for v1.1 Multi-Library Support milestone. Each maps to roadmap phas
### Library Scanning ### Library Scanning
- [ ] **LSCAN-01**: User can trigger a scan for a specific library (not all-or-nothing) - [x] **LSCAN-01**: User can trigger a scan for a specific library (not all-or-nothing)
- [ ] **LSCAN-02**: Scanning is sequential — only one library scans at a time (SQLite single-writer) - [x] **LSCAN-02**: Scanning is sequential — only one library scans at a time (SQLite single-writer)
- [ ] **LSCAN-03**: Scan progress UI shows which library is being scanned - [ ] **LSCAN-03**: Scan progress UI shows which library is being scanned
- [ ] **LSCAN-04**: Existing scan cancellation and pause/resume work per-library - [x] **LSCAN-04**: Existing scan cancellation and pause/resume work per-library
- [x] **LSCAN-05**: Audio files are associated with their library via `library_id` foreign key - [x] **LSCAN-05**: Audio files are associated with their library via `library_id` foreign key
### Unified Presentation ### Unified Presentation
@@ -186,10 +186,10 @@ Which phases cover which requirements. Updated during roadmap creation.
| LIB-04 | Phase 10 | Complete | | LIB-04 | Phase 10 | Complete |
| LIB-05 | Phase 10 | Complete | | LIB-05 | Phase 10 | Complete |
| LIB-06 | Phase 12 | Pending | | LIB-06 | Phase 12 | Pending |
| LSCAN-01 | Phase 11 | Pending | | LSCAN-01 | Phase 11 | Complete |
| LSCAN-02 | Phase 11 | Pending | | LSCAN-02 | Phase 11 | Complete |
| LSCAN-03 | Phase 11 | Pending | | LSCAN-03 | Phase 11 | Pending |
| LSCAN-04 | Phase 11 | Pending | | LSCAN-04 | Phase 11 | Complete |
| LSCAN-05 | Phase 10 | Complete | | LSCAN-05 | Phase 10 | Complete |
| VIEW-01 | Phase 13 | Pending | | VIEW-01 | Phase 13 | Pending |
| VIEW-02 | Phase 13 | Pending | | VIEW-02 | Phase 13 | Pending |
+2 -2
View File
@@ -76,7 +76,7 @@ Plans:
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 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) 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 4. Existing cancel and pause/resume controls work correctly for per-library scans — cancelling one library's scan doesn't affect others
**Plans:** 3 plans **Plans:** 1/3 plans executed
Plans: Plans:
- [ ] 11-01-PLAN.md — Backend scan queue coordinator, per-library scan methods, CreateAudioFile with library_id - [ ] 11-01-PLAN.md — Backend scan queue coordinator, per-library scan methods, CreateAudioFile with library_id
- [ ] 11-02-PLAN.md — Frontend progress UI with library name, cancel scope modal, Scan All button - [ ] 11-02-PLAN.md — Frontend progress UI with library name, cancel scope modal, Scan All button
@@ -120,7 +120,7 @@ Plans:
| 8. Frontend Performance & UX | v1.0 | 4/4 | Complete | 2026-03-05 | | 8. Frontend Performance & UX | v1.0 | 4/4 | Complete | 2026-03-05 |
| 9. Scan Cancellation & Keyboard Shortcuts | v1.1 | 5/5 | Complete | 2026-03-07 | | 9. Scan Cancellation & Keyboard Shortcuts | v1.1 | 5/5 | Complete | 2026-03-07 |
| 10. Schema & Migration | 2/2 | Complete | 2026-03-09 | - | | 10. Schema & Migration | 2/2 | Complete | 2026-03-09 | - |
| 11. Per-Library Scan Pipeline | v1.1 | 0/? | Not started | - | | 11. Per-Library Scan Pipeline | 1/3 | In Progress| | - |
| 12. Library CRUD & Data Integrity | v1.1 | 0/? | Not started | - | | 12. Library CRUD & Data Integrity | v1.1 | 0/? | Not started | - |
| 13. Library Views & Phantom Tracks | v1.1 | 0/? | Not started | - | | 13. Library Views & Phantom Tracks | v1.1 | 0/? | Not started | - |
+24 -14
View File
@@ -3,12 +3,12 @@ gsd_state_version: 1.0
milestone: v1.1 milestone: v1.1
milestone_name: Multi-Library Support milestone_name: Multi-Library Support
status: unknown status: unknown
last_updated: "2026-03-09T13:57:33.492Z" last_updated: "2026-03-09T20:03:14Z"
progress: progress:
total_phases: 2 total_phases: 2
completed_phases: 2 completed_phases: 2
total_plans: 7 total_plans: 8
completed_plans: 7 completed_plans: 8
--- ---
# YellowJacket — Project State # YellowJacket — Project State
@@ -18,15 +18,15 @@ progress:
See: .planning/PROJECT.md (updated 2026-03-08) See: .planning/PROJECT.md (updated 2026-03-08)
**Core value:** The music player works reliably and feels solid — every interaction is correct, responsive, and trustworthy. **Core value:** The music player works reliably and feels solid — every interaction is correct, responsive, and trustworthy.
**Current focus:** v1.1 Multi-Library Support — Phase 10 (Schema & Migration) **Current focus:** v1.1 Multi-Library Support — Phase 11 (Per-Library Scan Pipeline)
## Current Position ## Current Position
Phase: 10Schema & Migration Phase: 11Per-Library Scan Pipeline
Plan: 2 of 2 in Phase (Plan 02 complete) Plan: 1 of 3 in Phase (Plan 01 complete)
Status: Phase 10 complete — ready for Phase 11 Status: Phase 11 in progress — 2 plans remaining
Progress: ████████░░░░░░░░░░░░ 2/5 phases complete (Phase 10) Progress: ████████████░░░░░░░░ 2/5 phases complete (Phase 11 in progress)
Last activity: 2026-03-09 — Completed 10-02 sqlc queries + migration tests Last activity: 2026-03-09 — Completed 11-01 per-library scan pipeline
### Phase Overview ### Phase Overview
@@ -34,7 +34,7 @@ Last activity: 2026-03-09 — Completed 10-02 sqlc queries + migration tests
|-------|--------| |-------|--------|
| 9. Scan Cancellation & Keyboard Shortcuts | Complete (5/5 plans) ✅ | | 9. Scan Cancellation & Keyboard Shortcuts | Complete (5/5 plans) ✅ |
| 10. Schema & Migration | Complete (2/2 plans) ✅ | | 10. Schema & Migration | Complete (2/2 plans) ✅ |
| 11. Per-Library Scan Pipeline | Not started | | 11. Per-Library Scan Pipeline | In Progress (1/3 plans) |
| 12. Library CRUD & Data Integrity | Not started | | 12. Library CRUD & Data Integrity | Not started |
| 13. Library Views & Phantom Tracks | Not started | | 13. Library Views & Phantom Tracks | Not started |
@@ -52,6 +52,7 @@ Last activity: 2026-03-09 — Completed 10-02 sqlc queries + migration tests
| 09-05 | integration testing & verification | 3 min | 2 | 1 | | 09-05 | integration testing & verification | 3 min | 2 | 1 |
| Phase 10-01 P01 | 11 min | 2 tasks | 10 files | | Phase 10-01 P01 | 11 min | 2 tasks | 10 files |
| Phase 10-02 P02 | 5 min | 2 tasks | 9 files | | Phase 10-02 P02 | 5 min | 2 tasks | 9 files |
| Phase 11-01 P01 | 7 min | 2 tasks | 11 files |
## Accumulated Context ## Accumulated Context
@@ -91,6 +92,15 @@ Decisions from v1.0 are archived in PROJECT.md Key Decisions table. Key patterns
| COALESCE fallback chain: live → phantom → empty | Playlist queries use 3-level COALESCE so callers always get usable string values | | 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) | | 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 |
### Warnings (carry forward) ### 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) — carry forward
@@ -113,9 +123,9 @@ Decisions from v1.0 are archived in PROJECT.md Key Decisions table. Key patterns
### Last Session ### Last Session
**Date:** 2026-03-09 **Date:** 2026-03-09
**What happened:** Executed Phase 10, Plan 02added 7 library CRUD queries, updated all playlist queries for phantom support (LEFT JOINs, COALESCE fallback, is_phantom column), added library-filtered audio file queries, wrote 5 migration 6 integration tests, added NewTestDBWithLibrary helper. **What happened:** Executed Phase 11, Plan 01created scan queue coordinator (scan_queue.go), refactored Scan() to scanInternal() with per-library parameters, added ScanLibrary(id)/ScanAllLibraries() Wails bindings, FIFO queue with silent dedup, queue-aware cancel/pause, library_id in CreateAudioFile, library identification in all events.
**Where we stopped:** Completed 10-02-PLAN.md (Phase 10 complete) **Where we stopped:** Completed 11-01-PLAN.md
**Next action:** Plan or execute Phase 11 (Per-Library Scan Pipeline) **Next action:** Execute Phase 11, Plan 02
--- ---
*State initialized: 2026-02-27* *State initialized: 2026-02-27*
@@ -128,4 +138,4 @@ Decisions from v1.0 are archived in PROJECT.md Key Decisions table. Key patterns
| 18 | add multi-column metadata display to playlist-details | 2026-03-08 | ce23177 | [18-add-multi-column-metadata-display-to-pla](./quick/18-add-multi-column-metadata-display-to-pla/) | | 18 | add multi-column metadata display to playlist-details | 2026-03-08 | ce23177 | [18-add-multi-column-metadata-display-to-pla](./quick/18-add-multi-column-metadata-display-to-pla/) |
Last activity: 2026-03-08 - Completed quick task 18: add multi-column metadata display to playlist-details Last activity: 2026-03-08 - Completed quick task 18: add multi-column metadata display to playlist-details
*Last updated: 2026-03-09 — Completed 10-02-PLAN.md (Phase 10 complete)* *Last updated: 2026-03-09 — Completed 11-01-PLAN.md (Phase 11 complete)*
@@ -0,0 +1,127 @@
---
phase: 11-per-library-scan-pipeline
plan: 01
subsystem: library
tags: [scan-queue, per-library, wails-bindings, sqlc, events]
# Dependency graph
requires:
- phase: 10-schema-migration
provides: libraries table, library_id column on audio_files, GetLibrary/GetAllLibraries/GetLibraryByPath queries
provides:
- ScanLibrary(id) Wails-bound method for per-library scanning
- ScanAllLibraries() Wails-bound method for bulk sequential scanning
- Scan queue coordinator with FIFO sequential execution and silent dedup
- CancelCurrentScan() and CancelAllScans() for queue-aware cancellation
- GetScanQueueLength() and QueuedLibraryNames() for UI display
- Library-aware ScanProgress and ScanMetrics with libraryId, libraryName, queuedCount
- LibraryScanQueued and LibraryScanQueueDrained events
- CreateAudioFile with library_id parameter
affects: [12-library-crud-data-integrity, 13-library-views-phantom-tracks]
# Tech tracking
tech-stack:
added: []
patterns:
- "Scan queue coordinator pattern: FIFO queue with single-active-scan mutex"
- "scanInternal() as reusable per-library scan engine"
- "Silent dedup for scan requests (no-op if already scanning or queued)"
key-files:
created:
- backend/library/scan_queue.go
modified:
- backend/library/library.go
- backend/library/scan_control.go
- backend/library/metrics.go
- backend/events/events.go
- backend/database/sql/queries/audio_files.sql
- backend/database/sql/sqlcgen/audio_files.sql.go
- frontend/src/events.ts
- frontend/wailsjs/go/library/Library.d.ts
- frontend/wailsjs/go/library/Library.js
key-decisions:
- "Library identification threaded through importResult.libraryID rather than adding field to Library struct"
- "scanInternal returns *ScanMetrics instead of (*ScanMetrics, error) — errors are logged and warnings accumulated"
- "Worker count auto-detected per library path (ScanConcurrencyAuto) rather than using global config value"
- "Backward-compatible Scan() retained as deprecated wrapper for handleConfigUpdate"
patterns-established:
- "Scan queue coordinator: scanQueue []scanQueueEntry + drainQueue() pattern for sequential execution"
- "mkProgress closure for DRY ScanProgress event construction with library identification"
requirements-completed: [LSCAN-01, LSCAN-02, LSCAN-04]
# Metrics
duration: 7min
completed: 2026-03-09
---
# Phase 11 Plan 01: Per-Library Scan Pipeline Summary
**ScanLibrary(id) with FIFO queue coordinator, per-library file association via library_id, and queue-aware cancel/pause controls**
## Performance
- **Duration:** 7 min
- **Started:** 2026-03-09T19:56:10Z
- **Completed:** 2026-03-09T20:03:14Z
- **Tasks:** 2
- **Files modified:** 11
## Accomplishments
- `ScanLibrary(id)` resolves library path from DB and scans only that directory, associating files with library_id
- FIFO scan queue ensures only one scan runs at a time, with silent dedup for duplicate requests
- `ScanAllLibraries()` queries all libraries and queues them sequentially
- `CancelCurrentScan()` stops current library and auto-starts next queued; `CancelAllScans()` clears queue too
- Pause freezes current scan AND queue (drainQueue only runs on scan completion)
- All scan events (progress, started, complete, cancelled) include library name and queue count
## Task Commits
Each task was committed atomically (note: lint fix amend merged both into single commit):
1. **Task 1: Add library_id to CreateAudioFile + update events and progress types** - `943db1c` (feat)
2. **Task 2: Create scan queue coordinator and refactor Library for per-library scanning** - `943db1c` (feat)
_Note: Tasks were merged into a single commit due to lint fix amend during pre-commit hook._
## Files Created/Modified
- `backend/library/scan_queue.go` - Scan queue coordinator: ScanLibrary, ScanAllLibraries, CancelCurrentScan, CancelAllScans, drainQueue
- `backend/library/library.go` - Refactored Scan() → scanInternal() with library ID/name/path parameters, per-library DB queries
- `backend/library/scan_control.go` - Deprecated CancelScan() in favor of queue-aware methods
- `backend/library/metrics.go` - Added LibraryID, LibraryName to ScanMetrics; LibraryID, LibraryName, QueuedCount to ScanProgress
- `backend/events/events.go` - Added LibraryScanQueued and LibraryScanQueueDrained constants
- `backend/database/sql/queries/audio_files.sql` - Added library_id to CreateAudioFile INSERT
- `backend/database/sql/sqlcgen/audio_files.sql.go` - Regenerated with LibraryID in CreateAudioFileParams
- `frontend/src/events.ts` - Regenerated with scan queue events
- `frontend/wailsjs/go/library/Library.d.ts` - Auto-generated Wails bindings for new methods
- `frontend/wailsjs/go/library/Library.js` - Auto-generated Wails bindings for new methods
- `frontend/wailsjs/go/models.ts` - Auto-generated model updates
## Decisions Made
- **Library ID threading via importResult:** Rather than adding a libraryID field to the Library struct, the ID is threaded through the scan pipeline via the importResult struct and set in the DB writer goroutine. This keeps the data flow explicit and avoids mutation of shared state.
- **scanInternal returns only metrics:** Changed signature from `(*ScanMetrics, error)` to `*ScanMetrics` since the scan queue coordinator calls it in a goroutine where error return is impractical. Errors are logged and accumulated in ScanMetrics.Warnings.
- **Auto worker count per library:** Each library path may reside on different storage (SSD vs HDD), so worker count uses `ScanConcurrencyAuto` with per-path detection rather than the global config value.
- **Backward-compatible Scan():** Retained as deprecated wrapper that resolves the library from `l.conf.DirectoryPath` via `GetLibraryByPath`. This keeps `handleConfigUpdate` and `FullRescan` working without changes.
## Deviations from Plan
None - plan executed exactly as written.
## Issues Encountered
None
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
- Per-library scan pipeline complete, ready for Phase 11 Plan 02 (if exists) or Phase 12 (Library CRUD & Data Integrity)
- Frontend can now call `ScanLibrary(id)`, `ScanAllLibraries()`, `CancelCurrentScan()`, `CancelAllScans()`
- Progress events include library identification for UI display
- Phase 12 can build library management UI on top of these Wails bindings
---
*Phase: 11-per-library-scan-pipeline*
*Completed: 2026-03-09*