- images.rs: scope /api/img and /api/photos/{id}/original by album owner —
close the cross-tenant original/thumbnail leak (tenancy test now covers
these routes)
- migration 0003: refuse to run when albums exist and users != 1 instead of
silently reassigning every album to the oldest user
- Gallery: callback-ref ResizeObserver so a gallery mounted empty still
lays out once photos arrive (was permanently blank)
- upload dedup: re-uploading identical content whose photo is in 'error'
resets and re-enqueues it instead of returning the broken row
- client hashing: skip (and fall back to plain upload) above 512MB to avoid
whole-file arrayBuffer OOM / the ~2GiB cap
- zip: always spool each entry (no unread prefetched S3 body held across a
slow client stream) and backfill BOTH sha256 and crc32 for legacy photos
- tests/auth: share one session_payload builder instead of re-implementing
the cookie format in the test and mint_session
- albums.owner_id (migration 0003, backfilled to the original user)
- owned::{album,photo,share} are the only admin data-access paths; another
tenant's resources are indistinguishable from nonexistent (404)
- every admin handler threaded through ownership; each ALLOWED_EMAILS entry
is now its own isolated workspace
- tenant-isolation integration test matrix (tests/tenancy.rs, env-gated on
TEST_DATABASE_URL) driving the real router