Skip to content

Owner console must move to the backend profile service API (or be decommissioned) #1612

Description

@toddmitchell

Summary

The owner console (odin-js packages/apps/owner-app) still writes profile attributes by uploading files directly to the ProfileDrive. It does not use the backend profile service (ProfileAttributeService, exposed as PUT /api/v2/profile/attributes and PUT /api/v2/profile/attributes/photo). The owner console must either be migrated onto that API or be decommissioned — two writers for the same data is the source of the divergence described below.

Current state (verified by reading code)

odin-core exposes a server-side write surface:

  • src/apps/Odin.Hosting/UnifiedV2/Profile/V2ProfileController.csPUT /api/v2/profile/attributes, PUT /api/v2/profile/attributes/photo, DELETE /api/v2/profile/attributes/{id}
  • src/services/Odin.Services/Profile/ProfileAttributeService.cs — all writes funnel here, gated on the ManageProfile permission
  • src/services/Odin.Services/Profile/ProfilePublishService.cs — republishes sitedata.json, public_image.json (/pub/image) and public_profile.json (/pub/profile) off DriveFileAdded/Changed/Deleted notifications; registered in TenantServices.cs:328

odin-js does not call it. The owner console writes the attribute file itself:

  • packages/apps/owner-app/src/provider/profile/AttributeData/ManageAttributeProvider.tssaveProfileAttributeuploadFile / patchFile against the ProfileDrive; photoAttributeProcessing builds the prfl_key payload plus 250/600px thumbnails client-side
  • packages/apps/owner-app/src/hooks/profiles/useAttribute.ts → on success calls useStaticFiles().publish(type)
  • packages/common/common-app/src/hooks/staticFiles/useStaticFiles.tspublishProfile / publishProfileImage / publishProfileCardPOST /optimization/cdn/{publish,profileimage,profilecard}

There are no /api/v2 profile calls anywhere in js-lib or owner-app; DotYouClient.getEndpoint() resolves to /api/owner/v1 (or /api/apps/v1, /api/guest/v1).

For contrast, contacts have already made this move: odin-js contact writes go through ContactService via ContactsControllerBase (/api/{owner|apps}/v1/contacts), specifically so the server-side merge owns the record. Profile attributes are the remaining client-side writer.

Why this matters

The client-owned publish step is conditional and fails silently:

  1. useStaticFiles.ts:22 gates publishProfileImage/publishProfileCard on dotYouClient.getType() === ApiType.Owner. This matches odin-core, where profileimage/profilecard exist only on OwnerStaticFileContentControllerAppStaticFileContentController inherits only publish. So a photo saved from any app context never republishes /pub/image.
  2. ProfileCardManager.ts:245 only publishes a Photo attribute whose ACL is Anonymous and whose section is PersonalInfoSectionId. Anything else publishes nothing and leaves the previously published bytes being served.
  3. The client decides what the public artifacts contain (image resize, profile-card shape, which attributes are public). That logic is now duplicated between ProfileCardManager.ts and ProfilePublishService.cs, and the two sets are already documented as deliberately different (see the ProfileCardTriggerTypes comment in ProfilePublishService.cs:84).

Observed symptom that prompted this: saving a profile image through odin-js did not update the public profile image.

Note that ProfilePublishService already covers the direct-upload path server-side (it reacts to any ProfileDrive attribute write, fileType 77, and reuses the client's 250x250 thumbnail), so on current main the publish step is arguably redundant. That makes the duplication a liability rather than a safety net — but it also means the fix is not only "swap the write call", since the client-side publish and the server-side republish can both fire for the same save.

Requested outcome

Pick one and close the gap:

Option A — migrate the owner console.

  • Route profile attribute writes through PUT /api/v2/profile/attributes and PUT /api/v2/profile/attributes/photo
  • Drop the client-side publishProfile / publishProfileImage / publishProfileCard calls from the attribute save path and rely on ProfilePublishService
  • Confirm the V2 write surface covers everything the console writes today: Theme attributes live on the HomePageConfigDrive and are explicitly out of scope for ProfileAttributeService (ProfilePublishService.cs:68-71), and Experience/header-image attributes carry their own payload keys and thumbnail sets — these need either V2 coverage or a documented carve-out
  • Decide the fate of /optimization/cdn/{publish,profileimage,profilecard} once no client calls them

Option B — decommission the owner console in favor of whatever replaces it, and make the replacement a V2-only client from the start.

Open questions

  • Is there a target date / replacement for the owner console that makes Option B the real plan?
  • Does SetPhotoAttributeAsync accept the same rendition set the console produces today (250 + 600px), given the server does not resize?
  • Do other odin-js consumers (homebase-id-app, homebase-web) write profile attributes directly as well? They were not audited here.

Verification note

Everything under "Current state" was verified by reading odin-core main (e3f78eade) and the local odin-js working copy. The claim that the observed stale public image was caused by one of the specific gates above is inferred, not confirmed — it was not reproduced against a running server, and no tenant logs were inspected for the swallowed Failed to republish public_image.json warning that TryRunAsync would emit.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions