User Directory (cross-tenant)
En bref
A cross-tenant lookup and recovery surface for every human on the platform. Search by email, name, license number, phone, or user id; drill into a unified detail with sessions, devices, audit, and tickets; recover credentials; lock, unlock, soft-delete, merge duplicates; and inspect both the effective state and a per-user timeline stitched from nine source collections.
Comment ça fonctionne
Every operator-facing user task starts here. `GET /sys/user-directory?q=…` searches across all tenants by email, name, license, phone, or user id and returns hits enriched with tenant context and role. The detail view at `sys/(dashboard)/user-directory/[id]` aggregates profile, tenant memberships, sessions, devices, audit timeline, support history, open tickets, and linked OAuth identities into a single page. Recovery actions — reset password, reset MFA, reset WebAuthn, resend verification — are POSTed individually, each requiring a reason and fresh-auth, and each producing an audit row with the reason embedded.
Lock/unlock toggles a temporary block that is shown to the user as `contact support` at login without deleting any data. Soft-delete marks the user disabled and anonymises PII; the account is recoverable for 30 days, then hard-deleted. Impersonation is a one-click button that hands off into the F21.02 consent flow rather than starting impersonation directly, so the user always sees a grant request before any session opens.
The session panel lists active sessions per device and supports per-session or all-but-current revoke. Merge consolidates two accounts that turn out to be the same human across tenants: the preview endpoint shows the diff, the operator confirms, and the merge writes a full audit trail. Two power tools sit at the end.
The effective-state inspector returns one 60-second-cached payload that aggregates identity, sessions, tenant context, capabilities, feature flags, experiment assignments, pending operations, open support grants, open tickets, billing, and anomalies; an embedded rule engine flags failed-login spikes (≥3 in 24h), logins from new IPs (30-day lookback), long inactivity (≥90d), and the locked-with-active-session edge case. The per-user timeline aggregates nine source collections (`user_sessions`, `sys_failed_login_samples`, `sys_audit_entries`, `support_access_grants`, `impersonation_sessions`, `invoices`, `notifications`, `sys_incidents`, `legal_document_acceptances`) into a chronological stream with filter chips per kind, jump-to-date, and row-level drill-in — no new event-of-record collection, just a query-time merge with paging.
Capacités clés
- Cross-tenant search by email, name, license, phone, user id with tenant + role context
- Unified detail view: profile, sessions, devices, audit, tickets, OAuth identities
- Reason + fresh-auth recovery actions: reset password / MFA / WebAuthn / resend verification
- Lock/unlock without delete; soft-delete with 30-day recovery window
- Impersonate from detail view via F21.02 grant flow
- Per-device session panel with individual or bulk revoke
- Merge duplicates with preview, confirm, and full audit trail
- Effective-state inspector with anomaly rules and Copy-as-text/JSON for tickets
- Per-user timeline stitched at query time from nine collections, paginated
En pratique
A support operator picks up a ticket from a player who cannot log in. She searches by email, opens the detail view, and the effective-state inspector flags a failed-login spike: nine attempts in two hours from a new IP. She clicks `Copy as text`, pastes the snapshot into the ticket, and asks the player to confirm the IP.
The player confirms it is not theirs. She clicks `Reset MFA`, enters reason `suspected credential stuffing`, completes the fresh-auth passkey, and revokes all sessions but the most recent verified device. She then opens the timeline view, filters to `sys_failed_login_samples`, and forwards the IP to security operations.
Fonctionnalités de ce sous-système
10| ID | Status | Fonctionnalités |
|---|---|---|
| F21.06.01 | Livré | Search all users across all tenants by email, name, license number, phone, user id. Results include tenant context + role. ✅ PL-T126 |
| F21.06.02 | Livré | User detail view — profile, tenant memberships, sessions, devices, audit timeline, support history, open tickets, linked OAuth identities. UI: sys/app/(dashboard)/user-directory/[id]/index.tsx. API: GET /sys/user-directory/{user_id}. Implemented (PL-T126) |
| F21.06.03 | Livré | Account recovery — reset password, reset MFA, reset WebAuthn, resend verification email. Each requires reason + fresh-auth. UI: user-directory/[id]/recovery.tsx. API: POST /sys/user-directory/{user_id}/{reset-password,reset-mfa,reset-webauthn,resend-verification}. Implemented (PL-T126) |
| F21.06.04 | Livré | Lock/unlock account — temporary block without delete. Shown to user at login as "contact support". API: POST /sys/user-directory/{user_id}/{lock,unlock}. Implemented (PL-T126) |
| F21.06.05 | Livré | Soft-delete — marks user disabled + anonymized PII. Recoverable 30 d. Hard delete after grace period. API: POST /sys/user-directory/{user_id}/{soft-delete,restore}. Implemented (PL-T126) |
| F21.06.06 | Livré | Impersonate from detail view — inherits the reason prompt + audit from F21.02. Grant-flow-knapp i user-directory/[id]/index.tsx triggar /support-access/grants + F21.02-flödet. Implemented (PL-T126 + PL-T122) |
| F21.06.07 | Livré | Session panel — list active sessions for a user, per-device. Revoke individually or all-but-current. UI: user-directory/[id]/sessions.tsx. API: GET /sys/user-directory/{user_id}/sessions, DELETE /sys/user-directory/{user_id}/sessions[/{session_id}]. Implemented (PL-T126) |
| F21.06.08 | Livré | Merge duplicate users — consolidate two accounts (same person across tenants) into a single identity with linked tenant profiles. Audit-trail of the merge. UI: user-directory/merge.tsx. API: POST /sys/user-directory/merge/preview, POST /sys/user-directory/merge/{operation_id}/{confirm,cancel}. Implemented (PL-T126) |
| F21.06.09 | Livré | Effective-state inspector — GET /sys/users/{id}/effective-state?tenant_id=… aggregates identity + sessions + tenant context + capabilities + feature flags + experiment assignments + pending ops + open support-grants + open tickets + billing + anomalies in a single 60 s-cached payload. Sys-UI sys/app/(dashboard)/user-directory/[id]/effective-state.tsx renders a three-column layout with a red-bordered anomaly banner and "Copy as text / JSON" for ticket replies. sys_support / sys_security; every read audited as sys.user.effective-state.view. Anomaly rule engine detects failed-login spikes (≥3/24 h), logins from new IPs (30 d lookback), long inactivity (≥90 d), and locked-with-active-session. ✅ PL-T145 |
| F21.06.10 | Livré | Per-user timeline — GET /sys/users/{id}/timeline?from&to&kinds&limit&offset aggregates a kronologisk stream from nine source collections (user_sessions, sys_failed_login_samples, sys_audit_entries, support_access_grants, impersonation_sessions, invoices, notifications, sys_incidents, legal_document_acceptances) — no new event-of-record collection. Sys-UI sys/app/(dashboard)/user-directory/[id]/timeline.tsx with filter chips per kind, jump-to-date picker, and row-level drill-in to audit / incident / invoice / grant detail. Paginated (TIMELINE_MAX_PAGE=500, default 100). sys.user.timeline.view audited. ✅ PL-T145 |