- Koa server on port 10000 with WebSocket live feed from 112-nu.nl RSS - PM2 watch mode for auto-restart on file changes - Dark navy UI with per-type color accents (fire/ambulance/police/rescue) - Slide-in filter panel with service type + 12 Dutch province filters - Card click opens detail modal: parsed priority (A1/A2/MGS), vehicle number, rit/bon number, alarm type, meldkamer, and eenheden - Server-side Nominatim geocoder (cached, rate-limited) powering an interactive Leaflet/OpenStreetMap map in the modal (CartoDB Voyager tiles) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2.5 KiB
2.5 KiB
P-2000 Monitor
Real-time Dutch emergency services (P-2000) channel monitor. Koa server + WebSocket + RSS polling, dark shadcn-style UI.
Stack
| Layer | Tech |
|---|---|
| Server | Node.js 20, Koa 2, koa-static, koa-router |
| WebSocket | ws library — attached to same HTTP server |
| P-2000 data | RSS polling via axios + xml2js (30s interval) |
| Process mgr | PM2 with watch mode (pm2.config.js) |
| Frontend | Vanilla JS, TailwindCSS Play CDN, shadcn-style design |
Port
10000 (override via PORT env var)
Running
# Install
npm install
# Dev (PM2 watch mode — auto-restart on src/ or server.js changes)
npm run dev
# Logs
npm run logs
# Stop
npm run stop
# Plain node (no PM2)
npm start
Project layout
server.js # Koa HTTP + WebSocket server, P-2000 event bridge
src/p2000.js # EventEmitter: RSS fetcher, XML parser, type detector
public/index.html # Single-page frontend (TailwindCSS + vanilla JS)
pm2.config.js # PM2 watch config
logs/ # PM2 out/error logs (git-ignored)
P-2000 Feed source
Primary: https://112-nu.nl/hulpdiensten/rss (all services combined, polled every 30s)
Per-service feeds also available but not used (combined is sufficient):
https://112-nu.nl/brandweer/rsshttps://112-nu.nl/ambulance/rsshttps://112-nu.nl/politie/rss
Change the feed URL via COMBINED_FEED constant in src/p2000.js.
Message types
Detected from <category> RSS tag first, then keyword fallback:
| Category code | Type |
|---|---|
| BRA, BRW | fire |
| AMB, MKA | ambulance |
| POL | police |
| KNRM, HELI | rescue |
Extend CATEGORY_MAP or KEYWORD_MAP in src/p2000.js to tune detection.
WebSocket protocol
Client connects to ws://localhost:10000/ws
Server → Client messages:
{ "type": "history", "messages": [ ...MessageObject ] }
{ "type": "message", "message": MessageObject }
MessageObject:
{
"id": "unique-guid",
"title": "P1 Melding Brand - Rotterdam",
"description": "Extended alert text",
"pubDate": "2024-01-15T12:34:56.000Z",
"link": "https://...",
"type": "fire",
"region": "Zuid-Holland"
}
Health check
GET /health → { status, uptime, messages }