GuardCore · Control room
A control room screen for the shift actually in progress
Unresolved duress at the top, who is on duty from the roster, the open incidents, the patrols under way — and dispatch orders that move through six states, each stamping its own time.
The problem this solves
A control room does not need a dashboard. It needs one screen that is correct, ordered by what will hurt you first, and that changes without being reloaded.
So the command centre puts unresolved duress above everything else, always, with the recording and the list of who was notified attached. Below it: guards with their duty state derived from the roster rather than from a field somebody remembered to set, the open incidents, the patrols in progress, and a summary counted in SQL rather than in the browser.
Dispatch is a lifecycle, not a status field. Pending, dispatched, acknowledged, en route, arrived, completed — each transition stamps its own column, each impossible transition is refused by name, and the list of guards available to take an order excludes anyone already on a live one. Order numbers are sequential per organisation per year.
Behind all of it, Signals watches the event stream the product already writes. Every domain write lands in an event outbox, and until Signals the only thing reading it was outbound webhooks. A signal rule names an event and a set of conditions, and raises a reviewable item that is dismissed or turned into an incident. The conditions are deterministic predicates, not a classifier — there is no confidence score here, because there is nothing to be uncertain about.
Worked example
22:14. A guard raises duress, and two minutes later an alarm needs a mobile response.
- 1
The duress reaches the top of the screen
With the fix, the recording and who was notified — above the incidents, above the patrols, above everything, by construction rather than by sort order.
- 2
It re-sends until acknowledged
The critical notification requires acknowledgement and repeats every five minutes, each re-send its own transaction under a row lock and its own audit event.
- 3
A dispatch order is raised
From the guards genuinely free to take one — anybody already on a live order is excluded by the query, not by the operator remembering.
- 4
The order walks its states
Acknowledged, en route, arrived, completed, each with its own timestamp, so the response time is measured rather than estimated afterwards.
Two overlapping events, both with a defensible timeline, and neither reconstructed from memory at the end of the shift.
Capabilities
What control room gives you
All 6 of these are in the product today. Each one names what it is built on.
One screen for the shift in progress
LiveUnresolved duress first, then who is on duty from the roster, the open incidents, the patrols under way and a counted summary — refreshed on its own rather than when somebody remembers to reload.
Dispatch with a lifecycle, not a status field
LivePending, dispatched, acknowledged, en route, arrived, completed — each transition stamping its own time, each refusal named, and order numbers sequential per organisation per year. The available-guards list excludes anyone already on a live order.
Live map
LiveOn-duty guards on a map, with the latest fix per guard inside a fifteen-minute freshness window, and an on-duty list beside it that works when the map cannot.
Signals: a rule over every write
LiveEvery domain write already lands in an event outbox; a signal rule watches it for a named event and a set of conditions, and raises a reviewable item — dismissed, or turned into an incident, by hand or automatically.
Pass-down the next shift can read
LiveHandovers, occurrences, visitors, alarms, maintenance and instructions entered by the guard on the phone, and compiled into the shift’s Daily Activity Report rather than left in a notebook at the desk.
Outbound webhooks that retry properly
LiveFive attempts on a one, five, thirty, one-hundred-and-twenty, seven-hundred-and-twenty minute ladder, signed, then dead-lettered — with private addresses and the cloud metadata endpoint refused on every attempt, not only the first.
What backs these claims
Each capability names the decision record, module, route or table it is built on. Ask us for any of them in an evaluation and we will walk you through the code.
- One screen for the shift in progress
- GET /api/imss/command-centre · /imss/command-centre · OpsCommandCentre.tsx
- Dispatch with a lifecycle, not a status field
- src/server/imss-dispatch.ts refuseAction nextOrderNumber · POST /api/imss/dispatch · imss_dispatch_orders · /imss/dispatch
- Live map
- ADR 0022 · src/pages/imss/ops/OpsLiveMap.tsx · GET /api/imss/guard-locations/live · /imss/map
- Signals: a rule over every write
- ADR 0031 · src/server/imss-signals.ts matchesConditions convertToIncident · POST /api/imss/signal-rules · imss_signals · /imss/signals
- Pass-down the next shift can read
- src/server/imss-passdown.ts PASSDOWN_ENTRY_TYPES · src/server/imss-dar.ts · imss_passdown_entries
- Outbound webhooks that retry properly
- src/server/imss-automation.ts RETRY_LADDER_MINUTES · src/server/imss-jobs/deliveries.ts · imss_deliveries
Where this sits
Back to
GuardCore — every capability in one place
The whole module: what is live, and what is only on the roadmap.
Read next
Lone worker safety for the guard on their own at 3am
A welfare interval that escalates when it lapses, a duress alarm that records and keeps re-sending until someone acknowledges it, and five escalation levels that advance themselves.
Twenty minutes on a real contract.
Real data, four logins, nothing typed on the day — including the parts we have not built, which we will point out ourselves.