Skip to content

feat(members): apply tags to a member - #64

Merged
SiteRelEnby merged 1 commit into
mainfrom
feat/member-tags
Aug 27, 2026
Merged

feat(members): apply tags to a member#64
SiteRelEnby merged 1 commit into
mainfrom
feat/member-tags

Conversation

@SiteRelEnby

Copy link
Copy Markdown
Collaborator

Came out of a support question: "how do I add tags to a member?" The answer on Android was "you can't."

The gap

Settings > System > Tags lets you create, rename and delete tags. Nothing lets you put one on a member: no tag UI anywhere in the member screens, and the API layer only carried the tag CRUD endpoints (/v1/tags), never the member-tag one. So an Android-only user could build an entire tag vocabulary and then have no way to use it.

What's added

GET and PUT /v1/members/{id}/tags, plus a chip picker that follows the relationships editor on the same two screens:

  • Member editor - a chip per tag in the system, filled when applied, tap to toggle.
  • Member profile - the applied tags, read-only. Renders nothing at all when the member has no tags, so it drops in unconditionally.

Both sit inside the existing "existing members only" guard, since a member being created has no id to attach tags to yet.

A tap applies immediately rather than waiting for the editor's Save. The tag set is its own endpoint, not part of the member body that Save flushes, and the relationships editor directly beside it already works this way.

The sharp edge

The endpoint takes the member's complete tag set, not a delta. A toggle that sent only the changed tag would silently strip every other tag off the member - no error, no warning, just quietly fewer tags. That's the main thing the 8 tests pin: adding sends the whole resulting set, removing sends the remainder, removing the last one sends an empty list rather than skipping the call.

They also cover the optimistic rollback: leaving a chip filled after a refused write would report a tag as stuck when it isn't.

Smaller calls

  • A system with no tags defined gets a pointer to Settings > System > Tags rather than an empty card.
  • Listing the tag vocabulary is best-effort: a viewer who can read a member's tags but not list them all still sees what's applied, just with nothing to add from.
  • A reload can't stomp an edit - the composable's LaunchedEffect can re-fire, and a reload that reset the selection would undo a toggle the user just made. Tested.

Divergence from web

Web shows this on the member profile only. Here it's editable in the editor and read-only on the profile, matching how relationships already work on Android. Following the in-repo pattern seemed better than matching web's placement and having the two adjacent features behave differently.

Testing

:app:assemblePlayRelease, :app:assembleOpenRelease, :app:testPlayReleaseUnitTest green; 8 new unit tests.

Device checklist:

  • Member editor: chips for every tag, tapping fills/unfills, and it sticks across leaving and reopening
  • Apply two tags, then remove one: the other survives (the delta trap)
  • Member profile shows applied tags, none of them tappable
  • A member with no tags shows no tag section on the profile
  • A system with no tags defined shows the pointer to Settings, not an empty card
  • Creating a new member shows no tag section, and it appears after the first save
  • Airplane mode: a toggle fails visibly and the chip reverts rather than lying

Tags could be created, renamed and deleted under Settings > System > Tags, but
there was no way to put one on a member: the member screens had no tag UI, and
the API layer only carried the tag CRUD endpoints, not the member-tag one. An
Android-only user could build a whole tag vocabulary and never use it.

Adds GET and PUT /v1/members/{id}/tags and a chip picker, following the
relationships editor on the same screens: editable in the member editor,
read-only on the profile, and rendering nothing in read-only mode when the
member has no tags, so it drops in unconditionally. Both are inside the
existing "existing members only" guard, since a member being created has no id
to attach tags to yet.

A tap applies immediately rather than waiting for the editor's Save. The tag
set is its own endpoint, not part of the member body that Save flushes, and the
relationships editor beside it already behaves this way.

The endpoint takes the member's complete tag set rather than a delta, so a
toggle that sent only the changed tag would silently strip every other tag off
the member. That is the main thing the tests pin, along with the rollback when
a write is refused: leaving a chip filled after a rejected save would report a
tag as stuck when it is not.

A system with no tags defined gets a pointer to where they are created instead
of an empty card. Listing the tag vocabulary is best-effort, so a viewer who
can read a member's tags but not list all of them still sees what is set.

Web shows this on the member profile only; on Android it is editable in the
editor and read-only on the profile, matching how relationships already work
here.
@SiteRelEnby
SiteRelEnby merged commit 25221a3 into main Aug 27, 2026
1 check passed
@SiteRelEnby
SiteRelEnby deleted the feat/member-tags branch August 27, 2026 21:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant