Real-time situational awareness dashboard for Fredericksburg, VA metro area.
CRITICAL: The proxy server MUST be running for markers/waypoints to load!
npm installCreate a .env file in the repo root:
# Required
LOG_DIR=logs
# Optional (for UV index and air quality data)
OPENUV_API_KEY=your-openuv-key
WAQI_TOKEN=your-waqi-tokenOr copy the example: cp .env.example .env
npm run doctorThis verifies your environment is correctly configured.
npm run dev # Starts on port 8000
# or
npm start # Uses PORT from .env or default 8000bash scripts/termux-bootstrap.shThen clone the repo (if you haven't already) and install dependencies:
git clone <repo-url>
cd FXBG-PALANTIR-CITY-MANAGER-APP
npm installEnvironment placement:
- The bootstrap script creates
$HOME/.config/fxbg-palantir/.envfrom.env.exampleif it doesn't exist. - Edit that file to add any required API keys.
Start the app:
bash scripts/mobile.shOpen http://127.0.0.1:8000 on the phone. For LAN access from another device, use http://<phone-ip>:8000.
From anywhere inside the repo:
bash scripts/termux-run.shNeed a reminder for the full path?
bash scripts/termux-quickstart.shhttp://localhost:8000
The proxy server handles all external API requests (RSS feeds, 511 Virginia traffic, NWS weather, ArcGIS crash data) to bypass CORS restrictions.
# Health check
curl -s "http://localhost:8000/api/health" | head -c 800
# Crime reports status
curl -s "http://localhost:8000/api/fxbg/crime-reports/status"
# Refresh crime reports
curl -s "http://localhost:8000/api/fxbg/crime-reports/refresh?months=6" | head -c 1000
# Force refresh (bypass cache)
curl -s "http://localhost:8000/api/fxbg/crime-reports/refresh?months=6&force=1" | head -c 1000
# Upstreams health
curl -s "http://localhost:8000/api/health/upstreams"- β 511 Virginia incidents endpoint - Added fallback to Iteris CDN with JSONP parsing
- β Virginia crash data API - Improved error handling for 404/403 responses with helpful guidance
- β Better API error diagnostics - Added specific troubleshooting steps for different error types
- β Endpoint resilience - Multiple endpoint fallbacks for critical data sources
- β Improved logging - Clear debugging information for API endpoint issues
- β Improved RSS feed reliability - Enhanced error handling and better User-Agent headers
- β Fixed 511 Virginia incidents endpoint - Updated headers to avoid HTML responses
- β Better proxy server logging - Detailed logging for empty responses and errors
- β Enhanced User-Agent handling - Realistic browser headers to avoid blocking
- β Smarter Referer headers - Automatic Referer setting for specific endpoints
- β Increased timeouts - Extended from 12s to 15s for slow endpoints
- β Better error messages - Clear guidance when proxy server isn't running
- β Markers/Waypoints now load correctly - Fixed data ingestion and display
- β 511 API errors resolved - Improved error handling with better logging
- β Footer buttons show data - RSS feeds and API info now display properly
- β Better error messages - Console warnings are now more helpful
- β Fallback sample data - Demo markers appear when APIs are unavailable (for testing)
- 511 Virginia incidents returning HTML - Added fallback endpoint (Iteris CDN) with JSONP support
- Virginia crash data 404 errors - Removed problematic date filter, improved error messages
- API error diagnostics - Context-specific troubleshooting guidance for 404/403/network errors
- Endpoint resilience - Automatic failover between primary and fallback endpoints
- Dual-endpoint strategy for 511 Virginia - Try primary endpoint first, fall back to Iteris CDN
- JSONP parsing support - Handle both JSON and JSONP response formats
- Smarter Socrata queries - Removed date filters that cause 404s, use ID-based ordering
- Enhanced error messages - Specific guidance for 404 (endpoint changed), 403 (auth required)
The app pulls live data from:
- RSS Feeds: FXBG Police, Transit alerts, Local news
- 511 Virginia: Traffic cameras, incidents, construction
- NWS: Weather forecasts and alerts
- ArcGIS: Crash data from Virginia roads
- Interactive map with emoji markers for different event types
- Real-time traffic indicator for I-95
- Weather forecast display
- Filter by category (click footer legend items)
- Detailed panel view for each marker
- Auto-refresh every few minutes
View unified event stream from Reports, Crime, and System sources:
- Click Timeline button (β±οΈ) in header
- Filter by time range (1h to 30d) and event types
- Click events to center map on location
- Shows freshness: LIVE / CACHED / PENDING
Fast logging buttons at top of Timeline:
- + Report: Open full report form
β οΈ Hazard: Quick hazard marker (severity 3)- π Help: Request assistance (severity 4)
- β Check-in: Log location check-in
- π― Start / π End: Mission tracking
All actions work offline and sync when connected.
- Use the Field | Dispatch pill in the top bar to switch layouts.
- Mode is persisted per-device in localStorage key
fxbg.uiMode. - Field mode (mobile-first): timeline opens as a bottom sheet by default, quick actions are larger/always visible, and operational panels use full-width overlays.
- Dispatch mode (desktop ops): timeline is docked left by default, detail panel stays right-aligned, and timeline filters use a denser row.
- Starting a mission from Quick Actions pins an Active Mission header at the top.
- The header shows mission name, elapsed timer, and an End button.
- Active mission state persists in IndexedDB (
meta.activeMission) and localStorage (fxbg.activeMission) so timer survives reloads. - Ending a mission logs a
mission_endaction event (including duration and optional summary), then clears the pinned header.
App functions without internet:
- Timeline loads from local cache
- Quick Actions store to device
- Shows "OFFLINE" or "HUB UNREACHABLE" status
- Auto-syncs pending items when reconnected
Share timeline data between devices:
- Export Sync Pack: Download JSON with events+reports
- Import Sync Pack: Merge data from another device
- Useful for field teams without constant connectivity
T- Toggle Timeline panel- (See existing shortcuts with
?)
The app now supports runtime tile caching through the Service Worker (no Leaflet core changes):
- Cache tiles while browsing (default ON) via the Offline Map control on the map.
- Prefetch area downloads tiles around current map center.
- Radius options: 1km / 3km / 5km / 10km
- Zoom options: current zoom through +2 levels (capped at z18)
- Cache storage stats are shown in the control:
Tiles cached: NApprox MB: ...(rough estimate)
- Hard cap of ~2000 tile entries is enforced for runtime tile cache with LRU-like refresh behavior.
- Runtime tile caching targets supported dark basemaps used by this app:
- CARTO Dark (
basemaps.cartocdn.com) - Esri Dark Gray base/reference (fallback)
- CARTO Dark (
- If offline and a tile is not in cache, a clear in-app message appears: "Tiles not cached for this area" and a readable fallback tile is returned.
- OSM/debug basemap tiles are not part of offline caching strategy by default.
- Ensure proxy server is running:
node proxy-server.js - Check console for errors: Open browser DevTools (F12)
- Verify internet connection: The proxy needs network access to fetch live data
- Look for sample markers: If APIs fail, demo markers should still appear
- The proxy server needs a working internet connection
- Check console for "Unable to connect" messages
- Sample data will load if APIs are unreachable
- The proxy server isn't running or isn't accessible
- Make sure you're accessing
http://localhost:8000(notfile://)
index.html- Main HTML structureindex.js- Core application logicstyles.css- Styling (if present)proxy-server.js- CORS proxy server with caching
refreshAll()- Fetches all data sourcespollRSS()- Fetches RSS feeds with fallback datapollVa511()- Fetches 511 Virginia traffic datafetchNWS()- Fetches weather dataredraw()- Updates map markers
Edit CONFIG object in index.js to:
- Adjust polling intervals
- Add/remove data sources
- Change map center/zoom
- Modify region bounding box
The Report panel supports offline-ish field notes and incident logging. Reports persist on the server in data/reports.json and render as their own map layer after reload.
GET /api/reportsβ list reports{ ok, count, items }.- Optional filters:
since=ISO,sinceDays=number,bbox=minLng,minLat,maxLng,maxLat.
- Optional filters:
POST /api/reportsβ create a report (JSON or multipart form with optionalphoto).- Fields:
lat,lng,accuracy,type,severity(1β5),note(max 2000). - Photo limits: 5MB max, JPEG/PNG/WebP only.
- Fields:
GET /api/reports/export.csvβ export CSV.GET /api/reports/export.geojsonβ export GeoJSON FeatureCollection.GET /uploads/reports/<filename>β serve uploaded photos.
- Reports are stored locally on the server for resiliency if external feeds are down.
- Use the Report panel to submit incidents, pick a map location, and export data.
- For light operational checks against an already running server, run
npm run smoke(orBASE_URL=http://host:port npm run smoke, or./scripts/smoke.sh http://host:port). - For a one-command local validation, run
npm run smoke:localto start the proxy, run smoke checks, and shut it down automatically.
- Sample Data: When external APIs are unreachable (no internet, sandbox environment), the app loads demonstration markers so you can test the interface
- Caching: The proxy server caches responses to reduce API rate limits
- Performance: Max 650 total markers, keeping newest items
- Current Events Only: Filters show last 24 hours by default
- External APIs may be down or rate-limited occasionally
- Sandbox environments without internet will show sample data only
- Some RSS feeds may have inconsistent formatting
If markers still don't load after following this guide:
- Check browser console (F12) for errors
- Verify
node proxy-server.jsis running and shows no errors - Test proxy with:
curl http://localhost:8000/proxy?url=https://api.weather.gov - Look for the "sample markers" console message
Version: 14 Last Updated: 2026-01-02 Author: FXBG-PALANTIR Team
If your org/repo has a ruleset that rejects binary files in pull requests, remove binary assets from the diff before pushing.
git diff --name-only --cachedThis repo uses favicon.svg; avoid committing binary icon assets when PR rules reject binaries.
The app now ships with a Progressive Web App setup for installability and faster offline reloads.
- A web manifest is available at
/manifest.webmanifest. - Install metadata is provided by
manifest.webmanifestand existing SVG favicon assets (no binary icon files required). - Theme/background colors match the existing dark UI (
#0b1220). - On supported browsers/devices, you can use Add to Home Screen (or install from browser menu).
- Service worker file:
/sw.js. - Versioned caches use
CACHE_VERSIONso updates can safely rotate old caches. - App shell is pre-cached:
//index.html/index.js/styles.css/favicon.svg- manifest metadata
For local GET /api/* requests, the service worker serves cached data immediately (if present) while fetching fresh data in the background.
This improves reload speed and keeps timeline/report data available during intermittent connectivity.
Included endpoints:
/api/health/api/reports/api/reports/export.geojson/api/fxbg/crime-reports/incidents(including default query usage)- Other app timeline/report API sources fetched by
index.js
- API cache is capped to the latest 100 entries.
/proxy?url=...is not cached by the service worker, preventing unbounded proxy-response growth.
Header chip states show service worker lifecycle:
π¦ Cachedwhen activeβ¬οΈ Installingβ¦while installingβ¬οΈ Update availablewhen a new worker is waiting
When first install caching completes, a subtle Offline ready toast appears.
If an update is waiting, an Update button posts skipWaiting and reloads after activation.
The hub now serves two small local datasets used by the client geocoder when offline:
data/gazetteer.jsonviaGET /api/geo/gazetteerdata/intersections.jsonviaGET /api/geo/intersections
data/gazetteer.json:
{
"version": 1,
"items": [
{ "name": "Place Name", "aliases": ["Alias A"], "lat": 38.30, "lng": -77.46, "tags": ["category"] }
]
}data/intersections.json:
{
"version": 1,
"items": [
{ "a": "Caroline St", "b": "William St", "lat": 38.3026, "lng": -77.4582 }
]
}- Open the JSON file and add/update an item in
items. - Keep
versionas an integer (increment if you want to track major local changes). - Prefer including both canonical
nameand practicalaliases(for fuzzy alias matching). - Keep datasets intentionally small in this module (seed/high-value locations only).
- Restart the server after edits for immediate refresh, or wait up to 60s for server cache expiry.
The server auto-creates empty defaults if either file is missing, so startup remains safe.