Skip to content

feat(spaces): in-space album management + shared-space-album scope helper - #752

Merged
Deeds67 merged 38 commits into
mainfrom
space-albums-onto-main
Jul 19, 2026
Merged

feat(spaces): in-space album management + shared-space-album scope helper#752
Deeds67 merged 38 commits into
mainfrom
space-albums-onto-main

Conversation

@Deeds67

@Deeds67 Deeds67 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Space Albums for Shared Spaces (#752)

Adds first-class album support to Shared Spaces — link existing albums (or create new ones) into a space, browse and organise them in a dedicated Albums tab, and let members contribute across owners — all under the space's role-based access model. Along the way it also lands cross-owner contribution plumbing, a round of timeline/grouping UI polish, and several RBAC-hardening fixes.

High-level summary — the PR is large; see the commit history for the blow-by-blow.

Space albums

  • In-space album management — the full main-albums toolbar in the space Albums tab: search, sort, group (None / Year / Linked-by / Owner), and cover ↔ list views. Create album (editor+) auto-links and opens it; link album attaches an existing one; viewers are read-only but keep search/sort/group/view.
  • The space album page is editable like a regular album (rename, add/remove photos) for owners/editors; viewers browse read-only.
  • Cross-owner contributions — members can contribute assets they don't own into a linked space album (stored in album_space_asset, distinct from owner-added album_asset). Contributions render in the album grid and counts, are view/download-accessible to members, sync to mobile, and are tombstoned on unlink / re-delivered on re-link.
  • Per-album timeline toggle (showInTimeline) controls whether a linked album's photos appear in the aggregated space timeline — complementing the existing per-member timeline preference.
  • A single shared-space-album-scope helper routes space-album scoping through ~9 repositories (access / asset / search / timeline / map / memory / view / person-face / face-identity), replacing duplicated inline SQL — proven equivalent by real-DB characterization tests. Closes several soft-delete face-retention holes and enforces album_asset / album_space_asset exclusivity.

RBAC hardening

  • isOffline parity on the space-album asset-access arms — offline external-library assets reached through a space album are now blocked for members, matching the library arm.
  • Per-member photo counts on the Members tab now include album / library / contribution sources, not just the direct pool.

Timeline & UI polish

  • /photos filter panel collapses into a header filter button, letting the grid reclaim the width; Google-Photos-style sidebar nav pills.
  • Timeline grouping (Years / Months / All) fixes: breathing room for the memories strip, no flicker when switching grouping, no centred year/month label flash before the cover loads, and an instant (non-collapsing) day→grouped transition.
  • Scrubber e2e recalibrated for the new collapsed-panel width.

Also folded in

Testing

TDD throughout — server unit + real-DB medium tests (including the scope-equivalence characterization spec, the isOffline access parity, and per-source member counts), the full web component suite, and Playwright e2e journeys (search / sort / group / view / create / link / viewer gating). Regenerated SQL / OpenAPI / Dart clients.

@Deeds67 Deeds67 added the changelog:feat Feature change for changelog label Jul 6, 2026
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jul 9, 2026
@Deeds67
Deeds67 force-pushed the space-albums-onto-main branch from a117997 to 230b1db Compare July 10, 2026 08:38
Deeds67 added a commit that referenced this pull request Jul 16, 2026
…lper (#752)

Rebase of the 282-commit space-albums-onto-main branch onto v3.0.3 main,
squashed to a single commit (net feature diff of 7c12f74..tip re-applied
onto the force-pushed main).

Reconciled the branch's #755 stack-in-space work against main's landed #782:
- server addAssets/removeAssets: use main's #782 expandStackAssetIds
  (visibility-restricted, not owner-scoped) for stack atomicity, while keeping
  the branch's AssetShare permission (required now that album-linking makes the
  AssetRead space arm exploitable) and the branch's multi-path-aware face
  retention (getAssetIdsWithoutOtherSpacePath — keep faces for assets still
  reachable via a linked album/library).
- mobile space timelines: combined the branch's album joins/showInTimeline with
  the stack collapse.
- web space timeline: kept the branch's shell/snippet structure and re-added
  main's #782 withStacked badge prop.
- docs: kept main's #782 Stacked Photos section.

The branch's own getOwnedStackSiblingIds/getStackSiblingIdsInSpace repo helpers
are now unused by the service (superseded by StackRepository.getStackedAssetIds)
but retained with their direct repo test — optional follow-up cleanup.
@Deeds67
Deeds67 force-pushed the space-albums-onto-main branch from d84a451 to acc4656 Compare July 16, 2026 07:53
Deeds67 added a commit that referenced this pull request Jul 16, 2026
…lper (#752)

Rebase of the 282-commit space-albums-onto-main branch onto v3.0.3 main,
squashed to a single commit (net feature diff of 7c12f74..tip re-applied
onto the force-pushed main).

Reconciled the branch's #755 stack-in-space work against main's landed #782:
- server addAssets/removeAssets: use main's #782 expandStackAssetIds
  (visibility-restricted, not owner-scoped) for stack atomicity, while keeping
  the branch's AssetShare permission (required now that album-linking makes the
  AssetRead space arm exploitable) and the branch's multi-path-aware face
  retention (getAssetIdsWithoutOtherSpacePath — keep faces for assets still
  reachable via a linked album/library).
- mobile space timelines: combined the branch's album joins/showInTimeline with
  the stack collapse.
- web space timeline: kept the branch's shell/snippet structure and re-added
  main's #782 withStacked badge prop.
- docs: kept main's #782 Stacked Photos section.

The branch's own getOwnedStackSiblingIds/getStackSiblingIdsInSpace repo helpers
are now unused by the service (superseded by StackRepository.getStackedAssetIds)
but retained with their direct repo test — optional follow-up cleanup.
@Deeds67
Deeds67 force-pushed the space-albums-onto-main branch from acc4656 to 82dd112 Compare July 16, 2026 08:15
Deeds67 added a commit that referenced this pull request Jul 16, 2026
…B1 / consistency sweep / S5 / S7)

Resolves the confirmed launch blocker and the read-vs-machinery asymmetry surfaced by the
multi-agent audit of #752. The read/timeline layer already unions BOTH linked-album arms
(album_asset OR the cross-owner album_space_asset contribution, #764) via spaceAlbumAssetExists;
retention, count, reconcile, and thumbnail-eligibility joined only album_asset. This teaches them
the same union so a contributed asset is treated consistently everywhere it is visible.

- B1 (blocker) — face retention: getAssetIdsWithoutOtherSpacePath / getAlbumAssetIdsWithoutOtherSpacePath
  route the album arm through spaceAlbumAssetExists (both arms). Removing a direct add (or unlinking)
  no longer sweeps the space person for an asset still reachable via a cross-owner contribution while
  it remains visible in the timeline. New medium test: contributed-path retention.
- S1 / S6 (consistency sweep): the reconcile pager (getAssetIdsInSpacePage) now enumerates album +
  contributed assets so the face-projection fallback can (re)cover them; getAssetCount /
  getRecentAssets / getLastAssetAddedAt / isAssetInSpace now include contributions (count/cover/
  thumbnail eligibility agree with the timeline). New medium test: count + pager.
- S5 — remove-from-space: removeAssets bounds stack-atomic expansion to DIRECT members
  (getDirectAssetIds), so removing an album-projected asset can never drag a directly-added stack
  sibling out of the space; it now returns exactly the ids it removed, and the web RemoveFromSpaceAction
  reflects the real result (no false-success toast / optimistic hide of album-only assets). New medium
  test: album-only removal does not remove a direct stack sibling.
- S7 — rebase cleanup: deleted the dead getOwnedStackSiblingIds / getStackSiblingIdsInSpace repo
  helpers (superseded by StackRepository.getStackedAssetIds) and their dead medium spec (the live path
  is covered by shared-space-stacks.spec.ts + the new S5 test); updated the scope guard (registered the
  contributed helper, swapped the allowlist entry).
- Regenerated SQL + OpenAPI (spec, TS SDK, Dart client) for the removeAssets return type and repo changes.

Deferred to triage (design decisions, not in this change): S2 (real-time projection of contributed
faces), S3 (mobile sync spaceId correlation + revocation), S4 (space-editor album-write RBAC scoping).
Deeds67 added a commit that referenced this pull request Jul 16, 2026
…B1 / consistency sweep / S5 / S7)

Resolves the confirmed launch blocker and the read-vs-machinery asymmetry surfaced by the
multi-agent audit of #752. The read/timeline layer already unions BOTH linked-album arms
(album_asset OR the cross-owner album_space_asset contribution, #764) via spaceAlbumAssetExists;
retention, count, reconcile, and thumbnail-eligibility joined only album_asset. This teaches them
the same union so a contributed asset is treated consistently everywhere it is visible.

- B1 (blocker) — face retention: getAssetIdsWithoutOtherSpacePath / getAlbumAssetIdsWithoutOtherSpacePath
  route the album arm through spaceAlbumAssetExists (both arms). Removing a direct add (or unlinking)
  no longer sweeps the space person for an asset still reachable via a cross-owner contribution while
  it remains visible in the timeline. New medium test: contributed-path retention.
- S1 / S6 (consistency sweep): the reconcile pager (getAssetIdsInSpacePage) now enumerates album +
  contributed assets so the face-projection fallback can (re)cover them; getAssetCount /
  getRecentAssets / getLastAssetAddedAt / isAssetInSpace now include contributions (count/cover/
  thumbnail eligibility agree with the timeline). New medium test: count + pager.
- S5 — remove-from-space: removeAssets bounds stack-atomic expansion to DIRECT members
  (getDirectAssetIds), so removing an album-projected asset can never drag a directly-added stack
  sibling out of the space; it now returns exactly the ids it removed, and the web RemoveFromSpaceAction
  reflects the real result (no false-success toast / optimistic hide of album-only assets). New medium
  test: album-only removal does not remove a direct stack sibling.
- S7 — rebase cleanup: deleted the dead getOwnedStackSiblingIds / getStackSiblingIdsInSpace repo
  helpers (superseded by StackRepository.getStackedAssetIds) and their dead medium spec (the live path
  is covered by shared-space-stacks.spec.ts + the new S5 test); updated the scope guard (registered the
  contributed helper, swapped the allowlist entry).
- Regenerated SQL + OpenAPI (spec, TS SDK, Dart client) for the removeAssets return type and repo changes.

Deferred to triage (design decisions, not in this change): S2 (real-time projection of contributed
faces), S3 (mobile sync spaceId correlation + revocation), S4 (space-editor album-write RBAC scoping).
@Deeds67
Deeds67 force-pushed the space-albums-onto-main branch from 09dfeb5 to fb709e4 Compare July 16, 2026 10:54
Deeds67 added a commit that referenced this pull request Jul 16, 2026
…B1 / consistency sweep / S5 / S7)

Resolves the confirmed launch blocker and the read-vs-machinery asymmetry surfaced by the
multi-agent audit of #752. The read/timeline layer already unions BOTH linked-album arms
(album_asset OR the cross-owner album_space_asset contribution, #764) via spaceAlbumAssetExists;
retention, count, reconcile, and thumbnail-eligibility joined only album_asset. This teaches them
the same union so a contributed asset is treated consistently everywhere it is visible.

- B1 (blocker) — face retention: getAssetIdsWithoutOtherSpacePath / getAlbumAssetIdsWithoutOtherSpacePath
  route the album arm through spaceAlbumAssetExists (both arms). Removing a direct add (or unlinking)
  no longer sweeps the space person for an asset still reachable via a cross-owner contribution while
  it remains visible in the timeline. New medium test: contributed-path retention.
- S1 / S6 (consistency sweep): the reconcile pager (getAssetIdsInSpacePage) now enumerates album +
  contributed assets so the face-projection fallback can (re)cover them; getAssetCount /
  getRecentAssets / getLastAssetAddedAt / isAssetInSpace now include contributions (count/cover/
  thumbnail eligibility agree with the timeline). New medium test: count + pager.
- S5 — remove-from-space: removeAssets bounds stack-atomic expansion to DIRECT members
  (getDirectAssetIds), so removing an album-projected asset can never drag a directly-added stack
  sibling out of the space; it now returns exactly the ids it removed, and the web RemoveFromSpaceAction
  reflects the real result (no false-success toast / optimistic hide of album-only assets). New medium
  test: album-only removal does not remove a direct stack sibling.
- S7 — rebase cleanup: deleted the dead getOwnedStackSiblingIds / getStackSiblingIdsInSpace repo
  helpers (superseded by StackRepository.getStackedAssetIds) and their dead medium spec (the live path
  is covered by shared-space-stacks.spec.ts + the new S5 test); updated the scope guard (registered the
  contributed helper, swapped the allowlist entry).
- Regenerated SQL + OpenAPI (spec, TS SDK, Dart client) for the removeAssets return type and repo changes.

Deferred to triage (design decisions, not in this change): S2 (real-time projection of contributed
faces), S3 (mobile sync spaceId correlation + revocation), S4 (space-editor album-write RBAC scoping).
@Deeds67
Deeds67 force-pushed the space-albums-onto-main branch from fb709e4 to f33c828 Compare July 16, 2026 11:03
Deeds67 added a commit that referenced this pull request Jul 16, 2026
…B1 / consistency sweep / S5 / S7)

Resolves the confirmed launch blocker and the read-vs-machinery asymmetry surfaced by the
multi-agent audit of #752. The read/timeline layer already unions BOTH linked-album arms
(album_asset OR the cross-owner album_space_asset contribution, #764) via spaceAlbumAssetExists;
retention, count, reconcile, and thumbnail-eligibility joined only album_asset. This teaches them
the same union so a contributed asset is treated consistently everywhere it is visible.

- B1 (blocker) — face retention: getAssetIdsWithoutOtherSpacePath / getAlbumAssetIdsWithoutOtherSpacePath
  route the album arm through spaceAlbumAssetExists (both arms). Removing a direct add (or unlinking)
  no longer sweeps the space person for an asset still reachable via a cross-owner contribution while
  it remains visible in the timeline. New medium test: contributed-path retention.
- S1 / S6 (consistency sweep): the reconcile pager (getAssetIdsInSpacePage) now enumerates album +
  contributed assets so the face-projection fallback can (re)cover them; getAssetCount /
  getRecentAssets / getLastAssetAddedAt / isAssetInSpace now include contributions (count/cover/
  thumbnail eligibility agree with the timeline). New medium test: count + pager.
- S5 — remove-from-space: removeAssets bounds stack-atomic expansion to DIRECT members
  (getDirectAssetIds), so removing an album-projected asset can never drag a directly-added stack
  sibling out of the space; it now returns exactly the ids it removed, and the web RemoveFromSpaceAction
  reflects the real result (no false-success toast / optimistic hide of album-only assets). New medium
  test: album-only removal does not remove a direct stack sibling.
- S7 — rebase cleanup: deleted the dead getOwnedStackSiblingIds / getStackSiblingIdsInSpace repo
  helpers (superseded by StackRepository.getStackedAssetIds) and their dead medium spec (the live path
  is covered by shared-space-stacks.spec.ts + the new S5 test); updated the scope guard (registered the
  contributed helper, swapped the allowlist entry).
- Regenerated SQL + OpenAPI (spec, TS SDK, Dart client) for the removeAssets return type and repo changes.

Deferred to triage (design decisions, not in this change): S2 (real-time projection of contributed
faces), S3 (mobile sync spaceId correlation + revocation), S4 (space-editor album-write RBAC scoping).
@Deeds67
Deeds67 force-pushed the space-albums-onto-main branch from f33c828 to fdd8705 Compare July 16, 2026 11:21
Deeds67 added a commit that referenced this pull request Jul 16, 2026
Deeds67 added a commit that referenced this pull request Jul 17, 2026
…on-bar z-index (#752)

Removing an album-projected asset from a space is a no-op (it's present via a
linked album, not a direct member), yet the web toasted "removed 0 assets" as a
success. Add a member-gated endpoint that resolves which linked album(s) project
the blocked assets, and show a clear message naming the album ("... is in the
album X, which is linked to this space; remove it from the album instead"); only
toast success for assets actually removed.

Also move the space-album selection control bar outside UserPageLayout's z-0
stacking context (matching recently-added/favorites/etc.) so it no longer renders
behind the timeline scrubber and the asset grid.
Deeds67 added a commit that referenced this pull request Jul 17, 2026
…lper (#752)

Rebase of the 282-commit space-albums-onto-main branch onto v3.0.3 main,
squashed to a single commit (net feature diff of 7c12f74..tip re-applied
onto the force-pushed main).

Reconciled the branch's #755 stack-in-space work against main's landed #782:
- server addAssets/removeAssets: use main's #782 expandStackAssetIds
  (visibility-restricted, not owner-scoped) for stack atomicity, while keeping
  the branch's AssetShare permission (required now that album-linking makes the
  AssetRead space arm exploitable) and the branch's multi-path-aware face
  retention (getAssetIdsWithoutOtherSpacePath — keep faces for assets still
  reachable via a linked album/library).
- mobile space timelines: combined the branch's album joins/showInTimeline with
  the stack collapse.
- web space timeline: kept the branch's shell/snippet structure and re-added
  main's #782 withStacked badge prop.
- docs: kept main's #782 Stacked Photos section.

The branch's own getOwnedStackSiblingIds/getStackSiblingIdsInSpace repo helpers
are now unused by the service (superseded by StackRepository.getStackedAssetIds)
but retained with their direct repo test — optional follow-up cleanup.
@Deeds67
Deeds67 force-pushed the space-albums-onto-main branch from ac2bade to 0acbabc Compare July 17, 2026 16:51
Deeds67 added a commit that referenced this pull request Jul 17, 2026
…B1 / consistency sweep / S5 / S7)

Resolves the confirmed launch blocker and the read-vs-machinery asymmetry surfaced by the
multi-agent audit of #752. The read/timeline layer already unions BOTH linked-album arms
(album_asset OR the cross-owner album_space_asset contribution, #764) via spaceAlbumAssetExists;
retention, count, reconcile, and thumbnail-eligibility joined only album_asset. This teaches them
the same union so a contributed asset is treated consistently everywhere it is visible.

- B1 (blocker) — face retention: getAssetIdsWithoutOtherSpacePath / getAlbumAssetIdsWithoutOtherSpacePath
  route the album arm through spaceAlbumAssetExists (both arms). Removing a direct add (or unlinking)
  no longer sweeps the space person for an asset still reachable via a cross-owner contribution while
  it remains visible in the timeline. New medium test: contributed-path retention.
- S1 / S6 (consistency sweep): the reconcile pager (getAssetIdsInSpacePage) now enumerates album +
  contributed assets so the face-projection fallback can (re)cover them; getAssetCount /
  getRecentAssets / getLastAssetAddedAt / isAssetInSpace now include contributions (count/cover/
  thumbnail eligibility agree with the timeline). New medium test: count + pager.
- S5 — remove-from-space: removeAssets bounds stack-atomic expansion to DIRECT members
  (getDirectAssetIds), so removing an album-projected asset can never drag a directly-added stack
  sibling out of the space; it now returns exactly the ids it removed, and the web RemoveFromSpaceAction
  reflects the real result (no false-success toast / optimistic hide of album-only assets). New medium
  test: album-only removal does not remove a direct stack sibling.
- S7 — rebase cleanup: deleted the dead getOwnedStackSiblingIds / getStackSiblingIdsInSpace repo
  helpers (superseded by StackRepository.getStackedAssetIds) and their dead medium spec (the live path
  is covered by shared-space-stacks.spec.ts + the new S5 test); updated the scope guard (registered the
  contributed helper, swapped the allowlist entry).
- Regenerated SQL + OpenAPI (spec, TS SDK, Dart client) for the removeAssets return type and repo changes.

Deferred to triage (design decisions, not in this change): S2 (real-time projection of contributed
faces), S3 (mobile sync spaceId correlation + revocation), S4 (space-editor album-write RBAC scoping).
Deeds67 added a commit that referenced this pull request Jul 17, 2026
Deeds67 added 25 commits July 19, 2026 11:45
…on-bar z-index (#752)

Removing an album-projected asset from a space is a no-op (it's present via a
linked album, not a direct member), yet the web toasted "removed 0 assets" as a
success. Add a member-gated endpoint that resolves which linked album(s) project
the blocked assets, and show a clear message naming the album ("... is in the
album X, which is linked to this space; remove it from the album instead"); only
toast success for assets actually removed.

Also move the space-album selection control bar outside UserPageLayout's z-0
stacking context (matching recently-added/favorites/etc.) so it no longer renders
behind the timeline scrubber and the asset grid.
#752)

Replace the collapsed filter panel's vertical icon rail with a single filter
button in the timeline header. Collapsed, the panel now renders nothing so the
photo grid reclaims the width; the header button (shared FilterToggleButton, with
an active-filter dot) reopens it. Applied consistently across photos, album
detail, space timeline, the space-album page, and the map — where the collapsed
panel used to float over the map's own controls, the toggle now sits next to the
"Map" title.

Also: give each filter section more breathing room above its content, and turn
the panel's collapse chevron into a close (x) icon. Backward-compatible via a new
opt-in externalToggle prop, so the map's mobile drawer keeps the built-in button.
…hug the edge

The People/Places/Recently-added sections sat directly in UserPageLayout's p-2
content, leaving them too close to the side. Add px-2 md:px-4 to each section.
…Toggle mode

Collapsing an externalToggle panel unmounted it, so the transition-[width] had
nothing to animate. Keep the shell mounted at w-0 instead (space still reclaimed,
content inert while hidden) so the width transition glides open/close again.
…edge

The sidebar's item container had pe-6 but no leading padding, leaving the nav
items and active pills flush against the left edge. Add ps-2.
…#752)

The space "Create album" flow dropped you into a nameless empty album with no way
to title or describe it, and the list never refreshed its name/count afterward.
Render the regular album page's editable AlbumTitle + description (owner-gated) as
the space album's timeline header, auto-delete an abandoned empty album on
navigate-away, and re-fetch the linked-album list on mount so names/counts stay
current. Moves AlbumTitle/AlbumDescription to $lib/components/album-page so both
pages share them.
…abandon (#752)

The "linked album" activity captured the album name at link time — empty for the
create-then-name flow and stale after a rename. Resolve the current name live from
the stored album id, and drop link/unlink entries whose album no longer exists
(an abandoned create-flow album auto-deleted on navigate-away). Also allowlist
getLinkedAlbumsContainingAssets in the space-visibility guard (it returns album
id/name only, no asset content) — a pre-existing gap surfaced by the guard spec.
Round the hover/active nav background on both sides (not just the right, per
@immich/ui's rounded-e-full) and add more left inset so the pills sit off the edge.
… no scroll jump

Widen the nav pills toward the edges (ps-2/pe-0). Reserve the scrollbar gutter so
expanding Spaces/Albums no longer shrinks the pills when the thin scrollbar
appears. And drop the expand/collapse caret's own hover background so hovering it
highlights the parent item's pill instead.
The recent-spaces/albums sub-items carried 40px horizontal padding on both
sides (px-10); the right 40px was dead space that truncated names early. Keep
the ps-10 left indent but drop the right padding to pe-4, freeing ~24px of text.
After rebasing onto main's #733 merge-policy rewrite, the in-space merge now runs
main's cross-owner authorizer AND records a PersonMerge activity (the fork's
feature). #733's delegation tests didn't mock logActivity, and the strict
auto-mock fails on any unmocked repository call — so mock it for those cases.
- svelte-check: coerce the bindable `collapsed` (boolean | undefined) to a boolean
  when persisting; the `=== undefined` init keeps the seed-from-storage path.
- a11y/e2e: the collapse button used aria-label "Close", colliding with the album
  cover-selection "Close" (strict-mode violation in album.e2e). Label it "Collapse".
- map e2e: the map filter panel now uses externalToggle, so collapsing surfaces the
  header FilterToggleButton instead of the removed collapsed-icon-strip.
…n redesign

The collapsed filter panel is now an externalToggle header button (filter-toggle-btn)
instead of the inline collapsed-icon-strip. Update the collapse/expand and badge-dot
assertions accordingly: collapsing surfaces the header button, expanding clicks it, and
the single active dot replaces the per-icon strip badges.
The /photos header-button redesign lets the collapsed filter panel reclaim its
width (w-12 → w-0), shifting the timeline's total scroll height by a hair. With
~300 months in the fixture, a medium month's scrubber segment is only ~1.4px
tall, so dragging to its centre resolves — under browser pixel hit-testing — to
the target or an immediately adjacent month. That deterministically nudged the
"2011-8" drag onto its neighbour "2011-9" (1px away), failing the exact-match
assertion.

Accept a landing within one month of the target: that is the achievable
resolution of a sub-pixel scrubber segment, and it stays immune to future
sub-pixel layout shifts while still catching gross mis-navigation (wrong
direction, off-by-many, no scroll at all).
In month/year grouping the timeline renders large representative cards that
hugged the memories carousel. Pad the carousel wrapper (day view untouched) so
its measured height shifts the cards down for clear breathing room.
…ping

At the very top the memories strip occupies the space above the first card, so
getTimelineTopVisibleAnchor found no card and fell back to the first one — the
grouping change then scrolled down to it, flashing the memories out of view.
Return undefined when scrolled above the first card so the top position is kept.
The representative card showed its big centred title whenever it had no cover
asset id — including the brief window before covers finish loading — so the
label flashed in the centre then flicked to the bottom-left overlay. Treat the
loading window as a neutral placeholder and reserve the centred title for a
genuine image-load failure.
… collapse

Switching All→Months/Years let the outgoing day thumbnails play their scale-out
exit animation because updateOptions() only suspends transitions from a
post-render effect — after the view swap had already created the exit
transitions. Suspend transitions from an $effect.pre keyed on the grouping so
the swap is instant; updateOptions() still clears the flag after the reload.
An external-library asset reachable through a space album — owned (album_asset)
or a cross-owner contribution (album_space_asset) — was granted to space members
even when offline, because only the shared_space_library arm gated `isOffline`.
It is masked today (an offline transition also sets deletedAt, which the album
arms check), but it leaned on that cross-module coupling. Add the isOffline guard
to both album arms in checkSpaceAccess/checkSpaceAccessForSpace for parity, and
add medium coverage for external-library assets in a space album (reachable
online, blocked offline, contribution cascades away on asset delete).
…counts

The Members-page per-member count (getContributionCounts) only counted the direct
shared_space_asset pool, so photos a member brought in via linked albums, linked
libraries, or cross-owner contributions were dropped — a member showed far fewer
photos than they had contributed (e.g. 1,355 of 7,815). Mirror getAssetCount's
four sources, attributing each asset to whoever performed the action (addedById)
and UNION-deduping across paths. Adds medium coverage for album/library/
contribution attribution, off-timeline exclusion, and dedup.
New docs page covering linking/creating albums in a space, cross-owner
contributions, per-album timeline control, and the roles/permissions
table, plus a blurb and links from the Shared Spaces page.
* docs(plan): space albums launch fixes implementation plan (#752 follow-up)

* fix(web): report remove-from-album results truthfully, prune only removed assets (#752)

* fix(web): keep the space-album picker open and the grid untouched when adding photos fails (#752)

* fix(web): make the collapsed filter panel reopenable on mobile viewports (#752)

* fix(spaces): filter dead-album activity in SQL so feed pagination never dead-ends (#752)

* fix(spaces): sweep faces of contribution-only assets on unlink/departure/album delete (#752)

* fix(spaces): refresh surviving album grants on member re-join so absence-window contributions sync (#752)

* fix(spaces): regenerate SQL query docs to match make sql output (#752)

* fix(i18n): translate the new album/activity keys for fr/de/nl/pl/es/it (#752)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog:feat Feature change for changelog cli documentation Improvements or additions to documentation 🧠machine-learning 📱mobile 🗄️server 🖥️web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant