Summary
On a deployment without the Slack surface, the project Add people search always returns No matches — even for principals who have signed in through the portal, appear on the Admin Users page, and hold org_admin grants.
Cause
The web UI's member search calls GET /v1/directory/resolve, which resolves purely against the directory store (src/api/routes/directory.ts → app.resolveRecipient → deps.directory.resolve). The only producer that writes members into that store is the Slack surface (src/api/slack-core-client.ts pushing workspace members via upsertDirectory). Web/OIDC sign-ins create principals in the identity store but never touch the directory, so on a web-only deployment the directory stays empty forever and no one can ever be added to a project.
Repro
- Deploy with
services = core, web-ui, admin, portal (no Slack bot), external OIDC sign-in.
- Have two users sign in and appear under Admin → Users.
- Create a project as one of them and search the other's email in Add people → No matches.
Expected
A principal who can sign in should be findable as a project member. Suggested fix: fall back to (or merge in) the identity store's active principals in resolveRecipient, or upsert a directory member on first portal sign-in — the latter keeps a single search path and matches how the Slack surface feeds the directory.
Workaround
Operators can push members by hand with a source-signed POST /v1/directory (members[] of {principalId, displayName, type: "user"}) over fly proxy to core — confirmed working — but that's not discoverable and drifts as people join.
Summary
On a deployment without the Slack surface, the project Add people search always returns No matches — even for principals who have signed in through the portal, appear on the Admin Users page, and hold org_admin grants.
Cause
The web UI's member search calls
GET /v1/directory/resolve, which resolves purely against the directory store (src/api/routes/directory.ts→app.resolveRecipient→deps.directory.resolve). The only producer that writes members into that store is the Slack surface (src/api/slack-core-client.tspushing workspace members viaupsertDirectory). Web/OIDC sign-ins create principals in the identity store but never touch the directory, so on a web-only deployment the directory stays empty forever and no one can ever be added to a project.Repro
services= core, web-ui, admin, portal (no Slack bot), external OIDC sign-in.Expected
A principal who can sign in should be findable as a project member. Suggested fix: fall back to (or merge in) the identity store's active principals in
resolveRecipient, or upsert a directory member on first portal sign-in — the latter keeps a single search path and matches how the Slack surface feeds the directory.Workaround
Operators can push members by hand with a source-signed
POST /v1/directory(members[] of{principalId, displayName, type: "user"}) overfly proxyto core — confirmed working — but that's not discoverable and drifts as people join.