feat: FleetNow merged live+trips map SPA (nginx/Coolify)
Single-file MapLibre SPA merging live vehicle positions and historical trips into one console. Reads the existing dashboard read-API (fleetapi.rahamafresh.com); served as a static nginx image for Coolify. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
commit
3d420fa82e
6 changed files with 1157 additions and 0 deletions
4
.dockerignore
Normal file
4
.dockerignore
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
.git
|
||||
.gitignore
|
||||
README.md
|
||||
*.md
|
||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
.DS_Store
|
||||
*.log
|
||||
node_modules/
|
||||
.env
|
||||
18
Dockerfile
Normal file
18
Dockerfile
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# FleetNow — static single-file SPA served by nginx.
|
||||
# Coolify auto-detects this Dockerfile; set the app's port to 80 and attach
|
||||
# the domain (fleetnow.rahamafresh.com) in the Coolify UI — Traefik + LE are
|
||||
# wired automatically from there.
|
||||
FROM nginx:1.27-alpine
|
||||
|
||||
# Drop the stock default site, add ours.
|
||||
RUN rm -f /etc/nginx/conf.d/default.conf
|
||||
COPY nginx.conf /etc/nginx/conf.d/fleetnow.conf
|
||||
|
||||
# The whole app is one self-contained file (inline CSS/JS; MapLibre from a CDN).
|
||||
COPY index.html /usr/share/nginx/html/index.html
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
# Coolify reads this; also handy for `docker ps` health.
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget -qO- http://localhost/healthz >/dev/null 2>&1 || exit 1
|
||||
65
README.md
Normal file
65
README.md
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# FleetNow
|
||||
|
||||
A single-file map console that **merges live vehicle positions and historical
|
||||
trips** into one view for the Fireside Communications / Tracksolid fleet.
|
||||
|
||||
- Land on the **live fleet** (cost-centre-coloured pins, heading arrows, hover
|
||||
popups with reverse-geocoded address).
|
||||
- Pick a vehicle (click its dot → **Show trips**, or the plate dropdown) or apply
|
||||
**cost centre + time period** → the map switches to **seq-coloured trip routes**
|
||||
with start/end markers and a click-to-animate replay.
|
||||
- The **● Live** pill returns to the live snapshot.
|
||||
|
||||
Live: <https://fleetnow.rahamafresh.com>
|
||||
|
||||
## Architecture
|
||||
|
||||
The whole app is **one self-contained `index.html`** (inline CSS + JS; MapLibre
|
||||
GL JS loaded from a CDN). It has no build step and no local assets. It reads from
|
||||
the existing dashboard read-API — it does **not** talk to the database directly.
|
||||
|
||||
```
|
||||
index.html → the entire SPA
|
||||
Dockerfile → bakes index.html into an nginx:alpine image (port 80)
|
||||
nginx.conf → static serve + /healthz + no-cache on index.html
|
||||
```
|
||||
|
||||
### Backend it depends on
|
||||
|
||||
`const API_BASE = 'https://fleetapi.rahamafresh.com';` (top of the `<script>` in
|
||||
`index.html`). That service (`dashboard_api_rev.py` in the `tracksolid` repo)
|
||||
exposes:
|
||||
|
||||
| Endpoint | Use |
|
||||
|---|---|
|
||||
| `GET /webhook/live-positions` | live snapshot `{summary, geojson}` |
|
||||
| `GET /webhook/live-positions/track?vehicle_number=&hours=` | 1 h trail |
|
||||
| `GET /webhook/fleet-dashboard` | filter options (plates, cost centres) |
|
||||
| `POST /webhook/fleet-dashboard` | trips for a selection `{summary, geojson}` |
|
||||
|
||||
**CORS:** the API must allow the `https://fleetnow.rahamafresh.com` origin
|
||||
(`DASHBOARD_CORS_ORIGINS`). It is in the code default; make sure the deployed
|
||||
`dashboard_api` container's env includes it, then restart that container.
|
||||
|
||||
## Deploy (Coolify, git-based)
|
||||
|
||||
1. In Coolify, create a new **Application** from this git repo
|
||||
(`https://repo.rahamafresh.com/kianiadee/fleetnow.git`), branch `main`,
|
||||
build pack **Dockerfile**.
|
||||
2. Set the **port** to `80`.
|
||||
3. Add the domain **`fleetnow.rahamafresh.com`** (HTTPS / Let's Encrypt). Coolify
|
||||
wires Traefik on the `coolify` network automatically.
|
||||
4. Point DNS `fleetnow.rahamafresh.com` → the VPS (`31.97.44.246`) if not already.
|
||||
5. Deploy. Every push to `main` redeploys; `index.html` is served `no-cache` so
|
||||
changes appear immediately.
|
||||
|
||||
## Local preview
|
||||
|
||||
```bash
|
||||
docker build -t fleetnow . && docker run --rm -p 8080:80 fleetnow
|
||||
# open http://localhost:8080
|
||||
```
|
||||
|
||||
> Loading from `localhost` will be CORS-blocked by the live API unless that
|
||||
> origin is allow-listed. For pure UI work, run a same-origin proxy that forwards
|
||||
> `/webhook/*` to `fleetapi.rahamafresh.com`.
|
||||
1034
index.html
Normal file
1034
index.html
Normal file
File diff suppressed because it is too large
Load diff
32
nginx.conf
Normal file
32
nginx.conf
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Lightweight health endpoint (Docker/Coolify probe + Traefik).
|
||||
location = /healthz {
|
||||
access_log off;
|
||||
add_header Content-Type text/plain;
|
||||
return 200 'ok';
|
||||
}
|
||||
|
||||
# Single-page app: always fall back to index.html.
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# index.html must never be cached, so a redeploy is picked up immediately.
|
||||
location = /index.html {
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade";
|
||||
}
|
||||
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
|
||||
}
|
||||
Loading…
Reference in a new issue