183 lines
7.5 KiB
Markdown
183 lines
7.5 KiB
Markdown
---
|
|
phase: 11-per-library-scan-pipeline
|
|
plan: 03
|
|
type: execute
|
|
wave: 2
|
|
depends_on: ["11-01"]
|
|
files_modified:
|
|
- backend/app.go
|
|
- backend/library/library.go
|
|
autonomous: true
|
|
requirements: [LSCAN-01, LSCAN-02]
|
|
|
|
must_haves:
|
|
truths:
|
|
- "App auto-scans all libraries on launch using ScanAllLibraries"
|
|
- "Legacy LibraryConfigChanged event handler is removed or updated for multi-library"
|
|
- "Library struct no longer requires Config.DirectoryPath to function"
|
|
artifacts:
|
|
- path: "backend/app.go"
|
|
provides: "Updated OnDomReady or OnStartup to trigger ScanAllLibraries on launch"
|
|
- path: "backend/library/library.go"
|
|
provides: "Updated NewLibrary constructor — Config no longer required"
|
|
key_links:
|
|
- from: "backend/app.go"
|
|
to: "backend/library/scan_queue.go"
|
|
via: "ScanAllLibraries call on startup"
|
|
pattern: "library\\.ScanAllLibraries"
|
|
---
|
|
|
|
<objective>
|
|
Wire the per-library scan pipeline into app startup and clean up legacy single-directory scanning paths.
|
|
|
|
Purpose: Ensure auto-scan on launch uses `ScanAllLibraries()` (same codepath as the UI button per CONTEXT.md), and remove/update legacy `LibraryConfigChanged` handler that assumed a single directory.
|
|
Output: Updated app.go startup wiring, cleaned-up Library constructor.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@/home/caleb/.config/opencode/get-shit-done/workflows/execute-plan.md
|
|
@/home/caleb/.config/opencode/get-shit-done/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/phases/11-per-library-scan-pipeline/11-CONTEXT.md
|
|
@.planning/phases/11-per-library-scan-pipeline/11-01-SUMMARY.md
|
|
|
|
<interfaces>
|
|
<!-- From Plan 01 -->
|
|
From backend/library/scan_queue.go (created in Plan 01):
|
|
```go
|
|
func (l *Library) ScanLibrary(id int64) error
|
|
func (l *Library) ScanAllLibraries() error
|
|
func (l *Library) CancelCurrentScan()
|
|
func (l *Library) CancelAllScans()
|
|
```
|
|
|
|
From backend/app.go (current):
|
|
```go
|
|
func (yj *YellowJacketApp) OnStartup(ctx context.Context)
|
|
// Currently: yj.library.SetContext(ctx)
|
|
// Currently: library is created with appConfig.Library (Config with DirectoryPath)
|
|
|
|
func NewYellowJacketApp(...) {
|
|
lib, err := library.NewLibrary(
|
|
yjApp.appContext,
|
|
yjApp.logger,
|
|
yjApp.appConfig.Library, // Config with DirectoryPath
|
|
yjApp.database,
|
|
)
|
|
}
|
|
```
|
|
|
|
From backend/library/library.go (current event handler):
|
|
```go
|
|
func (l *Library) registerEventHandlers() {
|
|
runtime.EventsOn(l.ctx, events.LibraryConfigChanged, func(data ...any) {
|
|
// Parses DirectoryPath from event data, calls l.handleConfigUpdate
|
|
})
|
|
}
|
|
```
|
|
</interfaces>
|
|
</context>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Wire auto-scan on startup and clean up legacy single-directory code</name>
|
|
<files>
|
|
backend/app.go
|
|
backend/library/library.go
|
|
</files>
|
|
<action>
|
|
1. **Update `NewLibrary` constructor** in `backend/library/library.go`:
|
|
- Make `*Config` parameter optional/removable. The Library no longer needs a pre-configured DirectoryPath because scan paths come from the database.
|
|
- Keep the `*Config` parameter for backward compatibility but don't require `DirectoryPath` to be set.
|
|
- Update validation: if `conf` is nil, create a default config with empty DirectoryPath (already handled).
|
|
|
|
2. **Update `registerEventHandlers`** in `backend/library/library.go`:
|
|
- Remove the `LibraryConfigChanged` event handler entirely. This handler assumed a single-directory model where changing the config triggers a scan. In the multi-library model:
|
|
- Libraries are added/removed through the library CRUD API (Phase 12)
|
|
- Scanning is triggered explicitly via `ScanLibrary()` or `ScanAllLibraries()`
|
|
- The `LibraryConfigChanged` event and `handleConfigUpdate` method can be deleted or marked deprecated
|
|
- Delete `handleConfigUpdate` method
|
|
- Delete `errLibraryDirNotConfigured` sentinel error (no longer needed)
|
|
|
|
3. **Update `NewYellowJacketApp` in `backend/app.go`**:
|
|
- Change the `library.NewLibrary(...)` call. The Config parameter is less important now since DirectoryPath is ignored. Pass `yjApp.appConfig.Library` as before (it still has ScanConcurrency which is useful as a default).
|
|
|
|
4. **Add auto-scan on startup** in `backend/app.go`:
|
|
- In `OnDomReady` (or via a goroutine started in `OnStartup` that waits for DOM ready), trigger auto-scan.
|
|
- Best approach: In `OnDomReady`, after the startup error check, launch a goroutine:
|
|
```go
|
|
go func() {
|
|
if err := yj.library.ScanAllLibraries(); err != nil {
|
|
yj.logger.Error("auto-scan failed", "err", err)
|
|
}
|
|
}()
|
|
```
|
|
- This uses the same `ScanAllLibraries()` codepath as the UI button (per CONTEXT.md: "Auto-scan on launch should use the same ScanAllLibraries() codepath as the UI button — single implementation").
|
|
- It runs in a goroutine so it doesn't block the DOM ready callback.
|
|
- Only run if there are libraries in the DB: check `l.db.Queries.CountLibraries(l.ctx)` first (or let ScanAllLibraries handle the empty case gracefully by returning immediately when GetAllLibraries returns an empty slice).
|
|
|
|
5. **Clean up legacy `Scan()` method**:
|
|
- In Plan 01, the old `Scan()` was kept as backward-compatible wrapper. Now review: since we're removing `handleConfigUpdate` which was the only caller of the legacy `Scan()` via `l.handleConfigUpdate → l.Scan()`, we can either:
|
|
- Keep `Scan()` for tests (it's used in `scan_test.go`)
|
|
- Update it to call `scanInternal` with the library from `l.conf.DirectoryPath` if set, or return early if not set
|
|
- Keep `FullRescan()` — it's still called from the config-page UI. It should work with the first/default library. Update it to look up the default library from DB rather than using `l.conf.DirectoryPath`.
|
|
|
|
6. **Update `FullRescan()`** in `backend/library/rescan.go`:
|
|
- Instead of using `l.conf.DirectoryPath`, look up the first library from DB: `libs, err := l.db.Queries.GetAllLibraries(l.ctx)` and use `libs[0]`.
|
|
- If no libraries exist, return an error.
|
|
- Call `scanInternal(lib.ID, lib.Name, lib.Path)` instead of `l.Scan()`.
|
|
- Per-library FullRescan will be added in Phase 12 — for now this rescans the first/only library.
|
|
|
|
**Linting requirements:**
|
|
- Doc comments ending with period
|
|
- Blank line after early returns
|
|
- Lines under 100 chars
|
|
</action>
|
|
<verify>
|
|
<automated>cd /mnt/vault/dev/golang/yellowjacket && go build ./... && go vet ./backend/... && go test ./backend/library/... -count=1 -timeout 60s</automated>
|
|
</verify>
|
|
<done>
|
|
- Auto-scan on startup calls ScanAllLibraries (same codepath as UI button)
|
|
- Legacy LibraryConfigChanged handler removed
|
|
- Legacy handleConfigUpdate removed
|
|
- FullRescan uses library from DB instead of config DirectoryPath
|
|
- go build passes, go vet passes, existing tests pass
|
|
</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<verification>
|
|
```bash
|
|
# Full build
|
|
go build ./...
|
|
|
|
# Vet
|
|
go vet ./backend/...
|
|
|
|
# Tests pass (including scan_test.go)
|
|
go test ./backend/library/... -count=1 -timeout 60s
|
|
|
|
# No references to removed handler
|
|
grep -rn "LibraryConfigChanged" backend/library/ | grep -v "_test.go"
|
|
# Should return no hits (only events.go constant definition, not handler registration)
|
|
```
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- App auto-scans all libraries on launch via ScanAllLibraries
|
|
- LibraryConfigChanged handler removed from library package
|
|
- handleConfigUpdate removed
|
|
- FullRescan works with DB-sourced library (not config DirectoryPath)
|
|
- All tests pass, build passes
|
|
</success_criteria>
|
|
|
|
<output>
|
|
After completion, create `.planning/phases/11-per-library-scan-pipeline/11-03-SUMMARY.md`
|
|
</output>
|