# VDNs, Extensions, and Reporting Hotlines

> How a VDN binds a default skill, a reporting hotline, and an optional vector, what its extension number does, and how VDN grouping feeds reporting.

A **VDN** (Vector Directory Number) is the named routing entry point a DID lands
on. In TeleQuick, each VDN row carries five decisions:

| Field              | Purpose                                                       |
| ------------------ | ------------------------------------------------------------- |
| `ext`              | Optional extension number. Mirrors an Avaya VDN extension.    |
| `code`             | Short stable identifier used in config and reporting.         |
| `name`             | Human-readable label shown in the Sankey and in call detail.  |
| `default_skill_id` | Where the VDN queues calls when no special routing fires.     |
| `default_hotline_id` | The reporting bucket the call rolls up to.                  |
| `vector_id`        | Optional multi-step program. Blank means direct-to-skill.     |

The Admin → VDNs screen is the CRUD surface for these rows. Skill, hotline, and
vector are each pickers over the other admin objects, and each is clearable —
all three are nullable on a VDN.

## What a hotline is and how calls roll up to it

A **hotline** is a reporting bucket, not a routing target. It has an id, a
`code`, and a `name`, and it exists independently of the VDN — the VDNs screen
only *binds* one via `default_hotline_id`.

The distinction matters when you lay out your VDN estate:

- The **default skill** decides where the call goes.
- The **reporting hotline** decides which bucket the call is counted in.

Because those are separate fields, several VDNs that queue to different skills
can still roll up to one hotline (for example one "Billing" bucket fed by an
inbound VDN, an overflow VDN, and a callback VDN). The reverse also works: one
skill can be fed by VDNs that report to different hotlines, so you can split
reporting without splitting the queue.

`default_hotline_id` is optional. A VDN with no hotline bound shows `—` in the
**Reports to** column and contributes no hotline rollup.

The table resolves skill, hotline, and vector ids to `code · name` labels
client-side, from the `adminSkills.list`, `adminHotlines.list`, and
`adminVectors.list` queries the screen issues alongside the VDN page. An id that
does not resolve to a row in those lookups renders as a dash rather than as a
raw id.

## VDN extension numbers: Avaya parity vs. routing-only

The `ext` column exists for operators migrating from Avaya platforms, where a
VDN *is* an extension on the switch. Carrying the original number across means
your runbooks, wallboards, and spreadsheets keep referring to the same VDN by
the same digits.

Two things follow from how the screen treats the field:

- **`ext` is optional.** Leave it blank for a routing-only VDN — one that exists
  purely as a named entry point and a reporting grouping, with no legacy number
  attached. Blank `ext` renders as `—`.
- **`ext` is validated as a number, not as a dial plan.** On save, a blank value
  is stored as `null`; anything else must parse as a finite, non-negative
  number, or the form rejects it with
  `Extension must be a non-negative integer or blank.`

The extension is also indexed by the screen's search box, which matches on code,
name, and extension. That is the field's main day-to-day use: finding the VDN
you knew by its old number.

## Vector-less VDNs and direct-to-skill routing

The **Vector** picker is optional, and its placeholder states the fallback:
`— direct-to-skill (no vector) —`.

- **With a vector**, the VDN hands the call to the multi-step program authored
  on the Vectors screen. The table shows the vector's code as a purple chip.
- **Without a vector**, the VDN routes direct-to-skill: the call goes to the
  VDN's default skill with no intermediate program. The **Vector** column shows
  `direct`.

Direct-to-skill is the simpler shape and is usually what you want for a VDN that
exists to name an entry point and give it a reporting identity. Reach for a
vector when the entry point needs conditional steps rather than a single
destination.

Note that the default skill and the vector are independent fields. Setting a
vector does not clear `default_skill_id`; the default skill remains the VDN's
"if no special routing fires" destination, per the field's own hint.

## Deactivating vs. deleting a VDN

These are different operations with different reversibility.

**Deactivate** — uncheck **Active** in the edit drawer and save. `active` is
only editable in edit mode (new VDNs are created active), and it is sent as part
of the update patch. An inactive VDN keeps its row, its code, its bindings, and
its tags; it is simply hidden from the default list view. Turn on **Include
inactive** in the filter bar to see it again, and re-check **Active** to bring
it back.

**Delete** — the **Delete** button in the edit drawer calls
`adminVdns.remove`. The screen confirms first with
`Delete VDN "<code>"? This cannot be undone.` Prefer deactivation for a VDN that
has historical traffic: deleting removes the row that reporting labels resolve
against.

## Where VDN grouping shows up in reporting

VDNs are a reporting dimension as well as a routing object. Two places consume
them:

- **The Sankey at `/ops/vdn`** aggregates calls grouped by VDN. The VDN's
  **Name** is the label that appears there, which is why the field's hint calls
  it the label "shown in the Sankey + call detail." Renaming a VDN renames its
  node.
- **Call detail** shows the VDN a call entered through, again by name.

Hotline rollup sits one level above this: the VDN identifies the entry point,
and `default_hotline_id` groups entry points into the bucket you report on. Pick
VDN `name` values that read well as graph nodes, and pick `code` values you are
willing to keep stable, since the code is the identifier operators will quote.

## Tagging VDNs

Each row has a **Tags** cell backed by the shared tag system under the
`dim_vdn` resource kind. The screen resolves tags for the whole visible page in
one bulk call and the cell itself only writes, so tag edits refresh the page's
tag state rather than the VDN list. Clicking a tag cell does not open the edit
drawer.

Tags are an additional grouping axis alongside hotlines — useful when you want a
cross-cutting label (a migration wave, an owning team) that does not belong in
the reporting rollup.

## Search and pagination

The filter bar drives the `adminVdns.list` query:

| Control              | Effect on the query                                            |
| -------------------- | -------------------------------------------------------------- |
| Search box           | `search` — matches code, name, and extension. Resets to page 1. |
| **Include inactive** | `includeInactive` — adds deactivated VDNs. Resets to page 1.    |
| Pager                | `page` — the list is served 50 rows per page.                   |

The header subtitle reports the total VDN count returned by the query, and the
pager derives its page count from that same total.

## Procedures used by this screen

| Procedure             | Used for                                                        |
| --------------------- | --------------------------------------------------------------- |
| `adminVdns.list`      | The paginated table (`orgId`, `search`, `includeInactive`, `page`, `perPage`). |
| `adminVdns.create`    | New VDN. Takes `orgId` plus `code`, `name`, `description`, `default_skill_id`, `default_hotline_id`, `vector_id`, `ext`. |
| `adminVdns.update`    | Edit. Takes `orgId`, `id`, and a `patch` with the same fields plus `active`. |
| `adminVdns.remove`    | Permanent delete. Takes `orgId`, `id`.                          |
| `adminSkills.list`    | Options for the **Default skill** picker and id → label mapping. |
| `adminHotlines.list`  | Options for the **Reports to hotline** picker and id → label mapping. |
| `adminVectors.list`   | Options for the **Vector** picker and id → label mapping.        |

`code` and `name` are required — the Save button stays disabled until both are
non-empty. `description` is optional and is stored as `null` when blank. After a
successful create, update, or delete the screen invalidates the VDN list so the
table reflects the change.
