05108d3e12
Schema (media_sort_date denormalization): - Add media_sort_date column to storage.files with DEFAULT created_at - Add trigger sync_media_sort_date: when file_metadata is upserted, copies COALESCE(captured_at, created_at) into files.media_sort_date - Add partial index idx_files_media_timeline on (user_id, media_sort_date DESC) WHERE NOT is_trashed AND media type -- enables Index Scan + Limit (no Sort) - copy_folder_tree now copies media_sort_date for copied files - Remove dead idx_file_metadata_captured (no longer needed) Query optimization (list_media_files): - Rewrite to use fi.media_sort_date instead of COALESCE(fm.captured_at,...) - Eliminates LEFT JOIN file_metadata -- one fewer table touch - Plan: Limit to Index Scan O(LIMIT) instead of Sort O(N) Video thumbnail pre-scaling (client + server): - JS: pre-scale canvas to max 400px before toBlob -- 22x less RAM, 15x less BW - Rust: fast-path in store_external_thumbnail -- if payload is already WebP with dims within max_dim, store as-is (zero decode, zero encode)