fix(server): resolve shared-space birthdays on the asset faces endpoint (#808)#809
Open
Deeds67 wants to merge 1 commit into
Open
fix(server): resolve shared-space birthdays on the asset faces endpoint (#808)#809Deeds67 wants to merge 1 commit into
Deeds67 wants to merge 1 commit into
Conversation
…nt (#808) A name or birthday set inside a shared space is stored on `shared_space_person` and resolved at read time against the face identity — it is never written back to `person`. `PersonService.getById` already overlays that resolution, which is why a person's own overview page shows the age. The asset viewer Info panel does not read that endpoint. For the owner it renders `faceManager.people`, fed by `GET /faces?id=`, and `PersonService.getFacesById` mapped the raw `person` row straight through. For anyone whose birthday only ever existed on a space profile — the common case when a non-owner sets it inside a Space — `person.birthDate` is NULL, so the age silently disappeared on every photo. Apply the same identity-wide resolution in `getFacesById`. `mapFaces` already nulls people the caller does not own, so only owned faces are resolved and no cross-owner metadata is exposed. Each distinct identity is resolved once regardless of how many faces map onto it. The overlay is extracted to `src/utils/person-identity.ts` and `AssetService.applyResolvedPersonMetadata` — the sibling read path the Info panel uses for a space member — now shares it, so the two surfaces cannot drift apart again. Coverage: six unit tests on `getFacesById` (resolution, no identity, resolver miss, non-owned face, identity deduped across faces, birthday already on the base person) and four medium tests that reproduce the reported shape against a real database, proving the real `hydrateAccessiblePeople` query returns the space birthday. Three web tests pin the Info panel's age rendering (present, absent, birthday after the photo). Not changed: `applySpacePeople` still lets a space profile's NULL birthDate win in explicit space context. That is a member-visibility boundary (`sharePersonMetadata`), not the reported bug — the reporter's space profiles all carry the birthday.
Deeds67
force-pushed
the
fix/808-space-birthdate-info-panel
branch
from
July 21, 2026 20:25
8b962a8 to
2da8bba
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #808.
The bug
A name or birthday set inside a shared space is stored on
shared_space_personand resolved at read time against the face identity — it is never written back toperson.PersonService.getByIdalready overlays that resolution, which is why the person's own overview page (/people/{id}) shows the age correctly.The asset viewer Info panel does not read that endpoint. For the owner it renders
faceManager.people, fed byGET /faces?id=(DetailPanelPeople.svelte:28), andPersonService.getFacesByIdmapped the rawpersonrow straight throughmapFaces. When the birthday only ever existed on a space profile — the common case when a non-owner sets it inside a Space —person.birthDateisNULL, so the age silently disappeared on every photo, exactly as reported.The fix
Apply the same identity-wide resolution in
getFacesById.mapFacesalready nulls people the caller does not own, so only owned faces are resolved — no cross-owner metadata is exposed.src/utils/person-identity.ts, andAssetService.applyResolvedPersonMetadata— the sibling read path the Info panel uses for a space member — now shares it, so the two surfaces cannot drift apart again. That refactor is behaviour-preserving; the existingasset.service.spec.tsidentity tests cover both branches and still pass untouched.Coverage
Written test-first; each test was watched failing before the fix landed.
Unit (
person.service.spec.ts, 6 new) — resolution applied; person without an identity; resolver returns nothing; face owned by someone else (staysnull, resolver never called); one identity shared by several faces resolved exactly once; birthday already on the base person preserved.Medium / real database (
test/medium/specs/services/person.service.spec.ts, 4 new) — reproduces the reported shape:person.birthDateNULL, birthday only on ashared_space_personprofile reached via the sharedidentityId. CoversmanualandinheritedbirthDateSource, the no-birthday-anywhere case, and a non-member outsider. These matter because the unit tests stub the resolver; these prove the realhydrateAccessiblePeoplequery actually returns the space birthday for this shape. Verified RED against a real DB (expected null to be '2014-02-14') before the fix.Web (
detail-panel.spec.ts, 3 new) — pins the user-visible symptom: age renders when the birthday arrives on the faces payload, and does not render with no birthday or a birthday after the photo was taken.Deliberately not changed
AssetService.applySpacePeoplestill lets a space profile'sNULLbirthDate win in explicit space context, discarding the base person's value. That looks adjacent but is a member-visibility boundary (sharePersonMetadata), not the reported bug — the reporter's three space profiles all carry the birthday. Changing it would be an RBAC decision, so it is left alone and flagged here.Verification
server: 5099 unit tests pass;tsc --noEmitclean; eslint--max-warnings 0clean; prettier cleanservermediumperson.service.spec.ts: 25/25 pass. The repo has 28 pre-existing medium failures on this base (unbuilt plugin-core, exiftool) — baseline captured before and after; this branch adds noneweb: 3657 tests pass;tsc --noEmitclean; lint 0 errors