Skip to content

feat: server-side user search + user org membership in dashboard#678

Merged
lakhansamani merged 2 commits into
mainfrom
feat/user-search-and-orgs
Jul 12, 2026
Merged

feat: server-side user search + user org membership in dashboard#678
lakhansamani merged 2 commits into
mainfrom
feat/user-search-and-orgs

Conversation

@lakhansamani

Copy link
Copy Markdown
Contributor

Addresses two dashboard user-admin gaps.

1. Server-side user search (was client-side only)

The Users page filtered email.includes(q) over the current page only, so search missed users on other pages — the server _users query had no search param. Now:

  • _users takes ListUsersRequest { pagination, query }; storage ListUsers gains a case-insensitive search over email / given_name / family_name / nickname, across all 6 provider families.
  • Native where efficient (SQL LIKE, Mongo $regex+QuoteMeta, Arango LIKE(...,true), Couchbase N1QL); DynamoDB and Cassandra/Scylla do a documented O(n) scan+filter (no substring index on a non-key attr) — ponytail: comments name the upgrade path (GSI/SASI/external search).
  • Dashboard debounces (~300ms), sends query to the server, resets to page 1, and drops the client-only filter.

2. User's organizations in user details

The User type had no org info and there was no by-user org query. Adds _user_organizations(user_id) (super-admin gated) returning each org + the user's roles there; ViewUserModal lazily fetches and shows an "Organizations" section (with empty + error states). Storage ListOrgMembershipsByUser already existed across providers.

Reviews

  • Security (security-engineer): SOUND, no BLOCKER/HIGH/MEDIUM. Injection-safe on every backend (bound params / QuoteMeta / in-app filter), search returns the same super-admin-gated projection with no extra fields, _user_organizations gates on super-admin and skips dangling memberships, secrets are never in the searchable field set, proto/schema changes are back-compatible.
  • Storage search tests pass across all 5 NoSQL engines (Docker matrix) + SQLite; full integration suite green; build/vet/lint/proto-check clean; dashboard tsc/build/prettier clean.

Notes

  • _users GraphQL arg type PaginatedRequestListUsersRequest (field-compatible; admin-only). Proto UsersRequest.query is additive.
  • LOW follow-up (non-blocking): wildcard %/_ semantics differ across backends (live wildcard on LIKE providers vs literal on Mongo/Dynamo/Cassandra); could escape LIKE wildcards for consistency later.

- extend storage ListUsers with an optional case-insensitive substring
  filter over email/given_name/family_name/nickname across all providers
- SQL/Mongo/Arango/Couchbase use native LIKE/$regex; DynamoDB and
  Cassandra/ScyllaDB scan-and-filter (O(n), no substring index) — documented
- thread the query param through gRPC UsersRequest and a new GraphQL
  ListUsersRequest input; regenerate gen/ and gqlgen output
- dashboard: debounce the search box and drive the list from the server,
  dropping the page-local client-side filter
- add a super-admin GraphQL query returning the organizations a user
  belongs to with per-org roles, backed by the existing
  ListOrgMembershipsByUser storage method (GraphQL-only, matching the
  org admin surface)
- keep it off the User type so user-list rows stay cheap; the dashboard
  user detail view fetches it lazily and degrades gracefully on error
@lakhansamani
lakhansamani merged commit 71d90de into main Jul 12, 2026
6 checks passed
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