# Operator console access

> How the QuickDesk console gates itself on a server-side operator allowlist, what each gate state means, and why this surface has no tenant switcher.

The QuickDesk console at `admin.quickdesk.sh` is the operator surface for the
QuickDesk remote-desktop modality. Unlike the tenant-facing consoles, it is not
scoped to an organisation you belong to — it is gated on a server-side list of
**platform operators** held by the ClutchCall BFF. The shell renders whatever
allow/deny answer the server gives, so what you see on load tells you exactly
which half of the problem you have: no session, or a session that is not an
operator.

## How the access check works

The shell does not inspect your account and guess. It runs one cheap probe and
renders the result:

1. It waits for `ssoReady` — the SSO cookie hydration that installs a portal
   session into this subdomain. Probing before that resolves would let a fresh
   tab cache a `401` that no longer reflects reality.
2. It calls `adminQuickdesk.overview` once (`retry: false`,
   `refetchOnWindowFocus: false`). This is the same procedure the Overview
   screen uses, so the gate costs no extra round trip in the happy case.
3. It maps the outcome to one of four states.

| Probe outcome                    | Gate state | What the console renders |
| -------------------------------- | ---------- | ------------------------ |
| `ssoReady` pending, or query pending | `checking` | "Checking operator access…" |
| Error with `data.code` = `UNAUTHORIZED` | `signedOut` | "Sign in required" card |
| Any other error                  | `forbidden` | "Not a QuickDesk operator" card |
| Success                          | `ok`        | The routed screens        |

The state is computed once, in a single hook, and shared between the gate body
and the top bar. That is why the `platform operator` badge in the header appears
only in the `ok` state — the badge and the gate cannot disagree about whether
the signed-in account is an operator.

## The two failure states: signed out vs not an operator

Both failure states render a centred card, but they mean different things and
offer different actions.

**Sign in required (`UNAUTHORIZED`).** There is no valid session on this
subdomain. The card's action is a **Sign in** link to the portal hub's `/login`.
Sign in there, not here — the console has no login form of its own. A cold
visitor is redirected before the console paints, via `requirePortalSession()`.

**Not a QuickDesk operator (any other error code).** You are authenticated —
the card names the signed-in email — but that account is not on the operator
list for the QuickDesk console. There is nothing you can do in the browser to
change this. The card's only action is **Reload**, which re-runs the probe after
someone has added your account server-side.

> **NOTE:**
> Because the mapping is "`UNAUTHORIZED` means signed out, everything else means
> not an operator", a transient server error surfaces as the *not an operator*
> card. If you are confident the account is on the list, hit **Reload** before
> escalating.

## Where the allowlist lives and how to add an account

The allowlist is `QUICKDESK_ADMIN_EMAILS`, read on the BFF by the
`adminQuickdesk` router (`routers/admin-quickdesk.ts`). Every procedure the
console calls is behind it; the browser bundle contains no copy of the list and
cannot be edited to bypass it.

Consequences worth knowing before you file a ticket:

- **There is no UI for this.** No screen in the QuickDesk console adds, removes,
  or lists operators. Adding an account is a server-side configuration change to
  `QUICKDESK_ADMIN_EMAILS` on the BFF, made by whoever owns that deployment.
- **The identity is an email address**, matched against the email of the signed-in
  portal account. The deny card prints that email for you — quote it verbatim
  when you ask to be added, so nobody adds the wrong address.
- **Recovery is a reload, not a re-login.** Once the account is on the list, the
  existing session is fine; press **Reload** and the probe re-runs.

## Why QuickDesk operators are individuals, not tenants

The other consoles put a tenant switcher in the shell because their data is
partitioned per organisation. QuickDesk has no switcher, by design: QuickDesk
users are individuals, and this console is the *operator* view over the whole
QuickDesk account and API server — devices, sessions and files, recordings,
address books, webhooks, and releases.

So access here is not "which tenant am I acting as" but "is this human an
operator at all". That is a single yes/no from the server, which is why one
allowlist check gates the entire shell rather than each screen negotiating its
own scope. The top bar reflects the same idea: a `platform operator` pill and
the `quickdesk.sh` environment pill, with no org selector between them.

## Shared portal session across subdomains

The QuickDesk console does not own your identity. It borrows the portal
session:

- **Signing in** happens on the portal hub. The sign-in card links to
  `/login` there, and the session is shared across subdomains, so you land back
  in the console already authenticated.
- **Waiting for hydration.** The gate blocks on `ssoReady` so the shared cookie
  is installed before the first tRPC request goes out.
- **The account menu** (the circular initial in the top bar) shows the
  signed-in email, labels this surface as the QuickDesk operator console, and
  links back to the **Portal hub**.
- **Signing out** calls `signOutEverywhere`, which ends the session across the
  shared surfaces rather than just this tab, then redirects to the portal root.
  The redirect happens even if the sign-out call throws.

Because the session is shared, signing out of another console signs you out of
QuickDesk too. Returning to a stale tab afterwards produces the
**Sign in required** card, not a silent empty screen.

## Related

- [Authentication](/concepts/authentication) — API keys, relay tokens, and browser sessions
- [Telemetry](/platform/telemetry) — the operational streams behind the operator screens
