Occurrences Flow & GIS Automation
Designing the Flow
Building a system to handle emergency response and field logistics is always a high-stakes puzzle. In this deep dive, I want to show how we structured and optimized the Occurrences module of Saffira, our platform for real-time dispatch and disaster management.
The occurrence registration system already existed when I joined Aton. However, the experience was raw and sluggish. Operators were forced to navigate a single, massive form to log details while answering high-stress emergency calls.
My task was to overhaul the frontend data management and apply a brand-new UI/UX. I focused on breaking down that massive entry flow, structuring it into a dedicated occurrences menu where information is split and categorized. This allowed operators to fill in coordinates, affected resources, and team assignments at their own pace.
High-Level Architecture
We designed an event-driven system that bridges web applications, physical hardware gateways, and spatial database engines. Below is how the Angular client, Express backend, MongoDB cluster, and external systems (like Geoserver and ONVIF camera controllers) interface with each other.

Figure 1.1: Saffira Occurrences High-Level System Architecture map.
Figure 1.2: Interactive occurrence registration and automation flow simulation.
Technical Details
1. GIS Query & Spatial Logic
One of the biggest hurdles was discovering how client GIS departments structured their map layers. When auditing Suzano, Bracell, and UISA, we noticed they all named their map database columns differently. For example, a farm block was TALHAO for one client, UP for another, and Talhao for a third.
This mapping is necessary because we query WFS (Web Feature Service) spatial metadata at the clicked coordinate to link geographic shape data with the newly created occurrence. Since each client enforces their own unique nomenclature for map shapes, this translation layer standardizes the shape properties on the fly.
Our helper service, GeolocationHelperService, acts as this translation bridge:
| Target Property | Bracell Field | Suzano Field | UISA Field |
|---|---|---|---|
| nomePropriedade | PROJETO | Fazenda / fazenda | Nome_Faz |
| talhao | TALHAO | UP | Talhao |
| zona | ID_PROJETO | NUCLEO | Zona |
| areaEstimada | AREA_HA | AreaRotaca / Area | Área Tota |
2. Incident Creation & PTZ Automation
When an operator saves an occurrence, the frontend triggers a POST request. Instead of forcing the operator to wait for camera hardware and message dispatches to execute, the controller responds immediately (201 Created) and hands the background tasks to a worker job.
The background worker query checks for active ONVIF PTZ cameras within range, calculates the necessary pan/tilt/zoom angles, dispatches the camera motors, waits 4.5 seconds for hardware autofocus, takes snapshot frames, uploads them to MinIO, and alerts managers via Telegram with the snapshot attachment.
3. Dynamic Multi-Tenancy
We upgraded Saffira's backend multi-tenant architecture by introducing a new schema structure compiled dynamically at runtime, reducing connection pool exhaustion and code bloat:
4. Database Design: Thread-Safe Atomic Writes
To avoid database join overhead during critical incident response operations, we design a single consolidated Mongoose document schema. All related records crew, vehicles, telemetry, weather, and camera snaps are embedded inside nested document arrays.
Core metadata tracking the occurrence status, title, and initial dispatcher notes.
Because multiple dispatchers are active on the same incident, standard document saves would cause write race conditions. We bypass this by executing native atomic MongoDB operations ($push, $set, $pull):
5. Operational Cost Calculations Engine
Calculating combat expenses in real-time is a core operational requirement. We write custom analytical helpers that sum vehicle, personnel, and fuel variables into brigade aggregates:
6. Signals Caching & Cross-Tab Replication
To protect our servers from repeated requests during emergency events, the Angular client uses a memory caching dictionary. On write operations, we invalidate the cache.
To keep multiple browser tabs aligned without making backend database queries, we route events locally using the browser's native BroadcastChannel API.
| Title | Coordinates | Agg. Cost |
|---|---|---|
| Foco Inicial - Talhão 04 | [-22.312, -49.011] | R$ 4.250 |
| Incêndio Ativo - Faz. Santa Rita | [-22.325, -48.985] | R$ 12.800 |
Wrap up
Overhauling the occurrences flow wasn't just about speed; it was about the operator's state of mind. Standing in the shoes of a dispatcher answering high-stress emergency calls, I realized that every second spent navigating a convoluted form or waiting for physical camera feeds to load was a second of critical delay. Offloading heavy camera panning, MinIO uploads, and alert dispatches to detached background threads transformed a sluggish 45-second waiting cycle into an immediate, reassuring screen lock.
By bridging frontend Signals, BroadcastChannel sync, and atomic MongoDB operations, we got rid of the developer's constant worry over data drift and connection limits. More importantly, we built operational trust. Automated real-time billing calculations replaced error-prone spreadsheets, and immediate Telegram notifications with attached camera snaps kept the entire field team in lockstep. Ultimately, the biggest win wasn't just a 99.8% cache hit rate; it was giving emergency operators the quiet focus they needed to coordinate when every second mattered.