# QuickDesk fleet metrics

> How the QuickDesk Overview tiles are counted: devices, heartbeat-based online state, 24h sessions, recordings and storage, address books and peers.

The QuickDesk **Overview** screen is five counters over one tRPC call. Every
tile on the screen comes from a single `adminQuickdesk.overview` query, so all
five numbers describe the same instant and all five fail together.

The underlying procedure assembles the payload from three places:

| Part of the payload                                              | Where it comes from            |
| ---------------------------------------------------------------- | ------------------------------ |
| `devices`, `recordings`, `recordingBytes`, `addressBooks`, `peers` | Postgres counts               |
| `online`                                                         | Redis                          |
| `sessions24h`                                                    | One ClickHouse `uniq` aggregate |

The screen issues the query on mount with no polling interval. The tiles are a
snapshot from page load, not a live meter — remount or reload the screen to
re-read them.

## What counts as a device

`devices` is the registered fleet size for the tenant: one row per device that
has been enrolled into QuickDesk and not removed. It is a Postgres count, so it
is state, not activity. A device that has been powered off for weeks still
counts toward `devices`; it simply does not count toward `online`.

This is why the **Devices** tile carries `N online now` as its sub-label. The
big number is the fleet you administer, and the sub-label is the part of it that
is reachable right now. The two are read in the same call, so the sub-label can
never disagree with the **Online** tile beside it.

## The heartbeat window and online status

Enrolled devices send heartbeats to ClutchCall. The gateway records the most
recent heartbeat per device in Redis, and `online` is the number of devices whose
last heartbeat falls inside the **heartbeat window** — the trailing interval the
deployment treats as "still alive".

Two consequences matter when you read the tile:

- **Online is a decayed value, not a connection state.** No socket is probed
  when you load the screen. A device that dropped off the network mid-window
  keeps counting as online until its last heartbeat ages out of the window.
- **The window length is a deployment setting.** It is configured on the
  QuickDesk backend, not per screen and not per tenant in the console, and this
  page does not fix a value for it. Check your gateway config for the window
  your fleet is actually evaluated against, because it sets the worst-case lag
  between a device going dark and the tile reflecting it.

Because the value lives in Redis rather than Postgres, a flushed or
newly-restarted Redis reports a low `online` against an unchanged `devices`
until heartbeats repopulate it.

## Sessions in the last 24 hours

`sessions24h` counts remote-control connections to devices in the trailing
24 hours. It is computed as a single ClickHouse `uniq` aggregate, which has two
implications:

- **It is de-duplicated, not summed.** Session telemetry can write several rows
  for one connection — setup, state transitions, teardown. `uniq` collapses
  those to one, so the tile reports distinct sessions rather than event rows.
- **It is one scalar, not a series.** The procedure runs one aggregate over the
  window. There is no per-hour bucketing behind this tile, so you cannot read a
  trend or a peak off it. It answers "how much remote control happened today",
  and nothing finer.

The window is trailing and continuous: a session that started 25 hours ago and
is still open contributes nothing, and the number falls as old sessions age out
even if nobody connects.

## Recordings and storage accounting

The **Recordings** tile shows `recordings` as its value and `recordingBytes`,
rendered through the console's byte formatter, as its sub-label.

Both numbers are Postgres counts over the same set of recording rows, so they
are consistent by construction:

- `recordings` is the number of recording rows for the tenant.
- `recordingBytes` is the stored size of exactly those recordings, in bytes.

A recording whose row no longer exists contributes to neither number. The
storage figure is therefore the size of the recordings you can still see and
play from the console, not a billing statement and not a bucket-level disk
measurement — reconcile against object-storage usage rather than assuming they
match.

## Address books and peers

The last tile covers the operator-side directory rather than the fleet.

- An **address book** is a saved, named collection of remote endpoints an
  operator can initiate a session to. `addressBooks` counts those collections
  for the tenant.
- A **peer** is one entry inside an address book — a single addressable
  destination. `peers` counts entries, aggregated across every address book in
  the tenant, which is why it appears as the sub-label (`N peers`) rather than
  as its own tile.

Both are plain Postgres counts of configuration. Neither reflects reachability:
a peer entry can point at a device that has not heartbeated in months, and
`peers` will still count it. Compare `peers` against `devices` and `online` to
spot a directory that has drifted away from the fleet it is supposed to describe.

## Overview payload reference

`adminQuickdesk.overview` takes no input and returns one flat object. The screen
consumes exactly these fields:

| Field           | Tile                | Rendered as        | Meaning                                                 |
| --------------- | ------------------- | ------------------ | ------------------------------------------------------- |
| `devices`       | Devices             | value              | Enrolled devices for the tenant.                        |
| `online`        | Devices / Online    | sub-label / value  | Devices whose last heartbeat is inside the window.      |
| `sessions24h`   | Sessions (24h)      | value              | Distinct remote-control sessions in the trailing 24h.   |
| `recordings`    | Recordings          | value              | Recording rows for the tenant.                          |
| `recordingBytes`| Recordings          | sub-label (bytes)  | Stored size of those recordings.                        |
| `addressBooks`  | Address books       | value              | Address books for the tenant.                           |
| `peers`         | Address books       | sub-label          | Peer entries across all address books.                  |

Every field is consumed as a scalar. There are no nested objects, no lists and
no per-device detail in this payload — the Overview screen is deliberately a
roll-up, and device-level answers come from the device screens instead.

## When the tiles render dashes

The Overview tiles have three display states, and telling them apart is the
fastest way to diagnose a blank screen:

| What you see                          | Query state              | What it means                                           |
| ------------------------------------- | ------------------------ | ------------------------------------------------------- |
| `…` in every value, no sub-labels     | Query still pending      | The call is in flight. Normal on first paint.           |
| Numbers                               | Settled with a payload   | Everything below is fine.                               |
| `—` in every value, no sub-labels     | Settled with a null payload | The procedure returned nothing to render.            |

The em dash is not an error toast and not a zero. It means the query **settled**
and the payload was null, which happens when the QuickDesk backend is not
present in this deployment, or when the permission gate on
`adminQuickdesk.overview` denies the caller. The screen renders dashes on
purpose in that case: an earlier version dereferenced the null payload and
blanked the whole console instead of one screen.

Two things follow from the payload being all-or-nothing:

- **Dashes are never partial.** Because one query backs all five tiles, you
  cannot see a real device count next to a dashed session count. If some tiles
  show numbers, the payload arrived and the remaining numbers are genuinely
  those values — a `0` is a real zero.
- **Sub-labels vanish with the values.** The sub-labels that interpolate payload
  fields (`N online now`, the formatted byte size, `N peers`) render as empty
  while pending or null. The two static sub-labels — `within heartbeat window`
  and `remote-control connections` — are literal text and stay visible in every
  state, so their presence tells you nothing about the query.

To distinguish an absent backend from a denied gate, check the caller's
capability scope against the procedure first; see
[Authentication](/concepts/authentication) for how control-plane scopes are
evaluated.

## Related

- [Authentication](/concepts/authentication) — API-key scopes on control-plane procedures
- [Telemetry](/platform/telemetry) — the metric, trace and CDR streams behind console counters
- [Telephony Metrics](/glossary/metrics) — definitions for the call-side numbers
