feat(staging): runtime API-base injection via /env.js

Parameterize the previously hardcoded API_BASE so a staging build can point at
the staging API without forking the code:

  - env.js.template + /docker-entrypoint.d/30-fleetnow-env.sh render ${API_BASE}
    into /env.js on container start (envsubst ships with the nginx image)
  - index.html loads /env.js and uses window.FLEETNOW_API_BASE, falling back to
    the prod API (https://fleetapi.rahamafresh.com) when unset — so prod/main is
    unchanged; staging sets API_BASE=https://fleetapi.fivetitude.com
  - nginx: serve /env.js with no-store

Enables the fleetnow.fivetitude.com staging app (Coolify, staging branch).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
david kiania 2026-06-10 14:14:10 +03:00
parent a6d5a19273
commit 7138571c0e
5 changed files with 42 additions and 1 deletions

View file

@ -11,6 +11,13 @@ 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
# Runtime API-base injection: the entrypoint renders ${API_BASE} -> /env.js at
# container start (envsubst ships with the nginx image). Set API_BASE per env;
# unset falls back to the prod API, so prod/main is unaffected.
COPY env.js.template /usr/share/nginx/html/env.js.template
COPY docker-entrypoint.d/30-fleetnow-env.sh /docker-entrypoint.d/30-fleetnow-env.sh
RUN chmod +x /docker-entrypoint.d/30-fleetnow-env.sh
# Static map-overlay data (toggleable layers: gas stations, etc.), served at /layers/.
COPY layers/ /usr/share/nginx/html/layers/

View file

@ -0,0 +1,17 @@
#!/bin/sh
# Render the runtime API base into /env.js before nginx starts.
# The official nginx image runs every executable /docker-entrypoint.d/*.sh at
# startup, so this fires on each container boot — letting one image serve staging
# (API_BASE=https://fleetapi.fivetitude.com) and prod (…rahamafresh.com) from the
# same build. Only ${API_BASE} is substituted; index.html falls back to the prod
# API if it's empty.
set -e
: "${API_BASE:=}"
TEMPLATE=/usr/share/nginx/html/env.js.template
OUT=/usr/share/nginx/html/env.js
if [ -f "$TEMPLATE" ]; then
envsubst '${API_BASE}' < "$TEMPLATE" > "$OUT"
echo "fleetnow: rendered /env.js with API_BASE='${API_BASE}'"
fi

4
env.js.template Normal file
View file

@ -0,0 +1,4 @@
// Rendered at container start by /docker-entrypoint.d/30-fleetnow-env.sh
// (envsubst replaces ${API_BASE} with the API_BASE env var). If API_BASE is
// unset, this becomes an empty string and index.html falls back to the prod API.
window.FLEETNOW_API_BASE = "${API_BASE}";

View file

@ -380,6 +380,8 @@
<script src="https://unpkg.com/maplibre-gl@4.7.1/dist/maplibre-gl.js"></script>
<!-- Supercluster: Folium-style marker clustering while keeping our DOM pins. -->
<script src="https://unpkg.com/supercluster@8.0.1/dist/supercluster.min.js"></script>
<!-- Runtime config: nginx entrypoint renders ${API_BASE} into /env.js at start. -->
<script src="/env.js"></script>
</head>
<body>
@ -492,7 +494,12 @@
// ============================================================================
// CONFIG
// ============================================================================
const API_BASE = 'https://fleetapi.rahamafresh.com';
// API base is injected per-environment via /env.js (nginx renders ${API_BASE}
// at container start). Falls back to the prod API when unset, so a build with no
// API_BASE env (e.g. prod/main) is unchanged. Staging sets API_BASE=https://fleetapi.fivetitude.com.
const API_BASE = (window.FLEETNOW_API_BASE && /^https?:\/\//.test(window.FLEETNOW_API_BASE))
? window.FLEETNOW_API_BASE.replace(/\/$/, '')
: 'https://fleetapi.rahamafresh.com';
const EP_LIVE = `${API_BASE}/webhook/live-positions`;
const EP_TRACK = `${API_BASE}/webhook/live-positions/track`;
const EP_FLEET = `${API_BASE}/webhook/fleet-dashboard`;

View file

@ -25,6 +25,12 @@ server {
add_header Referrer-Policy "no-referrer-when-downgrade";
}
# Runtime config (per-environment API base) must never be cached.
location = /env.js {
add_header Cache-Control "no-store, no-cache, must-revalidate";
default_type application/javascript;
}
gzip on;
gzip_vary on;
gzip_min_length 1024;