Skip to content
Abelardo Carlos
← Projects

Brigada Málaga · FireFighter

Something is burning in Málaga. Who goes?

A call comes in. The dispatcher places it on the map, sees which crews are closest, assigns one and talks to it directly, browser to browser, while every decision is written to an audit trail.

Coordination app first built in 2017–2018, rebuilt with AbeFlow in 2026. Local training version with fictional data; not an approved emergency service, and not the fire brigade’s official emblem.

Brigada Málaga in two minutes: from “calls on top of calls” to one map and one channel.1:54

01

Central

Priority queue, hazards, elapsed time, crews assigned, map and crew board.

02

Mi equipo

Confirm or reject, leave, arrive, share position, finish. Big buttons.

03

Comunicaciones

Text, quick messages and voice notes, peer to peer, with receipts.

04

Registro

Every operational change, searchable and exportable to JSON.

The app

Six screens, one incident

A replica of the real V2 console with the training scenario: follow a house fire from the first call to the audit log. It plays by itself; use the arrows to move between screens.

127.0.0.1:4318 · Brigada Málaga

Coordinación en tiempo real

Central de operaciones.

ENTRENAMIENTO Servidor conectadoPerfil · Central · coordinación
1

Intervenciones activas

00

Avisos abiertos

Equipos disponibles

05

5 equipos en el espacio

En intervención

00

En camino o en el lugar

Confirmaciones pendientes

00

Respuesta de los equipos

Mapa de operaciones Málaga, EspañaCentrar mapa
2CentroLa TrinidadEl PerchelSohoMartiricosLa MalaguetaGibralfaroHuelinPuertoTeatinosMar MediterráneoB-01B-02E-01R-01B-03
● Intervención▭ Equipo┅ Posición antigua
3
Intervenciones 0

Architecture

One small server, many screens

The same Node.js process serves the frontend, the HTTP API and WebRTC signalling. Every operational command goes through the domain core and SQLite; chat goes browser to browser. It installs with npm ci and runs with no database server, no map key and no Docker.

Why one process?

Centraldispatch · browser tabMi equipocrew tablet · browserAdministraciónunits · audit logONE NODE.JS PROCESS · 127.0.0.1:4318Static frontendES modules · CSS · LeafletHTTP APIlimits · headers · routesEmergencyCorerules · roles · idempotency · auditSQLiteWAL · BEGIN IMMEDIATE · FULL syncSignallingpresence · SDP/ICE mailboxesWebRTC P2POpenStreetMapmap tiles onlyPollingstate 3 s · signals 1 sGrey: HTTP through the server · Orange: direct between browsers

Map & location

Where is everyone, and how sure are we?

Leaflet draws OpenStreetMap tiles; crews share their GPS position from the browser. Distances are straight lines from the last known position, and every position carries its age. Click the map to move the fire.

How are distances and positions handled?

Click anywhere on the map to move the incident

CentroLa TrinidadEl PerchelSohoMartiricosLa MalaguetaGibralfaroHuelinPuertoTeatinosMar Mediterráneo469 m1.0 km1.5 km2.6 km2.9 kmB-01B-02E-01R-01B-03

Closest first

  1. 1. B-02469 m
  2. 2. B-011.0 km
  3. 3. E-011.5 km
  4. 4. B-032.6 km
  5. 5. R-012.9 km

Great-circle distance from the last recorded position: a straight line, not a route or an ETA.

How old is B-03’s position?

20 s agoReciente

Positions are never refreshed artificially: under 30 s recent, under 2 min aging, then stale.

Could B-01 really be at La Malagueta?

The server rejects a jump longer than GPS accuracy + 100 m + 300 km/h × elapsed time.

Direct communication

Talking without the server in the middle

Browsers cannot find each other on their own. WebRTC needs a short introduction, called signalling: the server passes notes between them until they agree on a connection. After that, messages go straight from one browser to the other.

How can two browsers talk directly?

CentralServerB-02POST /v1/peers → {peerId, token}

Step 1 · through the server (HTTP)

Join

Each tab asks the server for an ephemeral session on this incident. Only the dispatcher and assigned crews are allowed in.

What the server sees

Who is present, and the negotiation (SDP offers and answers, ICE candidates), in expiring in-memory mailboxes.

What it never sees

The messages and voice notes. The chat is temporary; orders and assignments still go through the server and the audit log.

TransportWhat it isUsed forTrade-off
HTTP requestclient asks, server answersOrders, state, and here also signalling, polled every 1–3 severy command is validated and logged
WebSocketone open two-way pipe to the serverSignalling and positions in the 2017 prototypestill through the server
WebRTC data channela direct, encrypted pipe between two browsersText, quick messages and voice notes in V2no server in the middle; needs signalling to start

Limits, stated in the project: no STUN/TURN yet, so it is tested between browsers on the same machine; identities are declared by the client, so it is not audited end-to-end encrypted messaging; voice notes are up to 20 s and 1 MB, text up to 4,000 characters, always rendered as text. The emergency radio remains the official channel.

2017 → 2026

Same idea, rebuilt

The first version was a freelance prototype. The new one keeps the old code as history and moves every rule into a core that can be tested, audited and eventually scaled.

2017 prototype2026 V2
FrontendAngularJS 1 · BowerNative ES modules · responsive CSS · dark theme, day mode
ServerNode.js · LoopBack 3One Node.js 24 process, no framework
DataMongoDBSQLite (node:sqlite), WAL, one transaction per command
MapGoogle MapsLeaflet 1.9.4 served locally · OpenStreetMap tiles, attributed
SignallingWebSocket serverHTTP mailboxes polled every second
Chat & voiceWebRTC data channelsWebRTC data channels with receipts, size limits, backpressure
RulesIn the UIDomain core: roles, transitions, idempotency, audit
Tests—Unit tests + Playwright end to end, including real WebRTC