Skip to content

Alerts: how Korido decides something matters and tells someone

What this chapter covers

Korido watches every truck continuously, but attention is scarce. This chapter is about the machinery that turns a raw observation — a speed reading, an immobilizer flip, a fuel-level drop — into a decision: is this worth a person's attention, and if so, whose, and through which channel? It describes the event catalog that declares those decisions once and for all, the deduplication that keeps a persisting condition from becoming a storm, the delivery pipeline that carries an alert to the dashboard and WhatsApp, stores phone push eligibility, and the security detectors that watch for fuel loss, tracker interference, and tamper signals. It closes with how an operator acknowledges and resolves what they have been told.

The picture

Every alert Korido can raise is one row in a single registry. That row says everything about how the alert behaves — how loud it is, who cares, and how it travels:

The registry is the spine of the whole system. Adding a new kind of alert is a single registry row plus one detector rule — never a scattered edit across the dashboard, the push-eligibility code, and the WhatsApp renderer, because all three read their behavior from this one place.

The event catalog

Korido recognises a fixed set of event types — refuelling, drain suspicion, low battery, excessive idle, towing, a Route Guard deviation, an unauthorised stop, a mission milestone, a tracker anomaly, a vehicle going offline, and several dozen more. Each one has exactly one entry in the catalog, and that entry declares six facts:

  • Severity — one of info, warning, or critical. Severity is the human weight of the event: info is a fact worth recording, warning asks someone to look, and critical demands action now.
  • Category — one of mission, route_guard, fuel, documents, or system. The category groups alerts for the person receiving them and, on a phone, decides the notification channel and its loudness.
  • Delivery mode — one of immediate, digest, none, or suppressed. This is the default urgency of delivery: send it now, roll it into an hourly summary, record it silently, or hold it back entirely.
  • Channels — four independent switches: WhatsApp, the in-app dashboard, the customer tracking portal, and the driver's push eligibility. An alert can light up any combination.
  • Dedup scheme — which rule collapses repeats of this type into a single alert (the next section).
  • Copy key — which French message template renders it for WhatsApp.

Because every type must declare a complete row, there are no half-defined alerts: a new event type cannot ship until its severity, delivery, and routing are all decided. A few representative rows show how the catalog encodes intent:

Event typeSeverityModeChannels
towing_detectedcriticalimmediateWhatsApp · dashboard · driver push eligibility
fuel_drain_anomalycriticalimmediateWhatsApp · dashboard
off_station_refuelingwarningimmediateWhatsApp · dashboard
speedingwarningdigestWhatsApp · dashboard
low_batteryinfosuppresseddashboard
waypoint_arrivalinfononedashboard · portal

Current rollout

Notification rows, channel decisions, and push due-times are current behavior. Outbound Expo push is currently gated off by worker configuration, so mobile apps surface notifications from their in-app centers until the push rollout is enabled.

A tenant can override the delivery mode and channels for any type — a fleet that does not want speeding in its WhatsApp digest turns that channel off — but the catalog is the default every tenant starts from.

Deduplication: one alert for one condition

A truck sitting in a customs queue with a low tank does not need a fresh "low fuel" alert every time its tracker reports. A persisting condition must raise one alert, not a storm. Korido enforces this with an active-alert model: while an alert is open, a repeat of the same condition finds the existing row and updates it.

Two dedup mechanisms cover the two shapes an alert can take:

  • Per-vehicle active slot. For condition-style alerts (towing, an SOS line, a standalone tamper) there is one open slot per (tenant, vehicle, event type). The first firing opens it; every repeat while it is open is absorbed. When the condition clears and the alert is resolved, the slot frees for the next occurrence.
  • Idempotency key. For event-style alerts the row carries a natural key so retries and re-scans converge on the same row. The key is shaped per type: once per vehicle, once per trip / stop / gap / visit, once per mission, once per deviation, or once per vehicle per local calendar day. Parked low_fuel and low_battery use the daily bucket — a truck parked in a dead zone reporting a low tank every cycle still produces exactly one alert per day.

The active slot is deliberately per vehicle, not per mission, so two back-to-back missions share it. When a mission completes or cancels, any of its still-open, mission-scoped alerts are auto-resolved in the same step that closes the mission, freeing the slot for the next mission's alerts.

The delivery pipeline

When an event row is written, its delivery is resolved once, at that moment — the effective mode, the channel routing, and the moment it becomes eligible for driver push are all computed and stored on the row. Downstream schedules then filter by those stored fields in the database. This is what keeps the pipeline cheap and predictable: a digest-mode alert is structurally invisible to the immediate-dispatch schedule, and a suppressed alert is invisible to every channel.

Three behaviours in that pipeline are worth stating as rules:

  • The anti-flap window. A warning-severity alert that opens is held for 5 minutes before it is sent. If the condition clears inside that window, the alert is quietly suppressed and never reaches a person — this is what stops a flickering signal from paging an operator. critical alerts skip the window and send at once, and info facts that are closed the instant they are recorded either deliver immediately or not at all.
  • Quiet hours. Driver push eligibility respects a per-user quiet-hours window, off by default and typically set to 22:00–06:00. A push in the route_guard category is treated as time-sensitive: it is exempt from quiet hours and, once outbound push is enabled, can surface through the phone's focus modes. Every other category is a normal notification that stays silent during quiet hours.
  • Digests. The hourly digest gathers every digest-mode alert for a tenant into one French summary per verified owner. It shows up to 10 lines and collapses the rest into a "… et N autres alertes" tail, so a busy hour is one readable message, not fifty.

The security detectors, in product terms

A cluster of detectors exists specifically to catch high-risk interference on the corridor. They read signals the tracker reports whether or not it currently has a GPS fix — a truck can be parked in a dead zone and still have its alarm line, immobilizer, and defense state read every cycle.

  • SOS — the driver's hardware alarm line. The tracker carries a wired alarm line (the panic button and other hardware alarms). Any non-zero alarm code raises driver_alarm_violationcritical, immediate, to WhatsApp, the dashboard, and the driver's phone. Because no authoritative table maps every code to a meaning, any non-zero code fires: a mislabelled alarm is better than a silent panic button. The raw code travels with the alert for triage.
  • Immobilizer state change. When the engine immobilizer flips — remotely blocked or unblocked — Korido compares it against the last positively known state and raises engine_block_changed. A vehicle's very first reading establishes the baseline state, so it never fires spuriously. Each real flip is its own record, so a block and an unblock minutes apart are two distinct events.
  • Main-power disconnection. The tracker reports the voltage of the vehicle power source it is wired to. When that voltage drops from clearly present (6 V or more) to cut (1 V or less) while the tracker keeps transmitting on its own internal battery, the vehicle harness has likely been cut or disconnected — a high-risk tracker-interference pattern — and Korido raises power_disconnection: critical, immediate, to WhatsApp and the dashboard. The 1–6 V dead-band between "present" and "cut" means a noisy mid-range reading can never manufacture a disconnection. A tracker that never reports an external-voltage line simply never fires this detector, and the alert auto-resolves the moment external power comes back.
  • Tamper while parked. Two signals mean someone is physically at a stationary truck: the factory defense state dropping (disarmed without the engine starting) and a vibration alarm while parked with no trip open. Either raises tamper_detectedcritical, immediate — with a reason of defense_deactivated or vibration_while_parked. These fire only outside a signal gap: the same signals seen inside a gap are evidence the gap-classification path already uses to decide the gap was a tampering event, and surface there as a tracker anomaly instead, so the physical signal is never counted twice.
  • Towing. A truck moving faster than the towing threshold with its ignition off is being towed. This raises towing_detectedcritical, immediate, to WhatsApp, the dashboard, and the driver's phone.
  • GPS-jamming suspicion. A signature interference pattern is to jam GNSS while the tracker keeps transmitting: the heartbeat stays fresh, but no new position arrives. Korido reads this as a gap of the "GPS denied while alive" kind and raises gps_jamming_suspected — a warning, immediate — keyed to the gap so one jamming window yields one alert. It auto-resolves the moment real fixes resume.

Acknowledgment and resolution

An alert has a lifecycle, and which part of it a person touches depends on how the event was born. A warning or critical opens for someone to work: it moves openinvestigatingaction_takenresolved, and acknowledging it stamps who did so and when. An info fact is different — it exists purely as a timeline record, so it is born closed, already in its terminal state the instant it is written: a waypoint arrival or a completed refuel documents itself, so it enters the log finished. And many events resolve on their own — reality contradicts them and they close themselves as auto_resolved, or a safety net retires a forgotten one as expired.

Many alerts resolve themselves the moment reality contradicts them:

  • device_offline auto-resolves on the first telemetry row of any kind — a status-only frame is proof the tracker is back, matching the same clock the alert was opened from.
  • low_fuel_driving auto-resolves when the tank rises back above the threshold.
  • gps_jamming_suspected auto-resolves when fixes return.
  • power_disconnection auto-resolves when external power returns — a positively-known present reading is required, so a tracker that simply stops reporting voltage never clears a real disconnect.
  • tracker_anomaly — the tampering signature Korido reads when a signal gap closes on a hostile blackout — auto-resolves as that gap ends. The tampering window is already over by the time the alert is raised, so the alert delivers its critical warning and clears itself on the same beat rather than sitting open, which keeps the vehicle's active slot free for the next gap.
  • Mission-scoped alerts auto-resolve when their mission reaches a terminal state.

The engine can emit an open alert and an auto-resolve for a different condition in the same telemetry batch, so a truck's story stays current without an operator having to close stale rows by hand. What remains for the operator is the judgment work: looking at an open warning or critical, marking it under investigation, and resolving it once handled.

Edge cases

  • A flickering condition. A signal that toggles faster than the 5-minute anti-flap window never pages anyone: the alert opens, the condition clears, and it is suppressed before dispatch. Only conditions that persist past the window reach a person.
  • A parked truck in a dead zone. Low fuel or low battery on a truck that reports only by status frame still fires — the fuel and battery detectors read the full telemetry feed, not just GPS fixes — but the daily-bucket key collapses every cycle into exactly one alert per day.
  • Back-to-back missions. Because the active dedup slot is per vehicle, a mission-scoped alert left open at mission end would block the next mission's alert. The terminal mission transition auto-resolves it, freeing the slot.
  • The WhatsApp channel is off. Turning off WhatsApp delivery never starves the driver's in-app notification or push eligibility: the phone path keys on its own stored due-time, entirely decoupled from the WhatsApp dispatch lifecycle.
  • An unknown event type at the boundary. A type that does not match the catalog resolves to fully suppressed with no channels — an unrecognised alert can never leak to a person.
  • A block and an unblock in one window. Immobilizer transitions are recorded as distinct, closed facts rather than a single open condition, so a block and its unblock minutes apart both survive instead of contending for one slot.

Known limitations

  • A detector can only fire on a signal the device actually sends. The security detectors read fields the tracker reports — an alarm line, an immobilizer state, an external-voltage reading, a vibration flag. A device family that does not wire one of these cannot raise the alert that depends on it: a tracker with no external-voltage line never raises a power-disconnection, and one with no vibration sensor never raises a vibration tamper. Absence of a signal is treated as unknown, never as a negative reading, so a missing sensor stays silent rather than falsely reassuring.
  • Hardware alarm codes carry no authoritative meaning. Because no per-family table maps every alarm code to a specific cause, any non-zero code raises the same driver_alarm_violation and the raw code rides along for a person to interpret. This is deliberate — a mislabelled alarm is better than a silent panic button — but it does mean the alert names that an alarm fired, not precisely which one.

What's ahead

The event model already reserves a documents category — a driver can be prompted to re-submit a document today — but no fleet alert type is wired to it yet. The next step is document-lifecycle alerting: a truck about to run on an expired insurance paper, a permit lapsing before a border crossing, raised on exactly the same catalog machinery every other alert already rides, so a new documents alert is one registry row plus one detector rule rather than a new subsystem.

How it connects