Skip to content

feat(settings): profile location - show, set and clear latitude/longitude - G36 #57

Description

@Adron

Summary

The web publishes an optional profile location (latitude / longitude) that powers its Location and Weather widgets. UserDTO decodes latitude and longitude (UserDTO.swift:92–93), the native app neither shows nor sets them, and UpdateUserRequest has no fields for them — so the value is invisible and unclearable from macOS.

What the web offers (/help/settings ▸ Profile location)

Latitude / Longitude: Optional location for your profile, used by the Weather widget and similar location-aware features

Plus a set-from-current-location action and a clear action, under a Permissions section that requests browser geolocation.

Privacy — read this before designing the UI

This publishes an approximate home location on a public profile. Treat it accordingly:

  • Opt-in only. Never prompt at launch, never as part of onboarding, never bundled into another save.
  • The pane must state plainly, in the pane itself, that the value is publicly visible on the profile.
  • Clear must always work, even if setting is unavailable — a user who set this on the web must be able to remove it from the Mac.
  • If Core Location is used for "set from current location", request when-in-use at the moment the button is pressed and never on a background path. Handle denial by leaving manual entry available, not by nagging.

Unknown to probe first

UserDTO carries a cleared: Bool? flag (UserDTO.swift:95) that hints at a server convention for clearing the value — sending null may not be how it is done. Live probe on the test account returns "cleared":true with latitude:null, longitude:null, which is consistent with "cleared" being the explicit signal rather than a null coordinate pair.

Set a location on the web, then clear it, and watch what the web sends. Do not guess: a wrong clear payload could leave a location published that the user believes they removed. That is the failure mode that matters here.

Division of labor

Kit

  • Add latitude / longitude (and whatever the clear convention turns out to be) to UpdateUserRequest.
  • Contract test covering set and clear, asserting a cleared profile really reads back as cleared.

Domain

  • Location fields on the profile-settings model, with clear modelled as its own operation rather than "write nil" — so the intent is explicit at every layer.

App

  • A Profile location section in Settings: current value, manual lat/long entry, Set from current location, Clear, and the public-visibility notice.
  • Core Location permission requested only on the button press.
  • ⚠️ The App target is sandboxed — confirm the location entitlement is present and that adding it does not disturb the existing notarization/hardened-runtime setup. If it does, ship manual entry + clear first and treat "set from current location" as a follow-up; manual entry alone already closes the invisible-and-unclearable problem.

Tests

  • happy — set a coordinate pair, read it back, see it on the profile
  • invalid — out-of-range latitude/longitude rejected client-side
  • upstream-failure — a failed clear leaves the UI showing the location as still set, never as cleared
  • boundary — clearing an already-cleared profile; a profile with a location set on the web and never touched on macOS

Acceptance criteria

  • A location set on the web is visible and clearable from the Mac.
  • No location is ever published without an explicit user action.
  • Full E2E gate green.

Notes

work-consolidation.md tracks this as G36. Size S–M. Low priority relative to the rest of the account cluster, but the "unclearable from macOS" part is a genuine privacy wart.


Probe result (2026-09-15) — re-scoped, and the setter is deliberately not shipping

The issue was explicit: "Set a location on the web, then clear it, and watch what the web sends. Do not guess: a wrong clear payload could leave a location published that the user believes they removed. That is the failure mode that matters here."

Probed. There is no clear path at all, and the cleared-flag inference in this issue is disproved. Full evidence in #91; the short version:

  • PATCH /api/user/update is the only user-mutation route (OPTIONS /api/user → GET, HEAD, OPTIONS; no /api/user/location).
  • Setting works: {"latitude":47.6062,"longitude":-122.3321} → 200.
  • Every unset form — null, "", "null", false, out-of-range — is 400 latitude must be a number between -90 and 90.
  • Every speculative clear key (clearLocation, location:null, cleared:true) returns 200 and changes nothing, which is worse than a rejection.
  • DELETE /api/user/location → 404.

On cleared: this issue reasoned that "cleared":true alongside null coordinates was "consistent with 'cleared' being the explicit signal". It was correlation, not mechanism — setting a location leaves cleared at true, and writing cleared:true clears nothing. In the live OpenAPI it sits among spamScore, spamReasons, signupIp — a moderation field that happens to share a name with what a clear flag would be called.

Why the setter is not shipping

This issue calls the situation "a genuine privacy wart", and it is right — but the wart is unclearable, not invisible. Shipping "set" without "clear" would make macOS a way to publish an approximate home location on a public profile that the user cannot then remove from anywhere. That is strictly worse than today.

Its own acceptance criterion says so: "Clear must always work, even if setting is unavailable." Clear cannot work. So setting does not ship either.

Re-scoped macOS work

In scope now — the read-only half, folded into the Profile settings pane (#46) rather than a standalone PR, since it is the same pane:

This closes the "invisible" half of the complaint — a location set elsewhere becomes visible on the Mac — without widening the "unclearable" half.

Blocked on #91: manual lat/long entry, Set from current location (and with it the Core Location entitlement question), and Clear. They land together, because clear is the one that makes the others safe.

⚠️ The test account now has a location it cannot lose

The probe set 47.6062 / −122.3321 on the .env contract-test account and could not undo it. That is the bug reproduced, not carelessness — but it does need clearing out of band. Noted on #91.

Activity

  1. added
    enhancementNew feature or request
    parityWeb-parity gap with the InterlinedList web app
    on Sep 7, 2026
  2. added
    blockedCannot proceed — backend-gated or spike-first
    on Sep 15, 2026
  3. Adron commented on Sep 16, 2026

    @Adron
    MemberAuthor

    Read-only half shipped (PR #92) — the rest is blocked on #91

    Recording where this stands so the next reader does not have to reconstruct it.

    Shipped

    Settings ▸ Profile now shows a published location, with the plain statement that it is publicly visible and that it cannot be removed from the app, linked to #91. That closes the "invisible" half of this issue's complaint: a location set on the web is visible on the Mac.

    There is a test asserting that no coordinate ever reaches a PATCH body, because the failure mode that matters here is writing one by accident.

    Blocked, and deliberately so

    Manual lat/long entry, Set from current location, and Clear all wait on #91: a location can be set through this API and cleared through nothing. Every unset form is a 400; every speculative clear key returns 200 and changes nothing.

    This issue's own acceptance criterion settles the sequencing — "Clear must always work, even if setting is unavailable." Clear cannot work, so setting does not ship either.

    Two things that fall out of that, and are therefore not open questions any more:

    • The Core Location entitlement question (whether adding it disturbs the notarisation/hardened-runtime setup) does not need answering yet. "Set from current location" cannot ship before Clear does, so the entitlement work belongs with that, not before it.
    • The cleared flag inference in this issue's body is disproved — see upstream: a profile location can be set through the API but never cleared #91. It is correlation, not mechanism: setting a location leaves cleared at true, and writing cleared: true clears nothing. In the live OpenAPI it sits among spamScore, spamReasons and signupIp.

    What we need from you

    Nothing on this issue. Answer #91 and this becomes a small, well-understood piece of work.

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

    blockedCannot proceed — backend-gated or spike-firstenhancementNew feature or requestparityWeb-parity gap with the InterlinedList web app

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions