Spaces:
Paused
Paused
project readme
Browse files
README.md
CHANGED
|
@@ -1,10 +1,97 @@
|
|
| 1 |
---
|
| 2 |
title: Dispatch Console
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom: yellow
|
| 5 |
-
colorTo: indigo
|
| 6 |
sdk: docker
|
|
|
|
| 7 |
pinned: false
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
title: Dispatch Console
|
| 3 |
+
emoji: ๐บ๏ธ
|
|
|
|
|
|
|
| 4 |
sdk: docker
|
| 5 |
+
app_port: 8080
|
| 6 |
pinned: false
|
| 7 |
---
|
| 8 |
|
| 9 |
+
# Dispatch Console (PoC-style, self-hosted)
|
| 10 |
+
|
| 11 |
+
A production-ready, self-hosted alternative to hosted PoC dispatch consoles:
|
| 12 |
+
live member map, GPS tracking, SOS alert workflow, push-to-talk intercom with
|
| 13 |
+
server-enforced floor control, and member/talkgroup management.
|
| 14 |
+
|
| 15 |
+
## Stack
|
| 16 |
+
|
| 17 |
+
- **Backend** โ Node.js, Express (REST API), `ws` (WebSocket: GPS, SOS, PTT signaling, audio relay), SQLite (`better-sqlite3`), JWT auth
|
| 18 |
+
- **Frontend** โ React 18 + Vite, Leaflet (OpenStreetMap), AudioWorklet capture / WebAudio playback
|
| 19 |
+
- **Deploy** โ Docker / docker-compose; also runnable directly and on HF Spaces (this repo)
|
| 20 |
+
|
| 21 |
+
## Quickstart (local, no Docker)
|
| 22 |
+
|
| 23 |
+
```bash
|
| 24 |
+
# 1. backend
|
| 25 |
+
cd server
|
| 26 |
+
npm install
|
| 27 |
+
npm start # listens on :8080
|
| 28 |
+
|
| 29 |
+
# 2. frontend (dev server with proxy)
|
| 30 |
+
cd ../web
|
| 31 |
+
npm install
|
| 32 |
+
npm run dev # http://localhost:5173
|
| 33 |
+
|
| 34 |
+
# 3. simulated fleet (separate terminal)
|
| 35 |
+
cd ../server
|
| 36 |
+
npm run sim # 5 units: GPS every 5 s, SOS at 25 s, PTT turns
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
Default dispatcher: **admin / admin** (override with `ADMIN_PASSWORD` on first run; change it after first login).
|
| 40 |
+
|
| 41 |
+
## Quickstart (Docker)
|
| 42 |
+
|
| 43 |
+
```bash
|
| 44 |
+
docker compose up --build -d # http://localhost:8080
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
Data (SQLite + JWT secret) persists in `./data`.
|
| 48 |
+
|
| 49 |
+
## Architecture
|
| 50 |
+
|
| 51 |
+
```
|
| 52 |
+
web (React+Vite) โโHTTP /api/*โโ> Express โโ> SQLite (better-sqlite3)
|
| 53 |
+
| |
|
| 54 |
+
+--WebSocket /ws (JSON + PCM) --> Hub (realtime.js)
|
| 55 |
+
|- GPS ingestion -> members + gps_pings
|
| 56 |
+
|- SOS alerts -> broadcast + REST ack/resolve
|
| 57 |
+
+- PTT floor control + 16 kHz PCM audio relay
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
Devices (radios/phones) connect as WebSocket **device** clients
|
| 61 |
+
(`{type:"auth", token, memberId}`); dispatch consoles connect as plain
|
| 62 |
+
authenticated clients and see everything. Binary WebSocket frames carry audio:
|
| 63 |
+
`[1 byte type=0x01][4 bytes groupId BE][4 bytes memberId BE][16 kHz mono Int16 LE PCM]`.
|
| 64 |
+
Only the current floor holder may transmit; the server enforces one speaker per
|
| 65 |
+
talkgroup and relays frames to everyone subscribed to that group.
|
| 66 |
+
|
| 67 |
+
## REST API (JWT Bearer)
|
| 68 |
+
|
| 69 |
+
| Method | Path | Purpose |
|
| 70 |
+
|---|---|---|
|
| 71 |
+
| POST | `/api/login` | get token |
|
| 72 |
+
| GET | `/api/me` | current user |
|
| 73 |
+
| GET/POST | `/api/groups` | talkgroups |
|
| 74 |
+
| GET/POST | `/api/members` | list / create members |
|
| 75 |
+
| PUT/DELETE | `/api/members/:id` | edit / delete |
|
| 76 |
+
| GET | `/api/members/:id/trail` | GPS history |
|
| 77 |
+
| GET | `/api/sos` | alert list (`?state=open`) |
|
| 78 |
+
| POST | `/api/sos/:id/ack` / `/api/sos/:id/resolve` | SOS workflow |
|
| 79 |
+
| GET | `/api/calls` | call log |
|
| 80 |
+
|
| 81 |
+
## Limitations (v1, honest)
|
| 82 |
+
|
| 83 |
+
- Audio is relayed 16 kHz PCM over WebSocket โ fine for small fleets; move to
|
| 84 |
+
Opus + a media server (LiveKit/Janus) for scale and better quality.
|
| 85 |
+
- Devices authenticate with any valid dispatcher token + memberId; per-device
|
| 86 |
+
credentials are the first thing to add before real deployment.
|
| 87 |
+
- Single-node, single SQLite file; no clustering.
|
| 88 |
+
- The fleet simulator needs a real browser (or device client) to produce audio;
|
| 89 |
+
it exercises GPS, SOS and floor events only.
|
| 90 |
+
|
| 91 |
+
## Files
|
| 92 |
+
|
| 93 |
+
- `server/src/realtime.js` โ WebSocket hub: auth, GPS, SOS, PTT floor, audio relay
|
| 94 |
+
- `server/src/routes.js` โ REST CRUD + SOS workflow
|
| 95 |
+
- `server/simulator.js` โ simulated fleet for testing
|
| 96 |
+
- `web/src/App.jsx` โ state + realtime wiring
|
| 97 |
+
- `web/src/audio.js` โ AudioWorklet capture / playback / SOS alarm
|