Skip to content
Darmawan Zulkifli

Aptus Aware

Clinical communications for care teams — moving nurse call, presence and escalation off the wall panel and onto the handsets staff already carry.

The problem

A nurse call used to be a fixed panel wired into a building, answered by whoever was standing near it. Putting it on staff phones changes who can answer and from where — but only if the alert still reaches the right person as reliably as the panel did.

What I owned

  • Product direction — what Aptus Aware should be, not only how it gets built
  • The Matrix.org proof of concept, then the review and migration of backend code onto it
  • Location-aware presence, hunt-group routing and nurse-call configuration
  • The in-flight integration with Aptus Concierge, including its AI layer
  • Release hygiene end to end — version control, testing to standard, releases, issue tracking
Role
Product Champion · Engineer
Period
2024—
Status
live
Sector
Healthcare

Aptus Aware puts clinical communication on the devices care staff already carry. Nurse calls, presence and escalation stop being a fixed panel on a wall and become something that follows the right person.

The problem

A nurse call used to be a fixed panel wired into a building, answered by whoever was standing near it. That works until the person who should answer is two corridors away, or is the only one on shift who can deal with what the call is about.

Putting the call on the phone someone is already carrying changes who can answer and from where. That is the whole idea. The difficulty is that it turns into a delivery guarantee — and the phones are the least reliable part of the system.

Why it mattered

The thing that goes wrong is not a dropped message. It is a call nobody answered, in a building where somebody needed help. If a normal chat app loses a message, it is annoying. Here it has a clinical consequence, so the usual “good enough” assumptions about delivery do not hold.

Constraints

There are two kinds of device, not one. Some staff use a handset the organisation owns and manages. Others use their own phone. A managed handset is shared across shifts, so what matters is who is on duty, not which phone it is — the same physical device is three different people over a day. A personal phone is the opposite problem: we do not know the OS version, the network it is on, or whether it will let a notification through after the screen has been off for an hour. Both have to reach the right person just as reliably.

The phone’s operating system works against us here. Background limits, doze modes and notification throttling are sensible defaults for a normal phone and wrong for a clinical alert. We cannot turn them off, so we design assuming they will happen.

Records have to last beyond the shift. Who said what, to whom, and when — long after everyone involved has gone home.

The data is clinical. It cannot sit on someone else’s servers, which rules out most of the obvious off-the-shelf messaging options before we even compare them.

Architecture: why Matrix

The most interesting piece has been a proof of concept moving the messaging backend onto Matrix, the open federated messaging protocol, and then reviewing and migrating backend code onto it.

Clinical messaging needs things normal chat does not, and Matrix covers three of them directly. It has a real event graph, so history is recorded rather than pieced back together. It federates, so separate organisations can talk to each other without one of them owning the hub. And we can host it ourselves, so clinical data stays where the customer needs it.

Working this close to the protocol means the client library is not something you just accept as-is. I maintain a fork of the Matrix Dart SDK that adds compatibility the original does not cover, and the Flutter app sits on top of it.

flowchart TB
  subgraph Devices
    M[Managed handset<br/>shared across shifts]
    P[Personal phone<br/>unmanaged OS and network]
  end
  M --> C[Aptus Aware client<br/>Flutter]
  P --> C
  C <--> H[Matrix homeserver<br/>self-hosted, event graph]
  C <--> S[Backend services<br/>Node.js]
  S --> R[Presence and routing<br/>hunt groups, nurse call]
  R --> H
  S <--> K[Aptus Concierge<br/>including AI layer]
  N[Nurse call source] --> S

Presence, which looks simple and is not

Presence looks simple and is not. Automatic presence means the system works out who is available from where they are, instead of asking people to set a status. A status someone has to update by hand is wrong within an hour or two of the shift starting — and if routing trusts it, a clinical call goes to someone who has already left the building.

So we work presence out from the system rather than asking for it. Hunt-group routing then rings an ordered list of people one at a time until somebody picks up, instead of alerting everyone at once and hoping.

sequenceDiagram
  participant Call as Nurse call
  participant Route as Routing service
  participant Pres as Derived presence
  participant A as On duty, nearest
  participant B as Next in hunt group
  Call->>Route: raise
  Route->>Pres: who is actually available, and where
  Pres-->>Route: ordered candidates
  Route->>A: ring
  A--xRoute: no answer within window
  Route->>B: escalate
  B-->>Route: answered
  Route->>Call: attributed to B

Trade-offs

  • Hosting it ourselves instead of paying a vendor. Running our own server is real operational work a hosted service would have handled. We take that on because it is the only way to keep clinical data where the customer needs it.
  • Working presence out instead of asking for it. This is more code and it can be wrong in its own ways. But presence people set by hand is wrong more often, and wrong in the direction that sends calls to the wrong person.
  • Ringing people in order instead of alerting everyone. Alerting everyone is faster on average, but nobody is clearly responsible — each person assumes someone else took it. Going down a list is slower at best, and at every step there is one person who owns the call.

Failure handling

Escalation is the failure handling. A call that is not answered within the time window is not a lost call — it is the trigger for the next routing step. The same thinking applies to the phones: we assume a notification may not arrive on a personal device, so what we trust is the answer coming back, not the delivery going out.

Current work

Right now I am integrating Aptus Aware with Aptus Concierge, including its AI layer, so staff do not have to keep two separate systems in their head.

Result