diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e1afa2..f57651e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,41 @@ All notable changes to Armature are documented here. +## v0.6.15 — User Display Audit + +Every user-facing identity surface now shows human-readable names instead of +UUIDs, with the canonical fallback chain: `display_name → username → "Unknown"`. + +### Added + +- **`GET /api/v1/users/resolve?ids=...`** — batch endpoint returns identity + records (username, display_name, handle, avatar_url) for up to 100 user IDs. + Response keyed by ID for O(1) client lookups. +- **`sw.users` SDK module** — `resolve(id)`, `resolveMany(ids)`, + `displayName(user)` with 60-second local cache. Surfaces use this instead + of ad-hoc lookups or stale snapshots. +- **5 handler tests** for the resolve endpoint (single, multiple, missing, + empty, no-param). + +### Changed + +- **Admin users list** — shows `display_name || username` as primary + identifier, with username shown as secondary when display_name is set. +- **Admin teams/groups member lists** — replaced `username || user_id` + with `display_name || username || 'Unknown'`. +- **Team-admin members** — dropdown and list now show display_name. +- **Chat participants** — resolved from users table via `sw.users.resolveMany()` + instead of relying on creation-time snapshot. Message sender names, typing + indicators, and participant sidebar all use resolved names. +- **Dashboard greeting** — added `|| 'Unknown'` terminal fallback. +- **Team activity log** — capitalized fallback to `'Unknown'`. + +### Deprecated + +- **`participants.display_name` column** in chat-core — column retained for + backward compatibility but UI no longer relies on snapshot values. Comments + added to `packages/chat-core/script.star` noting deprecation. + ## v0.6.14 — Visual Polish Systematic cleanup of stale values, self-hosted fonts, and rendering fixes. diff --git a/ROADMAP-UI.md b/ROADMAP-UI.md index 461f206..d85e336 100644 --- a/ROADMAP-UI.md +++ b/ROADMAP-UI.md @@ -91,17 +91,13 @@ Shipped. Stale fallback colors purged (~65 instances), fonts self-hosted regressions (half-step tokens), theme settings default, surface overflow, and user menu zoom drift. See CHANGELOG.md. -### v0.6.15 — User Display Audit +### v0.6.15 — User Display Audit ✅ -Every place a user identity appears in the UI must show a human-readable -name, never a UUID. Fallback chain: `display_name → username → "Unknown"`. - -| Step | Description | -|------|-------------| -| Participant display-name resolution | `chat-core` participants endpoint resolves `display_name` from the users table at query time instead of relying on a creation-time snapshot. If the stored `display_name` is empty, look up `users.display_name` or `users.username` by `participant_id`. | -| Audit all user-facing identity surfaces | Walk every surface that shows user identity: chat participant list, chat message sender names, chat typing indicators, workflow assignees, team member lists, admin user list, notification actor names. Ensure the fallback chain is `display_name → username → "Unknown"` everywhere. | -| SDK user-resolve utility | Add `sw.users.resolve(id)` or similar to the SDK — returns `{id, username, display_name, avatar}` with local caching. Surfaces use this instead of ad-hoc lookups. | -| Stale snapshot cleanup | Remove or deprecate the static `display_name` column in the participants table. All display names come from the users table via the resolve utility. | +Shipped. `GET /api/v1/users/resolve?ids=...` batch endpoint, `sw.users` +SDK module with `resolve()`, `resolveMany()`, `displayName()` + 60s cache. +Chat participants resolved from users table instead of snapshot. All admin +surfaces show `display_name || username || 'Unknown'`. Chat-core snapshot +column deprecated. 5 new handler tests. See CHANGELOG.md. ### v0.6.16 — Usability Survey Gate @@ -133,7 +129,7 @@ v0.6.13 Responsive & Spacing ✅ SHIPPED ↓ v0.6.14 Visual Polish ✅ SHIPPED ↓ -v0.6.15 User Display Audit ← No UUIDs in the UI, ever +v0.6.15 User Display Audit ✅ SHIPPED ↓ v0.6.16 Usability Survey Gate ← Machine-audit the finished product ``` diff --git a/VERSION b/VERSION index fcbaa84..6769f67 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.6.14 +0.6.15 diff --git a/packages/chat-core/script.star b/packages/chat-core/script.star index a41fa38..0187836 100644 --- a/packages/chat-core/script.star +++ b/packages/chat-core/script.star @@ -91,6 +91,9 @@ def create(title, type="group", participants=None, creator_id="", creator_displa cid = conv["id"] # Add creator as admin participant + # NOTE: display_name is a snapshot captured at creation time. + # DEPRECATED v0.6.15 — UI resolves display names from users table via sw.users.resolve(). + # Column retained for backward compatibility; UI no longer relies on this value for display. if creator_id: db.insert("participants", { "conversation_id": cid, @@ -110,7 +113,7 @@ def create(title, type="group", participants=None, creator_id="", creator_displa "conversation_id": cid, "participant_id": pid, "participant_type": _str(p.get("type", "user")), - "display_name": _str(p.get("display_name", "")), + "display_name": _str(p.get("display_name", "")), # DEPRECATED v0.6.15 — snapshot only "role": _str(p.get("role", "member")), "joined_at": "", }) @@ -213,7 +216,7 @@ def add_participant(conversation_id, participant_id, participant_type="user", di "conversation_id": cid, "participant_id": pid, "participant_type": _str(participant_type), - "display_name": _str(display_name), + "display_name": _str(display_name), # DEPRECATED v0.6.15 — snapshot only "role": _str(role), "joined_at": "", }) diff --git a/packages/chat/js/main.js b/packages/chat/js/main.js index 1b33689..83c86a1 100644 --- a/packages/chat/js/main.js +++ b/packages/chat/js/main.js @@ -243,9 +243,9 @@ onMouseEnter=${() => setHover(true)} onMouseLeave=${() => setHover(false)}> ${!isOwn && html` - <${Avatar} name=${msg._display_name || msg.participant_id} size="sm" />`} + <${Avatar} name=${msg._display_name || 'Unknown'} size="sm" />`}