Aller au contenu principal

ADR-022 — UsersPage V2 spec

1. Context

Current UsersPage table has 8 columns: Name, Department, Platforms, Interactions, PII Detections, Avg Risk, Top Platform, Last Seen. Gaps:

  • No view of which surfaces (extension / agent / proxy) each user is enrolled into — operators can't tell "who's actually being protected" vs "who's only registered".
  • No Role / Status visible — admin actions require external query.
  • No MFA status — security hygiene blind spot.
  • "PII Detections" label conflicts with ADR-015 lexicon refactor (PII → Risk Signals).
  • No bulk actions — supporting onboarding cohorts is manual.
  • No alternative views (department pivot, onboarding funnel, risk anomaly) — operators can't answer "which department lags adoption" without exporting CSV.

This ADR fixes the table spec officially so issues can reference it and the implementation lands consistent across migrations.

2. Decision summary

  • 16 columns total in the column model (default visible: 8; rest behind column-visibility toggle from TanStack Table per ADR-021).
  • Entitlements column = three chips per user (Ext / Agent / Proxy), color-coded by enrollment state.
  • Lexicon alignment with ADR-015: "PII Detections" → "Risk events". Header keys + i18n strings updated.
  • Alternative views introduced as page-level tabs alongside the main table:
    • Table (default — V2 spec below)
    • Department pivot — adoption% per dept
    • Onboarding funnel — invited → joined → ext-installed → first-detection → habitual-use
    • Risk anomaly — top users deviating from peer baseline
  • All views share the same DataTable component for consistency; alternative views layer aggregations on top.

3. Column model

PosColTypeDefault visibleTierSource / Notes
1Name + avatar + emailidentity, sticky-leftyesallexisting
2Departmentchipyesallexisting (#39 backfill in roadmap if needed)
3Rolechip (Admin/Analyst/Viewer/Tenant Admin/Noxys Staff)yesallNEW — needs users.role confirmed in backend
4Statusdot+text (Active / Invited / Suspended / Deactivated)yesallNEW — needs users.status
5Entitlements3 chips (Ext, Agent, Proxy)yesallNEW — sources from per-surface enrollment tables
6MFAicon (✓ / ✗ / pending)yesallNEW — users.mfa_enabled boolean + method enum
7Risk events 30dnumber + delta arrowyesPro+replaces "PII Detections"; aggregate over 30d
8Avg risk scorebar 0-100noPro+existing — moved to optional default
9Top services (3)chip stacknoallexisting
10AI cost 30dcurrencynoPro+NEW — LiteLLM rollup per user (USERS-7)
11Last seenrelative timeyesallexisting — backfill via roadmap #26
12Last enrolled (Ext)relativenoPro+NEW — extension first-enroll timestamp
13Coaching statusicon (none / pending / escalated)noPro+NEW — pending review queue
14Region pinflag emoji + codenoEnterpriseper ADR-019 (only when tenant region_pin is multi or per-user override exists)
15Managerlink to usernoallV2 — depends on org-chart import (CSV upload or directory sync)
16Actionsmenu, sticky-rightyesallinvite/suspend/reset MFA/edit role/delete + bulk-action target

Default visible (8 cols): 1, 2, 3, 4, 5, 6, 7, 11, 16. Other 7 cols user-toggleable; preference persisted per-user via localStorage (key noxys.users.cols.<userId>).

4. Entitlements chip details

Each user row's "Entitlements" col renders three mini chips horizontally:

  • 🌐 Ext — Extension enrolled
  • 💻 Agent — Endpoint agent enrolled
  • 🛡️ Proxy — Proxy capturing this user's traffic

States (each chip):

  • Active (filled brand-cyan): enrolled + heartbeat received within 24h
  • Stale (filled amber): enrolled but no heartbeat >24h <7d
  • Inactive/Disconnected (filled red): enrolled but no heartbeat >7d
  • Not enrolled (gray outline only)

Hover → tooltip with: enrolled date, version, last heartbeat, channel (stable/staging per ADR-013).

Click chip → context modal:

  • If Not enrolled: action "Send enrollment instructions" (email user + show install link)
  • If Active: "Force re-enroll" / "Unenroll" / "View device details"

5. Bulk actions (toolbar above table)

When 1+ rows selected:

  • Suspend / Reactivate
  • Reset MFA
  • Force re-enroll surface (Ext / Agent / Proxy)
  • Assign role
  • Set department
  • Add tags
  • Export selection (CSV / JSON)
  • Delete (with confirm)

Bulk action availability gated by RBAC: Tenant Admin can do user-mgmt actions; Noxys Staff can do all + cross-tenant actions.

6. Filter toolbar

  • Search (name + email + department)
  • Department (multi-select)
  • Role (multi-select)
  • Status (multi-select)
  • Entitlement state — dropdown: "missing extension" / "missing agent" / "missing proxy" / "stale heartbeats" / "all enrolled"
  • Risk events 30d (slider min)
  • Region pin (Enterprise only)
  • Tags

7. Alternative views (tabs at top of page)

7.1 Department pivot (Department × Adoption)

Aggregation table: | Department | Headcount | Ext% | Agent% | Proxy% | Risk events 30d | Top services |

Click row → drill to filtered Users table for that department.

7.2 Onboarding funnel

Stage breakdown chart + table:

  1. Invited (sent email)
  2. Joined (accepted invite)
  3. Ext installed (first heartbeat)
  4. First detection (any risk event)
  5. Habitual user (≥10 events past 30d)

Per-stage count + drop-off %. Alert if stage 2→3 drop >40% (likely install friction).

7.3 Risk anomaly board

Top N users with risk score significantly deviating from same-department peers (z-score > 2). Surfaces "outlier behavior" — could be insider threat OR new high-value user, depends on context. Pro+ feature.

8. Backend gaps to fill

  • users.role column or user_roles table (confirm exists; if not, add).
  • users.status enum (Active / Invited / Suspended / Deactivated).
  • users.mfa_enabled + mfa_method (TOTP / WebAuthn / sms).
  • Per-user enrollment rollup endpoint:
    • GET /api/v1/users/:id/entitlements{extension: {state, version, last_heartbeat}, agent: {...}, proxy: {...}}
    • List endpoint augmented with rollup so table doesn't N+1.
  • AI cost per user aggregate (LiteLLM telemetry → user_id rollup, materialized view 1h refresh).
  • Coaching status table (coaching_reviews) — separate spec, optional.
  • Manager FK (users.manager_user_id nullable) + UI for admin to set / CSV import.

9. Sprint plan — 7 sprints, 9 days

IDTitleRepoWindowEffortPriority
USERS-1Backend — per-user entitlements rollup endpoint (Ext / Agent / Proxy enrollment states + heartbeat)noxys-apiW23-241.5dP1
USERS-2UsersPage V2 — TanStack Table migration + new cols (Role, Status, Entitlements, MFA, Region)noxys-consoleW25-262dP1
USERS-3UsersPage V2 — col visibility toggle, bulk actions, advanced filtersnoxys-consoleW25-261.5dP2
USERS-4UsersPage V2 — Department pivot view + Onboarding funnelnoxys-consoleW27-281.5dP2
USERS-5UsersPage V2 — Risk anomaly board (peer comparison via z-score)noxys-consoleW27-281dP3
USERS-6UsersPage — Lexicon refactor: "PII Detections" → "Risk events" (aligns EXT-UX-1)noxys-consoleW23-240.25dP1
USERS-7Backend — AI cost per user aggregate (LiteLLM telemetry rollup)noxys-apiW27-281.5dP2

10. Dependencies

  • USERS-2 depends on USERS-1 (entitlements endpoint).
  • USERS-2 depends on TANT-1 (DataTable wrapper, ADR-021).
  • USERS-6 coordinates with EXT-UX-1 (lexicon refactor).
  • USERS-7 depends on ADR-012 LiteLLM landed (PROXY-LITELLM-1/2).
  • Roadmap #26 (last_seen backfill) precondition for USERS-2 col accuracy.

11. Open questions

  • Coaching status table: separate ADR or absorb in this one? Recommend defer — single coaching pipeline ADR later when product is shaped.
  • Manager / org-chart: directory sync (Entra/Google Workspace) preferred over manual CSV. Defer to USERS-V3 (post-W30).
  • Tags model: free-form per-tenant strings or controlled vocabulary? Recommend free-form V1, controlled vocab V2 if tenants ask.
  • localStorage col preferences: persist per-user or per-device? Recommend per-userId for cross-device consistency, with localStorage as fallback offline.

12. Non-goals

  • Replacing the user invite flow (separate page).
  • Cross-tenant user merge (rare, sales-touch only).
  • User analytics dashboards (separate from UsersPage).
  • Per-user policy editor (lives in PoliciesPage).

13. Refs

  • ADR-012 LiteLLM bundled in proxy (cost per user telemetry source)
  • ADR-013 Extension versioning (heartbeat data drives entitlement chip state)
  • ADR-015 Extension UX modes (lexicon binding)
  • ADR-019 Storage tiers (region pin col)
  • ADR-021 TanStack Query + Table adoption (DataTable wrapper consumed)
  • ADR-024 Authentication & MFA strategy (TOTP/WebAuthn/backup codes encrypted via KMS pattern; tenant token reveal + tenant-wide MFA enforcement)
  • Roadmap #26 (last_seen backfill precondition)
  • Roadmap #39 (inventory parallel pattern)
  • Existing: src/pages/UsersPage.tsx (27KB, baseline for V2 refactor)
  • Future ADR-027 CRM choice (renumbered through ADR-019..ADR-026 — ADR-026 = API/OpenAPI policy)
  • ADR-026 API completeness & OpenAPI policy (every endpoint defined in this ADR must have OpenAPI 3.1 spec entry; backfill obligation in §9)