Skip to content
Z3tra
All projects
In development2026 — present
Batelys logo

Batelys

Lone worker safety, one button at a time

Batelys protects people who work alone. You check in when you arrive, then press a button now and then to confirm you are fine. Miss a check-in — because you fell, collapsed, or simply cannot reach your phone — and an alert leaves on its own, with your position, escalating through your chain until someone responds.

My role
Solo — product, architecture and development
Built with
  • TypeScript
  • Next.js
  • React
  • Node.js
  • PostgreSQL
  • REST API
  • Docker

Vision

Why this exists

A builder on a site, a technician in a plant room, a night-shift caretaker. They work alone, and when something goes wrong the problem is not that nobody cares — it is that nobody knows yet. The gap between an accident and someone noticing is the whole thing.

Batelys closes that gap with one mechanism: a dead man's switch. Check in at the start of the shift, confirm you are fine at intervals, and if a confirmation does not arrive, the system assumes the worst and acts. There is also a panic button for when you know something is wrong and want help now.

Everything else — the dashboards, the exports, the reporting, the roster management — is packaging around that single idea. I keep coming back to that when scoping features, because a safety product that becomes complicated is a safety product people stop using correctly.

Objectives

What it has to get right

Constraints stated up front, so the design decisions further down have something to be measured against.

01

Detect silence, not just emergencies

The people most at risk are the ones who cannot call for help. A missed check-in has to be as loud as a pressed button.

02

Escalate until someone answers

One notification to one supervisor is not a safety system. It has to climb the chain and end in a phone call.

03

Work on bad networks and old phones

The environments where this matters have concrete walls, no signal and a five-year-old Android. That is the target, not the edge case.

04

Collect the minimum

Continuous location tracking of employees is surveillance. Position is captured when an alert fires — not all day.

Interface

What it looks like

/projects/batelys/worker.png

The worker app — one button, one job.

/projects/batelys/incident.png

Incident timeline: every escalation step, recorded.

/projects/batelys/dashboard.png

Supervisor console — who is on shift and who is overdue.

Features

What it does

Shift check-in

Open the app, confirm presence, and the monitoring window starts. Clocking out ends it — no forgotten sessions raising false alarms at 2am.

Periodic confirmation

A single 'I'm fine' button at a configurable interval, with a grace period and a loud local reminder before anything escalates.

Automatic alert on silence

When the grace period expires the alert fires on its own, carrying the last known position and the time of the last confirmation.

Panic button

Immediate manual alert, no confirmation dialogue, reachable without unlocking into a menu.

Escalation chain

Supervisor first. No acknowledgement inside the window, and it moves to the next contact, then triggers an automated voice call.

Supervisor dashboard

Who is on shift, who is due to check in, and the full timeline of any incident — for the response, and afterwards for the report.

Architecture

How it is put together

This is the only project I have built where the failure mode is a person on the floor and nobody knowing. That reframes everything: availability is a safety property, an alert path is not allowed a single point of failure, and 'it retried and eventually worked' is not good enough if 'eventually' is twenty minutes.

01

Worker app

Deliberately small surface: check in, confirm, panic. Queues events locally when offline and replays them on reconnect, and warns the worker locally before a missed confirmation escalates.

  • React
  • PWA
  • Background sync
02

Monitoring service

Holds a deadline per active shift and reacts when one passes. Deadlines are persisted, not held in a process — a restart must never silently drop someone's timer.

  • Node.js
  • Job scheduling
  • PostgreSQL
03

Escalation engine

A state machine per incident: notify, wait for acknowledgement, escalate, repeat, then place an automated call. Every transition is recorded so an incident can be reconstructed exactly.

  • State machine
  • Push
  • SMS
  • Voice API
04

Supervisor console

Live shift status, incident timelines and exports. Read-heavy and cacheable, and intentionally separate from the alert path so a dashboard outage cannot affect alerting.

  • Next.js
  • TypeScript
  • REST API

Decisions worth defending

Deadlines live in the database, not in memory

The naive version keeps timers in the process. Then the process restarts during a deploy and everyone's monitoring window quietly disappears. Persisted deadlines mean any instance can pick up an overdue check-in.

Alerting and dashboards are separate paths

The console is where features accumulate and regressions get introduced. It must not be able to take alerting down with it.

The client fails towards raising an alert

Ambiguity resolves in favour of alerting. A false alarm costs someone a phone call; a missed alarm costs considerably more.

Location on alert only

Continuous tracking would be simpler to build and much harder to justify. Capturing position when an incident fires gives responders what they need without turning the app into a tracker.

Every escalation step is an audit record

After an incident, the question is always 'who was told, when, and did they respond'. That answer has to come from stored events, not from log grepping.

Challenges

The parts that were actually hard

Problem, what I did about it, and where that landed. Including the ones still open.

Problem

A missed check-in and a phone with no signal look identical from the server's point of view.

Approach

Distinguishing them on the client. The app knows it is offline, warns the worker loudly and locally, and queues the confirmation. The server treats prolonged silence as an incident regardless — but the timeline records which of the two it was.

Outcome

Fewer false alarms from dead zones, without ever using 'probably just bad signal' as a reason not to escalate.

Problem

Mobile operating systems aggressively suspend background apps, which is precisely what a dead man's switch cannot tolerate.

Approach

Moving the authority for the deadline to the server and using the client only to confirm. If the client is killed, the server still knows a confirmation is overdue.

Outcome

Escalation does not depend on the app staying alive — the exact scenario where the worker is unable to interact with it.

Problem

Notification delivery is best-effort. A safety system cannot be best-effort.

Approach

Layered channels with explicit acknowledgement: push, then SMS, then an automated voice call, each requiring a positive response before the chain stops.

Outcome

No single provider outage silences an alert, and 'nobody acknowledged' is itself an event that escalates.

Problem

Alert fatigue quietly kills these systems. Too many false positives and people stop responding.

Approach

Generous grace periods, an unmistakable local reminder before escalation, and one-tap cancellation with a reason — feeding back into interval tuning.

Outcome

Alerts that fire stay credible, which is what makes the escalation chain work at all.

Learned

What it taught me

Availability stops being a performance metric and becomes a safety requirement. It changes how you deploy, how you monitor, and what you are willing to ship on a Friday.

Anything holding a deadline in process memory is a bug waiting for a restart.

Regulation around lone worker protection and around employee geolocation pull in opposite directions, and the resolution is designing for data minimisation from the start rather than bolting on consent later.

Writing down what happens when each dependency fails — network, push provider, SMS gateway, the app itself — surfaced more design problems than any amount of feature planning.

For a product like this, the highest-value engineering is in the boring reliability work nobody sees.

Roadmap

Where it goes next

Shipped, in progress and planned — kept honest about which is which.

2026 H1In progress

Core safety loop

  • Shift check-in and periodic confirmation
  • Server-side deadlines with persistence
  • Panic button
  • Push and SMS escalation with acknowledgement
2026 H2Planned

Response and reporting

  • Automated voice call as final escalation step
  • Supervisor console with live shift status
  • Full incident timelines and exports
  • Configurable intervals and escalation chains per team
2027Planned

Field readiness

  • Offline-first hardening across the worker app
  • Fall detection using device sensors
  • Data retention and access controls aligned with GDPR
  • Independent review of the alert path

Next

Other projects