Skip to content

helixAppObject

Application-level Helix behaviour — settings that apply to the whole client rather than to a single stop or resource type — is configured as direct children of the domain’s helix block, authored in the domain file as {"define": {"helix": { … }}} (a {"set": {"helix": … }} block is also accepted) and carried on the reference record. It is a Helix addition and is ignored by Spiral itself. (The pre-relaid helix.app.{…} nesting is still read as a legacy fallback, but new domains should use the direct form: helix.contactCentre, helix.heatmap, helix.metric, helix.actionClasses, helix.domains.)

{
"actionClasses": [string] | null,
"heatmap": { radius, idle, late, unresourced } | null,
"metric": { [name]: { median, var, low, high } } | null,
"domains": { [domain]: { [skill]: "skill" | "constraint" | "capacity" } } | null,
}
contactCentre contactCentreObject
Contact-Centre (omni-search) configuration.
actionClasses string
Global catalogue of action class names. A class groups actions, marks a domain-authored definition AUTOMATIC, and is the SKILL GATE: operators are enabled per class in the Administration app (the picker offers this catalogue plus core's built-ins), and the queues show classed actions only to enabled operators. Class-less reaches everyone; the resource audience ignores class. See actionObject and builtInActions.
heatmap { radius, idle, late, unresourced }
Zoomed-out heat-map presentation: radius (metres, default 7500 — each heat point draws ~2×radius across) and the three signal colours as Helix palette names (or CSS values): idle (default "blue"), late ("red"), unresourced ("purple").
metric { [name]: { median, var, low, high } }
Metrics-panel tile colour tolerances, keyed by metric name (sla, stopsPerHour, driveTime, unresourced). A value ≤ median−var shows the `low` colour, ≥ median+var the `high` colour, in between amber — direction is encoded by the colours (e.g. sla: {"median":70,"var":20,"low":"red","high":"green"}; unresourced would reverse them). Colours are Helix palette names or CSS values; unconfigured metrics keep the built-in colouring.
domains { [domain]: { [skill]: "skill" | "constraint" | "capacity" } }
The domain master list (see below). Groups skills by domain and declares each skill’s value-form; the domain names are also the surge domains referenced by surgeZone and the per-type `domain` blocks.
dispatch { resourceList: { sort }, projectList: { sort } }
Dispatch-application configuration: named sort rules for the resource list and the project list. See below.

helix.dispatch configures the dispatch application’s lists. Both the resource list and the project list take named sort rules, and both work the same way:

"dispatch": {
"resourceList": { "sort": { "Activity": ["PACK","FREE","BRK","TIDY","WRAP","RECY","HEAD"] } },
"projectList": { "sort": { "Urgency": ["OSRC","REBK","PLAN","HEAD","ARVD"],
"Value": "byContractValue()" } }
}

Each key becomes an extra entry in that list’s Sort menu, alongside the built-in State, Delay and Earliest. State is always offered first and is the default: it orders on Helix’s own state vocabulary — the raw stop state (and, for resources, the roster duty type) — so it cannot fall out of order when a domain renames a state. Your named rules are the opt-in layer on top, for ordering the vocabulary you invented.

A rule takes one of two forms.

An array — a sequence. The rows rank by the position of their display status (clientState) in the array; anything unlisted sorts after everything named. This covers the common case without writing code.

A string — an order expression. A domain expression bound to a function in your client module, called once per comparison with the row as this and the row it is being compared against as its first argument. Return true when this sorts before that row, false when it sorts after:

// in the client module
byContractValue(other) {
return (this.data.ext?.value ?? 0) > (other.data.ext?.value ?? 0);
}

Any arguments written into the expression itself follow the compared row, so "byField('earliest')" arrives as byField(other, 'earliest').

Use the expression form when the ordering depends on something a list of status names cannot express — a number, a date, a computed score. Helix asks the expression both ways round for each pair, because a “sorts before” test alone cannot distinguish after from equal: rows your expression ranks equally then fall through to the built-in tie-breakers (delay, then earliest / planned arrival). An expression naming a function no module defines leaves the order to those tie-breakers rather than scrambling the list.

helix.domains is the client’s domain master list: it groups skills under named domains and declares each skill’s value-form. The domain names form one shared namespace used three ways:

  1. Skills grouping (here). Each skill is typed skill, constraint, or capacity; the type fixes the value the skills editor writes — skillnull (a boolean capability), constraint{ "max": n }, capacity{ "capacity": n }.
  2. A type’s default domainhelix.domain on a stop / resource / project type names the group the skills editor opens on for that type (Helix-only; not sent to Spiral).
  3. Surge domains — the same names label the per-type surge domain blocks and the surgeZone domain field.
{"define": {"helix": {
"domains": {
"Police": { "police":"skill", "firearms":"skill", "publicOrder":"skill" },
"Ambulance": { "paramedic":"skill", "convey":"skill", "stretcher":"capacity" },
"Fire": { "fire":"skill" },
"General": { "seats":"capacity" }
}
}}}

helix.domains is opt-in: a client that declares none keeps the free-form skills editor. Any skill referenced by a type (in coreSkills, initialSkills, exclusiveSkills, secondaryActivity.skills, or a stop option) that is not in the master list is flagged with a warning at domain-seed time — the seed still completes.

An entity’s addr object is the loc within the helix objects — its general location record. The schema is proprietary to the client, so nothing reads its fields directly: four domain-overridable doors expand it, each an expression resolved against the app-level helix.addr block:

{
"name": <string> | null,
"addr": <string> | null,
"at": <string> | null,
"tel": <string> | null,
"area": <string> | null,
}
name string
Expression for the SHORT NAME. Default helixAddrName() — the addr's `name` field.
addr string
Expression for the FULL ADDRESS. Default helixAddrText() — the non-empty of name, line1, line2, area, postcode, joined in that order.
at string
Expression for the COORDINATE. Default helixAddrAt() — the addr's `at` field ([lat,lng]).
tel string
Expression for the TELEPHONE. Default helixAddrTel() — the addr's `tel` field.
area string
Expression for the AREA summary. Default helixAddrArea() — the addr's `area` field. The addr subsumes the bare Location `area`: a location is `{at, addr}` and the area is pulled from the addr (the legacy `{at, area}` shape keeps working as a fallback until authoring migrates).

The default structure is { name, line1, line2, area, postcode, at, tel }. A client whose records differ (the AA pack authors {name, lines, area, code}) overrides the doors — author the block and implement the functions in the client extension (the SDK exports the defaults to compose with):

{"define": {"helix": {
"addr": { "name": "myAddrName()", "addr": "myAddrText()" }
}}}

Everything that displays an address resolves through these doors — hub names on the map and lists, the stop editor’s hub schedule row (the staged leg’s hid resolved to its hub record), and its hover/full address. addr itself is Helix-only: it is never sent to Spiral, which speaks ids and coordinates.

Configures the Contact-Centre contract search — the omni-search box operators use to find a contract or customer record and open or attach work to it.

{
"searchPaths": [string],
}
searchPaths string
Dot-paths into a contract record that the local search matches against (e.g. "fields.membershipNo", "fields.reg", "customer"). Drives the built-in /api/contract/search query.

The client may also supply a searchContracts(input) resolver (in its clientConfig) to merge results from an external system — CRM, telephony or ticketing — with the local matches. See Develop a client extension.