Indexes: share_targets.target_id, duplicate_groups.status,
GIN on stacks members + duplicate candidates JSONB,
composite (owner_user_id, created_at DESC) on assets.
N+1 elimination: batch metadata loading via find_by_assets(ids)
using WHERE asset_id = ANY($1), used in timeline + sidecar export.
Visibility: cache find_targets_for_user per request via OnceCell,
extract filter_visible helper to reduce duplication.
Streaming: FileStoragePort.open_file() returns (DataStream, u64),
LocalFileStorage uses ReaderStream instead of loading full file.
serve_file/serve_derivative use Body::from_stream().
Unbounded queries: sidecar full_export/import batched in 500-row
chunks instead of u32::MAX. find_unresolved paginated with
limit/offset. list_duplicates API accepts pagination params.
- adapters-sidecar: XmpSidecarWriter using xmp_toolkit
- Writes StructuredData → XMP with EXIF/DC/XMP namespace routing
- Reads XMP back to StructuredData
- Wired into bootstrap + worker, deleted both LogSidecarWriter stubs