feat(settings,index): per-user index sub-path, strip dead PP settings, scope duplicates

Lets a user pick a sub-folder under their library as a working index root,
stored server-side (new sidecar user_prefs table). The Library tree, reindex,
and both duplicate views (stacks + cross-folder scan) now re-root to it via a
single userLibraryBase() helper. Also fixes the cross-folder scan/archive
endpoints, which previously walked/touched the whole originals root instead
of being scoped per-user (archive now rejects out-of-scope paths, 403).

Removes PhotoPrism settings (Search/Maps/Server-UI/Features/Import) that only
steered PhotoPrism's own bundled SPA and were never read by mulimage's UI.

Also fixes the Library tree occasionally getting stuck on "Loading folders…"
by dropping gcTime:0 and gating the spinner on isLoading instead of isPending.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 22:41:12 +02:00
parent ba5684d120
commit 634abc2a95
12 changed files with 513 additions and 542 deletions

View File

@@ -81,6 +81,9 @@ func main() {
// under one group keeps the middleware wiring obvious.
auth := r.Group("/api/sidecar", requireSession(pp))
{
auth.GET("/prefs", handlePrefsGet(db))
auth.PUT("/prefs", handlePrefsPut(cfg, db))
auth.GET("/photos/marks", handleMarksAll(db))
auth.GET("/photos/:uid/marks", handleMarkGet(db))
auth.PUT("/photos/:uid/marks", handleMarkPut(db))
@@ -97,8 +100,8 @@ func main() {
auth.POST("/albums/:uid/convert", handleHeapConvert(cfg, pp))
auth.POST("/photos/move", handlePhotosMove(cfg, pp))
auth.GET("/duplicates/scan", handleDupScan(cfg, pp))
auth.POST("/duplicates/archive", handleDupArchive(cfg, pp))
auth.GET("/duplicates/scan", handleDupScan(cfg, pp, db))
auth.POST("/duplicates/archive", handleDupArchive(cfg, pp, db))
// User-scoped proxies — require PpDSN connection.
if ppDb != nil {