fix(photos): faster large-album loading and album cover lifecycle

Large albums opened slowly and flickered; the default album cover was
also lost in the media-objects refactor.

Large-album loading:
- quantize signed object URLs within a window and send Cache-Control so
  previews are reused instead of re-fetched
- publish photo.updated (not photo.created) when variants are ready, so
  clients update in place without reordering the grid
- worker concurrency + newest-first variant priority; raise default batch

Album cover:
- first uploaded photo becomes the cover when none is set
- clear the cover when the cover photo is trashed or moved out
- "set as album cover" in the photo context menu and actions panel

OpenSpec changes: fix-large-album-load, fix-album-cover
This commit is contained in:
iu
2026-10-11 14:15:59 +03:00
parent 6361e48b20
commit d7a37328f0
40 changed files with 999 additions and 57 deletions
+7
View File
@@ -110,6 +110,9 @@ func (s *Service) Upload(ctx context.Context, in UploadInput) (*models.Photo, er
return nil, err
}
// The first photo uploaded to an album becomes its default cover.
s.store.SetCoverIfEmpty(ctx, in.AlbumID, p.ID)
if err := s.attachURLs(ctx, p); err != nil {
return nil, err
}
@@ -298,6 +301,8 @@ func (s *Service) Delete(ctx context.Context, photoID, userID string) error {
if err := s.store.SetDeleted(ctx, photoID, true); err != nil {
return err
}
// A trashed cover leaves the album without one.
s.store.ClearCoverIfMatches(ctx, p.AlbumID, photoID)
s.publishDeleted(p)
return nil
}
@@ -451,6 +456,8 @@ func (s *Service) MoveBatch(ctx context.Context, ids []string, userID, targetAlb
if err := s.store.UpdateAlbum(ctx, id, targetAlbumID); err != nil {
continue
}
// Moving a cover photo out of its album leaves the album without one.
s.store.ClearCoverIfMatches(ctx, oldAlbum, id)
p.AlbumID = targetAlbumID
s.hub.Publish(oldAlbum, "photo.deleted", map[string]string{
"id": p.ID, "album_id": oldAlbum, "uploader_id": p.UploaderID,