main.rs drops from 2935 → 1200 lines, freed for startup wiring +
the watcher. The 16 route handlers move into three domain-grouped
files under src/handlers/:
- handlers/favorites.rs (128 lines): favorites, put_add_favorite,
delete_favorite.
- handlers/video.rs (665 lines): generate_video, stream_video,
get_video_part, get_video_preview, get_preview_status. The 5
pre-existing get_preview_status integration tests move with the
handler (still pass against TestPreviewDao + AppState::test_state).
- handlers/image.rs (1003 lines): get_image (with the
hash/library-scoped/bare-legacy thumb lookup), upload_image,
get_file_metadata, set_image_gps, get_full_exif, set_image_date,
clear_image_date. Helpers (create_circular_thumbnail,
build_metadata_response_for_date_mutation) and request structs
(SetGpsRequest, SetDateRequest, ClearDateRequest, UploadQuery)
travel with them.
main.rs's import block shrinks from ~50 lines to ~22 as everything
HTTP-specific (NamedFile, mp::Multipart, BytesMut, Span, KeyValue,
StreamExt, …) moves with the handlers. The is_video_file wrapper
also goes — remaining callers in watch_files / cleanup use
file_types::is_video_file directly.
cargo test --bin image-api: 325 passing (no regression).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>