feat: multi-library foundation (schema + libraries module)

Adds a `libraries` registry table and threads library_id through
per-instance metadata tables (image_exif, photo_insights,
entity_photo_links, video_preview_clips). File-path columns renamed to
rel_path to make the relative-to-root semantics explicit. Adds
content_hash + size_bytes on image_exif to support future hash-keyed
thumbnail/HLS dedup. Tags and favorites stay library-agnostic so they
share across libraries by rel_path.

Behavior is unchanged: a single primary library (id=1) is seeded from
BASE_PATH on first boot; all handlers and DAOs route through it as a
transitional shim until the API gains a library query param.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Cameron
2026-04-17 15:28:30 -04:00
committed by cameron
parent 2f4edba08c
commit ffcddbb843
17 changed files with 750 additions and 108 deletions

View File

@@ -1187,6 +1187,7 @@ impl InsightGenerator {
// 11. Store in database
let insight = InsertPhotoInsight {
library_id: crate::libraries::PRIMARY_LIBRARY_ID,
file_path: file_path.to_string(),
title,
summary,
@@ -2031,6 +2032,7 @@ Return ONLY the summary, nothing else."#,
// Upsert a photo link so this entity is associated with this photo
let link = InsertEntityPhotoLink {
entity_id: subject_entity_id,
library_id: crate::libraries::PRIMARY_LIBRARY_ID,
file_path: file_path.to_string(),
role: photo_role,
};
@@ -2742,6 +2744,7 @@ Return ONLY the summary, nothing else."#,
// 15. Store insight (returns the persisted row including its new id)
let insight = InsertPhotoInsight {
library_id: crate::libraries::PRIMARY_LIBRARY_ID,
file_path: file_path.to_string(),
title,
summary: final_content,